summaryrefslogtreecommitdiff
path: root/python-divinegift.spec
diff options
context:
space:
mode:
authorCoprDistGit <infra@openeuler.org>2023-04-11 21:48:35 +0000
committerCoprDistGit <infra@openeuler.org>2023-04-11 21:48:35 +0000
commitb73298cebe42e5ed6cf30404d3b873a0afdd3ff3 (patch)
treed59d6e6dbc8da3d30e17651205223c01f0ef3dcc /python-divinegift.spec
parent0657c321b24f94906b41f14571d7ac731bd5b410 (diff)
automatic import of python-divinegift
Diffstat (limited to 'python-divinegift.spec')
-rw-r--r--python-divinegift.spec1779
1 files changed, 1779 insertions, 0 deletions
diff --git a/python-divinegift.spec b/python-divinegift.spec
new file mode 100644
index 0000000..7b100b1
--- /dev/null
+++ b/python-divinegift.spec
@@ -0,0 +1,1779 @@
+%global _empty_manifest_terminate_build 0
+Name: python-divinegift
+Version: 2.15.16
+Release: 1
+Summary: Ver.2.15.16. Kafka clients fixed.
+License: MIT
+URL: https://gitlab.com/gng-group/divinegift.git
+Source0: https://mirrors.nju.edu.cn/pypi/web/packages/91/8e/ce77d95b224d93a00e45122a8754fa8ab03b76abc8aa83e0c50419fcaa5e/divinegift-2.15.16.tar.gz
+BuildArch: noarch
+
+Requires: python3-requests
+Requires: python3-deprecation
+Requires: python3-cryptography
+Requires: python3-pyyaml
+Requires: python3-dateutil
+Requires: python3-schedule
+
+%description
+**The most useful package for you, young python programmer :)**
+
+# How to use it
+
+## Install this packages before use
+
+* sqlalchemy - For works with databases
+* cx_Oracle - Oracle driver
+* sqlalchemy-pytds - MSSQL driver
+* psycopg2-binary - Postgres driver
+* xlutils - For Excel
+* xlsxwriter - for Excel
+* openpyxl - For Excel
+* transliterate - For Transliteration
+* confluent-kafka[avro] - For work with kafka
+
+## logging
+
+```
+# Import necessary functions
+from divinegift.logger import log_info, log_err, log_warning, set_loglevel
+
+# info msg
+log_info('Your message')
+
+# error msg
+log_err('Error msg',
+ src='Error source', # e.g. str(sys.argv[0])
+ mode=['telegram', 'email'] # May be empty
+ channel={
+ "telegram": -1001343660695,
+ "email": {"TO": ["your@domain.ru"], "FROM": "from@domain.com",
+ "HOST": "smtp.domain.com", "usr": "from@domain.com", "pwd": "supersecretpassword"}
+ }) # You can add "CC" to "email" for add copy_to addresses
+
+# error msg with out sending problem to external system
+log_err('Error msg', src='Error src')
+```
+
+## Pass log_level and log_name through cmd arguments
+
+To specify log_level and log_name in your app you can send it through arguments:
+```
+if __name__ == '__main__':
+ # Get all args from cmd:
+ args = get_args()
+ # Get log_level, log_name, log_dir
+ lp = get_log_param(args)
+ # Set log_level and log_name:
+ set_loglevel(lp.get('log_level'), lp.get('log_name'), lp.get('log_dir'))
+```
+You should pass your args by pairs: key value, e.g. --log_level INFO
+Available variants for logging are:
+* --log_level or shortcut is -ll
+* --log_name or shortcut is -ln
+* --log_dir or shortcut is -ld
+
+log_level could be DEBUG, INFO, WARNING, ERROR
+
+Example of starting app with arguments:
+```
+python test.py -ll INFO -ln test.log
+```
+
+## Config parsing
+
+To parsing configs you can use class *divinegift.config.Settings* .
+By default, it's use yaml as config language. But you can use json-style too.
+
+### YAML-config
+```
+from divinegift.config import Settings # Necessary imports
+
+settings = {}
+
+# You should use divinegift.logger.set_loglevel before config parsing
+s = Settings()
+s.parse_settings('./settings.ini')
+settings = s.get_settings()
+```
+
+#### Config example
+```
+monitoring:
+- telegram
+- email
+- slack
+monitoring_channel:
+ email_to:
+ - aims.control@s7.ru
+ telegram: -1001343660695
+```
+
+### JSON-config
+
+```
+from divinegift.config import Settings # Necessary imports
+
+settings = {}
+
+# You should use divinegift.logger.set_loglevel before config parsing
+s = Settings()
+s.parse_settings('./settings.ini', use_yaml=False)
+settings = s.get_settings()
+```
+
+#### Config example
+
+```
+{
+ "log_level": "INFO",
+ "log_name": "YourAwesomeProject.log",
+ "monitoring": [
+ "telegram",
+ "email"
+ ],
+ "monitoring_channel": {
+ "telegram": -1001343660695,
+ "email_to": [
+ "aims.control@s7.ru"
+ ]
+ }
+ }
+```
+
+## Working with DB (sqlalchemy)
+
+You should define dict with db_conn creditional.
+For example:
+
+### Oracle
+Install oracle driver:
+```
+pip install cx_oracle
+```
+```
+db_conn = {
+ "db_user": "dbuser", # username
+ "db_pass": "dbpass", # password
+ "db_host": "dbhost", # host (ip, fqdn). could be empty if we connect via tns
+ "db_port": "", # port (string). could be empty if we connect via tns
+ "db_name": "dbname", # database name
+ "db_schm": "", # db scheme if not equal username
+ "dialect": "oracle" # if use cx_Oracle or oracle+another_dialect
+}
+```
+### MSSQL
+Install mssql driver:
+```
+pip install sqlalchemy-pytds
+```
+```
+db_conn = {
+ "db_user": "dbuser", # username
+ "db_pass": "dbpass", # password
+ "db_host": "", # host (ip, fqdn). could be empty if we connect via tns
+ "db_port": "", # port (string). could be empty if we connect via tns
+ "db_name": "dbname", # database name
+ "db_schm": "", # db scheme if not equal username
+ "dialect": "mssql+pytds" # mssql dialect
+}
+```
+### Postgres
+Install postgres driver:
+```
+pip install psycopg2
+```
+```
+db_conn = {
+ "db_user": "dbuser", # username
+ "db_pass": "dbpass", # password
+ "db_host": "", # host (ip, fqdn). could be empty if we connect via tns
+ "db_port": "", # port (string). could be empty if we connect via tns
+ "db_name": "dbname", # database name
+ "db_schm": "", # db scheme if not equal username
+ "dialect": "postgresql+psycopg2" # dialect
+}
+```
+
+### Create connection
+
+Use class DBClient to create connection to DB. Old-styled functions, which contained in *divinegift.db* module directly, are deprecated but still works.
+```
+from divinegift.db import DBClient
+connection = DBClient(db_conn) # db_conn - variable which was described above
+# Describe which fields you wants to method get_conn will returned (possible fields are 'engine', 'conn' and 'metadata')
+engine, conn, metadata = connection.get_conn(fields=['engine', 'conn', 'metadata'])
+```
+
+If you need to call stored procedure with db cursors you should use raw connection.
+```
+from divinegift.db import DBClient
+connection = DBClient(db_conn, do_initialize=False) # db_conn - variable which was described above
+connection.set_raw_conn()
+conn = connection.get_conn(fields='conn')
+```
+
+### Get data from sript (file or just string)
+
+After you got "connection" variable you can get data from file or from str variable directly.
+
+```
+from divinegift.db import DBClient
+connection = DBClient(db_conn)
+
+result = connection.get_data('path/to/scripts/some_script.sql')
+# or you can use str variable:
+script = 'select * from dual'
+result = connection.get_data(script)
+print(result)
+>>>[{'dummy': 'X'}]
+```
+
+You can use specific encoding for your files (by default it's 'cp1251').
+Just put it into args:
+```
+result = connection.get_data('path/to/scripts/some_script.sql', encoding='utf8')
+```
+
+Also you can add some variables into your script (e.g. date) and then you can pass it into a function:
+```
+from divinegift.db import DBClient
+connection = DBClient(db_conn)
+
+script = """select * from dual
+where dummy = '$param'"""
+parameters = {'param': 'X'}
+result = connection.get_data(script, **parameters)
+# Or another variant
+result = connection.get_data(script, param='X')
+print(result)
+>>>[{'dummy': 'X'}]
+```
+
+### Run script without getting data
+
+You can run script without recieving data.
+You should use *divinegift.db.DBClient.run_script* for this like get_data, e.g.:
+```
+from divinegift.db import Connection
+connection = Connection(db_conn)
+connection.run_script('path/to/scripts/some_script.sql')
+```
+
+## Sending email
+
+You can use function send_mail from class *divinegift.sender.Sender*
+
+You should set your msg, subject and list of recipients, and account which should be used for sending email
+Simple example:
+```
+from divinegift.sender import Sender
+
+sender = Sender()
+sender.send_mail('Test message', 'Test subject', TO=['your@domain.com'],
+ FROM="from@domain.com", HOST="smtp.domain.com", usr="from", pwd="pwd")
+```
+
+You can specify TO, CC, BCC, HOST, FROM and attachments. Also you can send it like html-message or like text.
+
+You should pass list of attachments files with absolute path to it. You can use function *divinegift.main.get_list_files* for get it.
+For sending email with attachment(s):
+```
+from divinegift.main import get_list_files
+from divinegift.sender import Sender
+
+sender = Sender()
+attachment_list = get_list_files('/path/to/files', add_path=True)
+sender.send_mail('Hello! This are files in attach', 'Test sending attachments', ['your@domain.com'],
+ FROM="from@domain.com", HOST="smtp.domain.com", usr="from", pwd="pwd",
+ attachments=attachment_list)
+# Also you can send only one file:
+attachment = '/path/to/file/file_name'
+sender.send_mail('Hello! There is file in attach', 'File', ['your@domain.com'],
+ FROM="from@domain.com", HOST="smtp.domain.com", usr="from", pwd="pwd",
+ attachments=attachment)
+```
+
+If you set IS_HTML to False (by default it is True), you could send an email like simple text message, not html
+
+## Work with JSON
+
+You can simple parse and create JSONs
+
+To create json you could use *divinegift.main.create_json*
+To parse it you could use *divinegift.main.parse_json*
+Or you could use class *divinegift.main.Json* instead of it
+
+For example:
+```
+from divinegift.main import create_json, parse_json
+A = {'key1': 'data1', 'key2': 'data2'}
+create_json(A, 'json_file_name.json')
+B = parse_json('json_file_name.json')
+
+print(B)
+>>> {'key1': 'data1', 'key2': 'data2'}
+
+from divinegift.main import Json
+A = {'key1': 'data1', 'key2': 'data2'}
+json_obj = Json('json_file_class.json')
+json_obj.set_data(A)
+json_obj.create()
+B = json_obj.parse()
+```
+
+## Work with YAML
+
+You can simple parse and create YAMLs
+
+To create json you could use *divinegift.main.create_yaml*
+To parse it you could use *divinegift.main.parse_yaml*
+Or you could use class *divinegift.main.Yaml* instead of it
+
+For example:
+```
+from divinegift.main import create_yaml, parse_yaml
+A = {'key1': 'data1', 'key2': 'data2'}
+create_yaml(A, 'yaml_file_name.yml')
+B = parse_yaml('yaml_file_name.yml')
+
+print(B)
+>>> {'key1': 'data1', 'key2': 'data2'}
+
+from divinegift.main import Yaml
+A = {'key1': 'data1', 'key2': 'data2'}
+yml_obj = Yaml('yml_file_class.yml')
+yml_obj.set_data(A)
+yml_obj.create()
+B = yml_obj.parse()
+```
+
+## Transliterate strings between Russian and English and back
+
+From version 1.0.8 you can use transliterate library to transliterate strings between languages
+
+Example:
+```
+from divinegift.translit import translit
+
+name = 'SHEVCHENKO ANDREY'
+name_r = translit(name, 'ru_ext')
+name_e = translit(name_r, 'ru_ext', reversed=True)
+name_r_cap = translit(name, 'ru_ext').capitalize()
+name_r_low = translit(name, 'ru_ext').lower()
+
+print(f'From English to Russian: {name}\t->\t{name_r}')
+print(f'From Russian to English: {name_r}\t->\t{name_e}')
+print(f'Capitalize : {name}\t->\t{name_r_cap}')
+print(f'Lower : {name}\t->\t{name_r_low}')
+```
+
+Code from above will show next:
+```
+From English to Russian: SHEVCHENKO ANDREY -> ШЕВЧЕНКО АНДРЕЙ
+From Russian to English: ШЕВЧЕНКО АНДРЕЙ -> SHEVCHENKO ANDREI
+Capitalize : SHEVCHENKO ANDREY -> Шевченко андрей
+Lower : SHEVCHENKO ANDREY -> шевченко андрей
+```
+
+## Encryption
+From version 1.0.10 you can use encryption module
+
+### Simple example
+Example:
+```
+from divinegift.cipher import get_key, get_cipher, encrypt_str, decrypt_str
+
+cipher_key = get_key()
+cipher = get_cipher(cipher_key)
+text = 'qwerty1234!!'
+text_enc = encrypt_str(text, cipher)
+print(text_enc)
+text_dec = decrypt_str(text_enc, cipher)
+print(text_dec)
+```
+
+Code above will output next:
+```
+gAAAAABcanXfhUr9i__R_24rPyrHzZoMgQSTYiBmx9ZtVqdcMiGZPOxoSz4gkAW0Y9TDWpAJ6jzAjPo-mrK_IcJcdByyfWrbhQ==
+qwerty1234!!
+```
+
+If you use parameter get_str=False in functions encrypt_str and decrypt_str than this functions will returns binary string
+
+### Works with key in file
+
+Save your key in file by *write_key* function:
+```
+from divinegift.cipher import get_key, write_key
+
+cipher_key = get_key()
+write_key('key.ck', cipher_key)
+```
+
+Read your key file by *read_key* function:
+```
+from divinegift.cipher import read_key
+
+cipher_key = read_key('key.ck')
+```
+
+### Caesar
+
+You can use caesar encrypt/decrypt:
+```
+from divinegift.cipher import caesar_code
+
+text = caesar_code('Hello, World!', shift=5)
+print(text)
+```
+It will output next:
+```
+Mjqqt, 1twqi!
+```
+
+### Easy encription/decryption database-passwords for more security
+
+Before all you should encrypt your file with settings.
+Use next code to do this once:
+```
+from divinegift.config import Settings
+
+s = Settings()
+s.parse_settings('settings.conf')
+s.initialize_cipher()
+s.encrypt_password('db_conn') # db_conn - name of db connection in settings.conf which contains "db_pass"
+s.save_settings('settings.conf')
+```
+
+After that your password in section 'db_conn' will automaticaly encrypted.
+If you have more db-connections just add s.encrypt_password('db_conn_name_you_have') before saving function
+
+Next you must use decryption function in your code to use connection:
+```
+from divinegift.config import Settings
+
+s = Settings()
+s.parse_settings('settings.conf')
+s.decrypt_password('db_conn') # db_conn - name of db connection in settings.conf which contains "db_pass"
+```
+
+
+## Live templates. Start create your app as easy as possible
+
+From version 1.0.11 you can create files from templates.
+You should use module *templator* for this.
+
+Example:
+Create tmp.py with following text and run it:
+```
+from divinegift.templator import Templator
+
+t = Templator()
+# create console app, or main logic (you can omit the file extension, '.py' will add automaticaly.):
+t.create_console('your_awesome_name.py')
+# or
+t.create_console() # it will create 'main.py' file
+
+# create QT-app:
+t.create_gui(your_awesome_name.py')
+# or
+t.create_gui() # it will create 'main_gui.py' file
+
+# create config file:
+t.create_config('your_config_name.ini')
+# or
+t.create_config() # it will create 'settings.ini' file
+
+# After creating file with config you can add email section on it:
+t.add_email_config('your_config_name.ini')
+# or
+t.add_email_config() # it will add email section to 'settings.ini'
+```
+
+## Kafka Client
+
+From version 1.3.0 you can use kafka client to read and write data from/to topics
+
+
+Example:
+```
+from divinegift.kafka_client import KafkaClient
+
+kafka_client = KafkaClient()
+
+# Reader
+kafka_client.set_consumer(**s.settings.get('consumer_config'))
+
+messages = kafka_client.read_messages(topic_name)
+# You can read all messages from begin if you needed:
+messages = kafka_client.read_messages(topic_name, from_beginning=True)
+
+# Writer
+kafka_client.set_consumer(**s.settings.get('producer_config'))
+
+kafka_client.send_message(topic_name, msg)
+```
+
+Config example from example above:
+```
+kafka_config: &kafka_config
+ bootstrap_servers:
+ - server.domain:9093
+ security_protocol: SSL
+ ssl_check_hostname: False
+ ssl_cafile: CARoot.pem
+ ssl_certfile: certificate.pem
+ ssl_keyfile: key.pem
+producer_config:
+ <<: *kafka_config
+consumer_config:
+ <<: *kafka_config
+ consumer_timeout_ms: 1000
+```
+
+## Working with Excel
+
+### Reading file
+
+For reading excel-file you should use function *divinegift.excel.read_excel*
+
+You should pass filename, array with column names
+
+Optional fields are:
+ sheet_name, int_columns, date_columns, start_row
+
+```
+from divinegift import excel
+
+filename = 'your/path/to/excel.xlsx' # or it could be xls
+excel_header = ['column1', 'column2', ]
+excel_data = excel.read_excel(filename, excel_header)
+```
+
+By default, all cells are read as strings, but if you need read int columns/date columns, you could pass their names
+in parameters int_columns/date_columns. You should name it like you pass it at excel_header
+
+```
+from divinegift import excel
+
+filename = 'your/path/to/excel.xlsx' # or it could be xls
+excel_header = ['column1', 'column2', 'int_col', 'date_col']
+excel_data = excel.read_excel(filename, excel_header, int_columns=['int_col'], date_col=['date_col'])
+```
+
+### Writing file
+
+For writing excel-file you should use function *divinegift.excel.create_excel*
+
+You should pass filename and list with data
+
+Optional fields are:
+ sheet_name, header
+
+When you set excel_header, you could set column width
+
+```
+from divinegift import excel
+
+filename = 'path/to/excel/your.xlsx'
+data = [{'col1': 1, 'col2': 2,},] # or it could be just list of list
+
+excel_header = {'col1': 10, 'col2', 13, }
+excel.create_excel(data, filename, excel_header=excel_header)
+```
+
+
+
+%package -n python3-divinegift
+Summary: Ver.2.15.16. Kafka clients fixed.
+Provides: python-divinegift
+BuildRequires: python3-devel
+BuildRequires: python3-setuptools
+BuildRequires: python3-pip
+%description -n python3-divinegift
+**The most useful package for you, young python programmer :)**
+
+# How to use it
+
+## Install this packages before use
+
+* sqlalchemy - For works with databases
+* cx_Oracle - Oracle driver
+* sqlalchemy-pytds - MSSQL driver
+* psycopg2-binary - Postgres driver
+* xlutils - For Excel
+* xlsxwriter - for Excel
+* openpyxl - For Excel
+* transliterate - For Transliteration
+* confluent-kafka[avro] - For work with kafka
+
+## logging
+
+```
+# Import necessary functions
+from divinegift.logger import log_info, log_err, log_warning, set_loglevel
+
+# info msg
+log_info('Your message')
+
+# error msg
+log_err('Error msg',
+ src='Error source', # e.g. str(sys.argv[0])
+ mode=['telegram', 'email'] # May be empty
+ channel={
+ "telegram": -1001343660695,
+ "email": {"TO": ["your@domain.ru"], "FROM": "from@domain.com",
+ "HOST": "smtp.domain.com", "usr": "from@domain.com", "pwd": "supersecretpassword"}
+ }) # You can add "CC" to "email" for add copy_to addresses
+
+# error msg with out sending problem to external system
+log_err('Error msg', src='Error src')
+```
+
+## Pass log_level and log_name through cmd arguments
+
+To specify log_level and log_name in your app you can send it through arguments:
+```
+if __name__ == '__main__':
+ # Get all args from cmd:
+ args = get_args()
+ # Get log_level, log_name, log_dir
+ lp = get_log_param(args)
+ # Set log_level and log_name:
+ set_loglevel(lp.get('log_level'), lp.get('log_name'), lp.get('log_dir'))
+```
+You should pass your args by pairs: key value, e.g. --log_level INFO
+Available variants for logging are:
+* --log_level or shortcut is -ll
+* --log_name or shortcut is -ln
+* --log_dir or shortcut is -ld
+
+log_level could be DEBUG, INFO, WARNING, ERROR
+
+Example of starting app with arguments:
+```
+python test.py -ll INFO -ln test.log
+```
+
+## Config parsing
+
+To parsing configs you can use class *divinegift.config.Settings* .
+By default, it's use yaml as config language. But you can use json-style too.
+
+### YAML-config
+```
+from divinegift.config import Settings # Necessary imports
+
+settings = {}
+
+# You should use divinegift.logger.set_loglevel before config parsing
+s = Settings()
+s.parse_settings('./settings.ini')
+settings = s.get_settings()
+```
+
+#### Config example
+```
+monitoring:
+- telegram
+- email
+- slack
+monitoring_channel:
+ email_to:
+ - aims.control@s7.ru
+ telegram: -1001343660695
+```
+
+### JSON-config
+
+```
+from divinegift.config import Settings # Necessary imports
+
+settings = {}
+
+# You should use divinegift.logger.set_loglevel before config parsing
+s = Settings()
+s.parse_settings('./settings.ini', use_yaml=False)
+settings = s.get_settings()
+```
+
+#### Config example
+
+```
+{
+ "log_level": "INFO",
+ "log_name": "YourAwesomeProject.log",
+ "monitoring": [
+ "telegram",
+ "email"
+ ],
+ "monitoring_channel": {
+ "telegram": -1001343660695,
+ "email_to": [
+ "aims.control@s7.ru"
+ ]
+ }
+ }
+```
+
+## Working with DB (sqlalchemy)
+
+You should define dict with db_conn creditional.
+For example:
+
+### Oracle
+Install oracle driver:
+```
+pip install cx_oracle
+```
+```
+db_conn = {
+ "db_user": "dbuser", # username
+ "db_pass": "dbpass", # password
+ "db_host": "dbhost", # host (ip, fqdn). could be empty if we connect via tns
+ "db_port": "", # port (string). could be empty if we connect via tns
+ "db_name": "dbname", # database name
+ "db_schm": "", # db scheme if not equal username
+ "dialect": "oracle" # if use cx_Oracle or oracle+another_dialect
+}
+```
+### MSSQL
+Install mssql driver:
+```
+pip install sqlalchemy-pytds
+```
+```
+db_conn = {
+ "db_user": "dbuser", # username
+ "db_pass": "dbpass", # password
+ "db_host": "", # host (ip, fqdn). could be empty if we connect via tns
+ "db_port": "", # port (string). could be empty if we connect via tns
+ "db_name": "dbname", # database name
+ "db_schm": "", # db scheme if not equal username
+ "dialect": "mssql+pytds" # mssql dialect
+}
+```
+### Postgres
+Install postgres driver:
+```
+pip install psycopg2
+```
+```
+db_conn = {
+ "db_user": "dbuser", # username
+ "db_pass": "dbpass", # password
+ "db_host": "", # host (ip, fqdn). could be empty if we connect via tns
+ "db_port": "", # port (string). could be empty if we connect via tns
+ "db_name": "dbname", # database name
+ "db_schm": "", # db scheme if not equal username
+ "dialect": "postgresql+psycopg2" # dialect
+}
+```
+
+### Create connection
+
+Use class DBClient to create connection to DB. Old-styled functions, which contained in *divinegift.db* module directly, are deprecated but still works.
+```
+from divinegift.db import DBClient
+connection = DBClient(db_conn) # db_conn - variable which was described above
+# Describe which fields you wants to method get_conn will returned (possible fields are 'engine', 'conn' and 'metadata')
+engine, conn, metadata = connection.get_conn(fields=['engine', 'conn', 'metadata'])
+```
+
+If you need to call stored procedure with db cursors you should use raw connection.
+```
+from divinegift.db import DBClient
+connection = DBClient(db_conn, do_initialize=False) # db_conn - variable which was described above
+connection.set_raw_conn()
+conn = connection.get_conn(fields='conn')
+```
+
+### Get data from sript (file or just string)
+
+After you got "connection" variable you can get data from file or from str variable directly.
+
+```
+from divinegift.db import DBClient
+connection = DBClient(db_conn)
+
+result = connection.get_data('path/to/scripts/some_script.sql')
+# or you can use str variable:
+script = 'select * from dual'
+result = connection.get_data(script)
+print(result)
+>>>[{'dummy': 'X'}]
+```
+
+You can use specific encoding for your files (by default it's 'cp1251').
+Just put it into args:
+```
+result = connection.get_data('path/to/scripts/some_script.sql', encoding='utf8')
+```
+
+Also you can add some variables into your script (e.g. date) and then you can pass it into a function:
+```
+from divinegift.db import DBClient
+connection = DBClient(db_conn)
+
+script = """select * from dual
+where dummy = '$param'"""
+parameters = {'param': 'X'}
+result = connection.get_data(script, **parameters)
+# Or another variant
+result = connection.get_data(script, param='X')
+print(result)
+>>>[{'dummy': 'X'}]
+```
+
+### Run script without getting data
+
+You can run script without recieving data.
+You should use *divinegift.db.DBClient.run_script* for this like get_data, e.g.:
+```
+from divinegift.db import Connection
+connection = Connection(db_conn)
+connection.run_script('path/to/scripts/some_script.sql')
+```
+
+## Sending email
+
+You can use function send_mail from class *divinegift.sender.Sender*
+
+You should set your msg, subject and list of recipients, and account which should be used for sending email
+Simple example:
+```
+from divinegift.sender import Sender
+
+sender = Sender()
+sender.send_mail('Test message', 'Test subject', TO=['your@domain.com'],
+ FROM="from@domain.com", HOST="smtp.domain.com", usr="from", pwd="pwd")
+```
+
+You can specify TO, CC, BCC, HOST, FROM and attachments. Also you can send it like html-message or like text.
+
+You should pass list of attachments files with absolute path to it. You can use function *divinegift.main.get_list_files* for get it.
+For sending email with attachment(s):
+```
+from divinegift.main import get_list_files
+from divinegift.sender import Sender
+
+sender = Sender()
+attachment_list = get_list_files('/path/to/files', add_path=True)
+sender.send_mail('Hello! This are files in attach', 'Test sending attachments', ['your@domain.com'],
+ FROM="from@domain.com", HOST="smtp.domain.com", usr="from", pwd="pwd",
+ attachments=attachment_list)
+# Also you can send only one file:
+attachment = '/path/to/file/file_name'
+sender.send_mail('Hello! There is file in attach', 'File', ['your@domain.com'],
+ FROM="from@domain.com", HOST="smtp.domain.com", usr="from", pwd="pwd",
+ attachments=attachment)
+```
+
+If you set IS_HTML to False (by default it is True), you could send an email like simple text message, not html
+
+## Work with JSON
+
+You can simple parse and create JSONs
+
+To create json you could use *divinegift.main.create_json*
+To parse it you could use *divinegift.main.parse_json*
+Or you could use class *divinegift.main.Json* instead of it
+
+For example:
+```
+from divinegift.main import create_json, parse_json
+A = {'key1': 'data1', 'key2': 'data2'}
+create_json(A, 'json_file_name.json')
+B = parse_json('json_file_name.json')
+
+print(B)
+>>> {'key1': 'data1', 'key2': 'data2'}
+
+from divinegift.main import Json
+A = {'key1': 'data1', 'key2': 'data2'}
+json_obj = Json('json_file_class.json')
+json_obj.set_data(A)
+json_obj.create()
+B = json_obj.parse()
+```
+
+## Work with YAML
+
+You can simple parse and create YAMLs
+
+To create json you could use *divinegift.main.create_yaml*
+To parse it you could use *divinegift.main.parse_yaml*
+Or you could use class *divinegift.main.Yaml* instead of it
+
+For example:
+```
+from divinegift.main import create_yaml, parse_yaml
+A = {'key1': 'data1', 'key2': 'data2'}
+create_yaml(A, 'yaml_file_name.yml')
+B = parse_yaml('yaml_file_name.yml')
+
+print(B)
+>>> {'key1': 'data1', 'key2': 'data2'}
+
+from divinegift.main import Yaml
+A = {'key1': 'data1', 'key2': 'data2'}
+yml_obj = Yaml('yml_file_class.yml')
+yml_obj.set_data(A)
+yml_obj.create()
+B = yml_obj.parse()
+```
+
+## Transliterate strings between Russian and English and back
+
+From version 1.0.8 you can use transliterate library to transliterate strings between languages
+
+Example:
+```
+from divinegift.translit import translit
+
+name = 'SHEVCHENKO ANDREY'
+name_r = translit(name, 'ru_ext')
+name_e = translit(name_r, 'ru_ext', reversed=True)
+name_r_cap = translit(name, 'ru_ext').capitalize()
+name_r_low = translit(name, 'ru_ext').lower()
+
+print(f'From English to Russian: {name}\t->\t{name_r}')
+print(f'From Russian to English: {name_r}\t->\t{name_e}')
+print(f'Capitalize : {name}\t->\t{name_r_cap}')
+print(f'Lower : {name}\t->\t{name_r_low}')
+```
+
+Code from above will show next:
+```
+From English to Russian: SHEVCHENKO ANDREY -> ШЕВЧЕНКО АНДРЕЙ
+From Russian to English: ШЕВЧЕНКО АНДРЕЙ -> SHEVCHENKO ANDREI
+Capitalize : SHEVCHENKO ANDREY -> Шевченко андрей
+Lower : SHEVCHENKO ANDREY -> шевченко андрей
+```
+
+## Encryption
+From version 1.0.10 you can use encryption module
+
+### Simple example
+Example:
+```
+from divinegift.cipher import get_key, get_cipher, encrypt_str, decrypt_str
+
+cipher_key = get_key()
+cipher = get_cipher(cipher_key)
+text = 'qwerty1234!!'
+text_enc = encrypt_str(text, cipher)
+print(text_enc)
+text_dec = decrypt_str(text_enc, cipher)
+print(text_dec)
+```
+
+Code above will output next:
+```
+gAAAAABcanXfhUr9i__R_24rPyrHzZoMgQSTYiBmx9ZtVqdcMiGZPOxoSz4gkAW0Y9TDWpAJ6jzAjPo-mrK_IcJcdByyfWrbhQ==
+qwerty1234!!
+```
+
+If you use parameter get_str=False in functions encrypt_str and decrypt_str than this functions will returns binary string
+
+### Works with key in file
+
+Save your key in file by *write_key* function:
+```
+from divinegift.cipher import get_key, write_key
+
+cipher_key = get_key()
+write_key('key.ck', cipher_key)
+```
+
+Read your key file by *read_key* function:
+```
+from divinegift.cipher import read_key
+
+cipher_key = read_key('key.ck')
+```
+
+### Caesar
+
+You can use caesar encrypt/decrypt:
+```
+from divinegift.cipher import caesar_code
+
+text = caesar_code('Hello, World!', shift=5)
+print(text)
+```
+It will output next:
+```
+Mjqqt, 1twqi!
+```
+
+### Easy encription/decryption database-passwords for more security
+
+Before all you should encrypt your file with settings.
+Use next code to do this once:
+```
+from divinegift.config import Settings
+
+s = Settings()
+s.parse_settings('settings.conf')
+s.initialize_cipher()
+s.encrypt_password('db_conn') # db_conn - name of db connection in settings.conf which contains "db_pass"
+s.save_settings('settings.conf')
+```
+
+After that your password in section 'db_conn' will automaticaly encrypted.
+If you have more db-connections just add s.encrypt_password('db_conn_name_you_have') before saving function
+
+Next you must use decryption function in your code to use connection:
+```
+from divinegift.config import Settings
+
+s = Settings()
+s.parse_settings('settings.conf')
+s.decrypt_password('db_conn') # db_conn - name of db connection in settings.conf which contains "db_pass"
+```
+
+
+## Live templates. Start create your app as easy as possible
+
+From version 1.0.11 you can create files from templates.
+You should use module *templator* for this.
+
+Example:
+Create tmp.py with following text and run it:
+```
+from divinegift.templator import Templator
+
+t = Templator()
+# create console app, or main logic (you can omit the file extension, '.py' will add automaticaly.):
+t.create_console('your_awesome_name.py')
+# or
+t.create_console() # it will create 'main.py' file
+
+# create QT-app:
+t.create_gui(your_awesome_name.py')
+# or
+t.create_gui() # it will create 'main_gui.py' file
+
+# create config file:
+t.create_config('your_config_name.ini')
+# or
+t.create_config() # it will create 'settings.ini' file
+
+# After creating file with config you can add email section on it:
+t.add_email_config('your_config_name.ini')
+# or
+t.add_email_config() # it will add email section to 'settings.ini'
+```
+
+## Kafka Client
+
+From version 1.3.0 you can use kafka client to read and write data from/to topics
+
+
+Example:
+```
+from divinegift.kafka_client import KafkaClient
+
+kafka_client = KafkaClient()
+
+# Reader
+kafka_client.set_consumer(**s.settings.get('consumer_config'))
+
+messages = kafka_client.read_messages(topic_name)
+# You can read all messages from begin if you needed:
+messages = kafka_client.read_messages(topic_name, from_beginning=True)
+
+# Writer
+kafka_client.set_consumer(**s.settings.get('producer_config'))
+
+kafka_client.send_message(topic_name, msg)
+```
+
+Config example from example above:
+```
+kafka_config: &kafka_config
+ bootstrap_servers:
+ - server.domain:9093
+ security_protocol: SSL
+ ssl_check_hostname: False
+ ssl_cafile: CARoot.pem
+ ssl_certfile: certificate.pem
+ ssl_keyfile: key.pem
+producer_config:
+ <<: *kafka_config
+consumer_config:
+ <<: *kafka_config
+ consumer_timeout_ms: 1000
+```
+
+## Working with Excel
+
+### Reading file
+
+For reading excel-file you should use function *divinegift.excel.read_excel*
+
+You should pass filename, array with column names
+
+Optional fields are:
+ sheet_name, int_columns, date_columns, start_row
+
+```
+from divinegift import excel
+
+filename = 'your/path/to/excel.xlsx' # or it could be xls
+excel_header = ['column1', 'column2', ]
+excel_data = excel.read_excel(filename, excel_header)
+```
+
+By default, all cells are read as strings, but if you need read int columns/date columns, you could pass their names
+in parameters int_columns/date_columns. You should name it like you pass it at excel_header
+
+```
+from divinegift import excel
+
+filename = 'your/path/to/excel.xlsx' # or it could be xls
+excel_header = ['column1', 'column2', 'int_col', 'date_col']
+excel_data = excel.read_excel(filename, excel_header, int_columns=['int_col'], date_col=['date_col'])
+```
+
+### Writing file
+
+For writing excel-file you should use function *divinegift.excel.create_excel*
+
+You should pass filename and list with data
+
+Optional fields are:
+ sheet_name, header
+
+When you set excel_header, you could set column width
+
+```
+from divinegift import excel
+
+filename = 'path/to/excel/your.xlsx'
+data = [{'col1': 1, 'col2': 2,},] # or it could be just list of list
+
+excel_header = {'col1': 10, 'col2', 13, }
+excel.create_excel(data, filename, excel_header=excel_header)
+```
+
+
+
+%package help
+Summary: Development documents and examples for divinegift
+Provides: python3-divinegift-doc
+%description help
+**The most useful package for you, young python programmer :)**
+
+# How to use it
+
+## Install this packages before use
+
+* sqlalchemy - For works with databases
+* cx_Oracle - Oracle driver
+* sqlalchemy-pytds - MSSQL driver
+* psycopg2-binary - Postgres driver
+* xlutils - For Excel
+* xlsxwriter - for Excel
+* openpyxl - For Excel
+* transliterate - For Transliteration
+* confluent-kafka[avro] - For work with kafka
+
+## logging
+
+```
+# Import necessary functions
+from divinegift.logger import log_info, log_err, log_warning, set_loglevel
+
+# info msg
+log_info('Your message')
+
+# error msg
+log_err('Error msg',
+ src='Error source', # e.g. str(sys.argv[0])
+ mode=['telegram', 'email'] # May be empty
+ channel={
+ "telegram": -1001343660695,
+ "email": {"TO": ["your@domain.ru"], "FROM": "from@domain.com",
+ "HOST": "smtp.domain.com", "usr": "from@domain.com", "pwd": "supersecretpassword"}
+ }) # You can add "CC" to "email" for add copy_to addresses
+
+# error msg with out sending problem to external system
+log_err('Error msg', src='Error src')
+```
+
+## Pass log_level and log_name through cmd arguments
+
+To specify log_level and log_name in your app you can send it through arguments:
+```
+if __name__ == '__main__':
+ # Get all args from cmd:
+ args = get_args()
+ # Get log_level, log_name, log_dir
+ lp = get_log_param(args)
+ # Set log_level and log_name:
+ set_loglevel(lp.get('log_level'), lp.get('log_name'), lp.get('log_dir'))
+```
+You should pass your args by pairs: key value, e.g. --log_level INFO
+Available variants for logging are:
+* --log_level or shortcut is -ll
+* --log_name or shortcut is -ln
+* --log_dir or shortcut is -ld
+
+log_level could be DEBUG, INFO, WARNING, ERROR
+
+Example of starting app with arguments:
+```
+python test.py -ll INFO -ln test.log
+```
+
+## Config parsing
+
+To parsing configs you can use class *divinegift.config.Settings* .
+By default, it's use yaml as config language. But you can use json-style too.
+
+### YAML-config
+```
+from divinegift.config import Settings # Necessary imports
+
+settings = {}
+
+# You should use divinegift.logger.set_loglevel before config parsing
+s = Settings()
+s.parse_settings('./settings.ini')
+settings = s.get_settings()
+```
+
+#### Config example
+```
+monitoring:
+- telegram
+- email
+- slack
+monitoring_channel:
+ email_to:
+ - aims.control@s7.ru
+ telegram: -1001343660695
+```
+
+### JSON-config
+
+```
+from divinegift.config import Settings # Necessary imports
+
+settings = {}
+
+# You should use divinegift.logger.set_loglevel before config parsing
+s = Settings()
+s.parse_settings('./settings.ini', use_yaml=False)
+settings = s.get_settings()
+```
+
+#### Config example
+
+```
+{
+ "log_level": "INFO",
+ "log_name": "YourAwesomeProject.log",
+ "monitoring": [
+ "telegram",
+ "email"
+ ],
+ "monitoring_channel": {
+ "telegram": -1001343660695,
+ "email_to": [
+ "aims.control@s7.ru"
+ ]
+ }
+ }
+```
+
+## Working with DB (sqlalchemy)
+
+You should define dict with db_conn creditional.
+For example:
+
+### Oracle
+Install oracle driver:
+```
+pip install cx_oracle
+```
+```
+db_conn = {
+ "db_user": "dbuser", # username
+ "db_pass": "dbpass", # password
+ "db_host": "dbhost", # host (ip, fqdn). could be empty if we connect via tns
+ "db_port": "", # port (string). could be empty if we connect via tns
+ "db_name": "dbname", # database name
+ "db_schm": "", # db scheme if not equal username
+ "dialect": "oracle" # if use cx_Oracle or oracle+another_dialect
+}
+```
+### MSSQL
+Install mssql driver:
+```
+pip install sqlalchemy-pytds
+```
+```
+db_conn = {
+ "db_user": "dbuser", # username
+ "db_pass": "dbpass", # password
+ "db_host": "", # host (ip, fqdn). could be empty if we connect via tns
+ "db_port": "", # port (string). could be empty if we connect via tns
+ "db_name": "dbname", # database name
+ "db_schm": "", # db scheme if not equal username
+ "dialect": "mssql+pytds" # mssql dialect
+}
+```
+### Postgres
+Install postgres driver:
+```
+pip install psycopg2
+```
+```
+db_conn = {
+ "db_user": "dbuser", # username
+ "db_pass": "dbpass", # password
+ "db_host": "", # host (ip, fqdn). could be empty if we connect via tns
+ "db_port": "", # port (string). could be empty if we connect via tns
+ "db_name": "dbname", # database name
+ "db_schm": "", # db scheme if not equal username
+ "dialect": "postgresql+psycopg2" # dialect
+}
+```
+
+### Create connection
+
+Use class DBClient to create connection to DB. Old-styled functions, which contained in *divinegift.db* module directly, are deprecated but still works.
+```
+from divinegift.db import DBClient
+connection = DBClient(db_conn) # db_conn - variable which was described above
+# Describe which fields you wants to method get_conn will returned (possible fields are 'engine', 'conn' and 'metadata')
+engine, conn, metadata = connection.get_conn(fields=['engine', 'conn', 'metadata'])
+```
+
+If you need to call stored procedure with db cursors you should use raw connection.
+```
+from divinegift.db import DBClient
+connection = DBClient(db_conn, do_initialize=False) # db_conn - variable which was described above
+connection.set_raw_conn()
+conn = connection.get_conn(fields='conn')
+```
+
+### Get data from sript (file or just string)
+
+After you got "connection" variable you can get data from file or from str variable directly.
+
+```
+from divinegift.db import DBClient
+connection = DBClient(db_conn)
+
+result = connection.get_data('path/to/scripts/some_script.sql')
+# or you can use str variable:
+script = 'select * from dual'
+result = connection.get_data(script)
+print(result)
+>>>[{'dummy': 'X'}]
+```
+
+You can use specific encoding for your files (by default it's 'cp1251').
+Just put it into args:
+```
+result = connection.get_data('path/to/scripts/some_script.sql', encoding='utf8')
+```
+
+Also you can add some variables into your script (e.g. date) and then you can pass it into a function:
+```
+from divinegift.db import DBClient
+connection = DBClient(db_conn)
+
+script = """select * from dual
+where dummy = '$param'"""
+parameters = {'param': 'X'}
+result = connection.get_data(script, **parameters)
+# Or another variant
+result = connection.get_data(script, param='X')
+print(result)
+>>>[{'dummy': 'X'}]
+```
+
+### Run script without getting data
+
+You can run script without recieving data.
+You should use *divinegift.db.DBClient.run_script* for this like get_data, e.g.:
+```
+from divinegift.db import Connection
+connection = Connection(db_conn)
+connection.run_script('path/to/scripts/some_script.sql')
+```
+
+## Sending email
+
+You can use function send_mail from class *divinegift.sender.Sender*
+
+You should set your msg, subject and list of recipients, and account which should be used for sending email
+Simple example:
+```
+from divinegift.sender import Sender
+
+sender = Sender()
+sender.send_mail('Test message', 'Test subject', TO=['your@domain.com'],
+ FROM="from@domain.com", HOST="smtp.domain.com", usr="from", pwd="pwd")
+```
+
+You can specify TO, CC, BCC, HOST, FROM and attachments. Also you can send it like html-message or like text.
+
+You should pass list of attachments files with absolute path to it. You can use function *divinegift.main.get_list_files* for get it.
+For sending email with attachment(s):
+```
+from divinegift.main import get_list_files
+from divinegift.sender import Sender
+
+sender = Sender()
+attachment_list = get_list_files('/path/to/files', add_path=True)
+sender.send_mail('Hello! This are files in attach', 'Test sending attachments', ['your@domain.com'],
+ FROM="from@domain.com", HOST="smtp.domain.com", usr="from", pwd="pwd",
+ attachments=attachment_list)
+# Also you can send only one file:
+attachment = '/path/to/file/file_name'
+sender.send_mail('Hello! There is file in attach', 'File', ['your@domain.com'],
+ FROM="from@domain.com", HOST="smtp.domain.com", usr="from", pwd="pwd",
+ attachments=attachment)
+```
+
+If you set IS_HTML to False (by default it is True), you could send an email like simple text message, not html
+
+## Work with JSON
+
+You can simple parse and create JSONs
+
+To create json you could use *divinegift.main.create_json*
+To parse it you could use *divinegift.main.parse_json*
+Or you could use class *divinegift.main.Json* instead of it
+
+For example:
+```
+from divinegift.main import create_json, parse_json
+A = {'key1': 'data1', 'key2': 'data2'}
+create_json(A, 'json_file_name.json')
+B = parse_json('json_file_name.json')
+
+print(B)
+>>> {'key1': 'data1', 'key2': 'data2'}
+
+from divinegift.main import Json
+A = {'key1': 'data1', 'key2': 'data2'}
+json_obj = Json('json_file_class.json')
+json_obj.set_data(A)
+json_obj.create()
+B = json_obj.parse()
+```
+
+## Work with YAML
+
+You can simple parse and create YAMLs
+
+To create json you could use *divinegift.main.create_yaml*
+To parse it you could use *divinegift.main.parse_yaml*
+Or you could use class *divinegift.main.Yaml* instead of it
+
+For example:
+```
+from divinegift.main import create_yaml, parse_yaml
+A = {'key1': 'data1', 'key2': 'data2'}
+create_yaml(A, 'yaml_file_name.yml')
+B = parse_yaml('yaml_file_name.yml')
+
+print(B)
+>>> {'key1': 'data1', 'key2': 'data2'}
+
+from divinegift.main import Yaml
+A = {'key1': 'data1', 'key2': 'data2'}
+yml_obj = Yaml('yml_file_class.yml')
+yml_obj.set_data(A)
+yml_obj.create()
+B = yml_obj.parse()
+```
+
+## Transliterate strings between Russian and English and back
+
+From version 1.0.8 you can use transliterate library to transliterate strings between languages
+
+Example:
+```
+from divinegift.translit import translit
+
+name = 'SHEVCHENKO ANDREY'
+name_r = translit(name, 'ru_ext')
+name_e = translit(name_r, 'ru_ext', reversed=True)
+name_r_cap = translit(name, 'ru_ext').capitalize()
+name_r_low = translit(name, 'ru_ext').lower()
+
+print(f'From English to Russian: {name}\t->\t{name_r}')
+print(f'From Russian to English: {name_r}\t->\t{name_e}')
+print(f'Capitalize : {name}\t->\t{name_r_cap}')
+print(f'Lower : {name}\t->\t{name_r_low}')
+```
+
+Code from above will show next:
+```
+From English to Russian: SHEVCHENKO ANDREY -> ШЕВЧЕНКО АНДРЕЙ
+From Russian to English: ШЕВЧЕНКО АНДРЕЙ -> SHEVCHENKO ANDREI
+Capitalize : SHEVCHENKO ANDREY -> Шевченко андрей
+Lower : SHEVCHENKO ANDREY -> шевченко андрей
+```
+
+## Encryption
+From version 1.0.10 you can use encryption module
+
+### Simple example
+Example:
+```
+from divinegift.cipher import get_key, get_cipher, encrypt_str, decrypt_str
+
+cipher_key = get_key()
+cipher = get_cipher(cipher_key)
+text = 'qwerty1234!!'
+text_enc = encrypt_str(text, cipher)
+print(text_enc)
+text_dec = decrypt_str(text_enc, cipher)
+print(text_dec)
+```
+
+Code above will output next:
+```
+gAAAAABcanXfhUr9i__R_24rPyrHzZoMgQSTYiBmx9ZtVqdcMiGZPOxoSz4gkAW0Y9TDWpAJ6jzAjPo-mrK_IcJcdByyfWrbhQ==
+qwerty1234!!
+```
+
+If you use parameter get_str=False in functions encrypt_str and decrypt_str than this functions will returns binary string
+
+### Works with key in file
+
+Save your key in file by *write_key* function:
+```
+from divinegift.cipher import get_key, write_key
+
+cipher_key = get_key()
+write_key('key.ck', cipher_key)
+```
+
+Read your key file by *read_key* function:
+```
+from divinegift.cipher import read_key
+
+cipher_key = read_key('key.ck')
+```
+
+### Caesar
+
+You can use caesar encrypt/decrypt:
+```
+from divinegift.cipher import caesar_code
+
+text = caesar_code('Hello, World!', shift=5)
+print(text)
+```
+It will output next:
+```
+Mjqqt, 1twqi!
+```
+
+### Easy encription/decryption database-passwords for more security
+
+Before all you should encrypt your file with settings.
+Use next code to do this once:
+```
+from divinegift.config import Settings
+
+s = Settings()
+s.parse_settings('settings.conf')
+s.initialize_cipher()
+s.encrypt_password('db_conn') # db_conn - name of db connection in settings.conf which contains "db_pass"
+s.save_settings('settings.conf')
+```
+
+After that your password in section 'db_conn' will automaticaly encrypted.
+If you have more db-connections just add s.encrypt_password('db_conn_name_you_have') before saving function
+
+Next you must use decryption function in your code to use connection:
+```
+from divinegift.config import Settings
+
+s = Settings()
+s.parse_settings('settings.conf')
+s.decrypt_password('db_conn') # db_conn - name of db connection in settings.conf which contains "db_pass"
+```
+
+
+## Live templates. Start create your app as easy as possible
+
+From version 1.0.11 you can create files from templates.
+You should use module *templator* for this.
+
+Example:
+Create tmp.py with following text and run it:
+```
+from divinegift.templator import Templator
+
+t = Templator()
+# create console app, or main logic (you can omit the file extension, '.py' will add automaticaly.):
+t.create_console('your_awesome_name.py')
+# or
+t.create_console() # it will create 'main.py' file
+
+# create QT-app:
+t.create_gui(your_awesome_name.py')
+# or
+t.create_gui() # it will create 'main_gui.py' file
+
+# create config file:
+t.create_config('your_config_name.ini')
+# or
+t.create_config() # it will create 'settings.ini' file
+
+# After creating file with config you can add email section on it:
+t.add_email_config('your_config_name.ini')
+# or
+t.add_email_config() # it will add email section to 'settings.ini'
+```
+
+## Kafka Client
+
+From version 1.3.0 you can use kafka client to read and write data from/to topics
+
+
+Example:
+```
+from divinegift.kafka_client import KafkaClient
+
+kafka_client = KafkaClient()
+
+# Reader
+kafka_client.set_consumer(**s.settings.get('consumer_config'))
+
+messages = kafka_client.read_messages(topic_name)
+# You can read all messages from begin if you needed:
+messages = kafka_client.read_messages(topic_name, from_beginning=True)
+
+# Writer
+kafka_client.set_consumer(**s.settings.get('producer_config'))
+
+kafka_client.send_message(topic_name, msg)
+```
+
+Config example from example above:
+```
+kafka_config: &kafka_config
+ bootstrap_servers:
+ - server.domain:9093
+ security_protocol: SSL
+ ssl_check_hostname: False
+ ssl_cafile: CARoot.pem
+ ssl_certfile: certificate.pem
+ ssl_keyfile: key.pem
+producer_config:
+ <<: *kafka_config
+consumer_config:
+ <<: *kafka_config
+ consumer_timeout_ms: 1000
+```
+
+## Working with Excel
+
+### Reading file
+
+For reading excel-file you should use function *divinegift.excel.read_excel*
+
+You should pass filename, array with column names
+
+Optional fields are:
+ sheet_name, int_columns, date_columns, start_row
+
+```
+from divinegift import excel
+
+filename = 'your/path/to/excel.xlsx' # or it could be xls
+excel_header = ['column1', 'column2', ]
+excel_data = excel.read_excel(filename, excel_header)
+```
+
+By default, all cells are read as strings, but if you need read int columns/date columns, you could pass their names
+in parameters int_columns/date_columns. You should name it like you pass it at excel_header
+
+```
+from divinegift import excel
+
+filename = 'your/path/to/excel.xlsx' # or it could be xls
+excel_header = ['column1', 'column2', 'int_col', 'date_col']
+excel_data = excel.read_excel(filename, excel_header, int_columns=['int_col'], date_col=['date_col'])
+```
+
+### Writing file
+
+For writing excel-file you should use function *divinegift.excel.create_excel*
+
+You should pass filename and list with data
+
+Optional fields are:
+ sheet_name, header
+
+When you set excel_header, you could set column width
+
+```
+from divinegift import excel
+
+filename = 'path/to/excel/your.xlsx'
+data = [{'col1': 1, 'col2': 2,},] # or it could be just list of list
+
+excel_header = {'col1': 10, 'col2', 13, }
+excel.create_excel(data, filename, excel_header=excel_header)
+```
+
+
+
+%prep
+%autosetup -n divinegift-2.15.16
+
+%build
+%py3_build
+
+%install
+%py3_install
+install -d -m755 %{buildroot}/%{_pkgdocdir}
+if [ -d doc ]; then cp -arf doc %{buildroot}/%{_pkgdocdir}; fi
+if [ -d docs ]; then cp -arf docs %{buildroot}/%{_pkgdocdir}; fi
+if [ -d example ]; then cp -arf example %{buildroot}/%{_pkgdocdir}; fi
+if [ -d examples ]; then cp -arf examples %{buildroot}/%{_pkgdocdir}; fi
+pushd %{buildroot}
+if [ -d usr/lib ]; then
+ find usr/lib -type f -printf "/%h/%f\n" >> filelist.lst
+fi
+if [ -d usr/lib64 ]; then
+ find usr/lib64 -type f -printf "/%h/%f\n" >> filelist.lst
+fi
+if [ -d usr/bin ]; then
+ find usr/bin -type f -printf "/%h/%f\n" >> filelist.lst
+fi
+if [ -d usr/sbin ]; then
+ find usr/sbin -type f -printf "/%h/%f\n" >> filelist.lst
+fi
+touch doclist.lst
+if [ -d usr/share/man ]; then
+ find usr/share/man -type f -printf "/%h/%f.gz\n" >> doclist.lst
+fi
+popd
+mv %{buildroot}/filelist.lst .
+mv %{buildroot}/doclist.lst .
+
+%files -n python3-divinegift -f filelist.lst
+%dir %{python3_sitelib}/*
+
+%files help -f doclist.lst
+%{_docdir}/*
+
+%changelog
+* Tue Apr 11 2023 Python_Bot <Python_Bot@openeuler.org> - 2.15.16-1
+- Package Spec generated