рдореИрдВрдиреЗ рд╣рд╛рд▓ рд╣реА рдореЗрдВ рд▓рд┐рдЦрд╛ рд╣реИ
рдкреНрд░рд╢реНрди рдХреА рдкреГрд╖реНрдарднреВрдорд┐ рдпрд╣ рд╣реИ: рдПрдХ рдмрд╛рд░ рдПрдХ рдкрд░рд┐рдпреЛрдЬрдирд╛ рдереА, рдкрд╣рд▓реЗ рдпрд╣ рдЙрдкрдпреЛрдЧрд┐рддрд╛рдУрдВ рдФрд░ рд╕реНрдХреНрд░рд┐рдкреНрдЯ рдХреЗ рд╕рд╛рде рдПрдХ рдЫреЛрдЯрд╛ рд╕рд╛ рдореЛрдиреЛрд▓рд┐рде рдерд╛, рд▓реЗрдХрд┐рди рд╕рдордп рдХреЗ рд╕рд╛рде рдпрд╣ рдмрдврд╝рддрд╛ рдЧрдпрд╛, рд╕реЗрд╡рд╛рдУрдВ рдореЗрдВ рд╡рд┐рднрд╛рдЬрд┐рдд рд╣реЛ рдЧрдпрд╛, рдЬреЛ рдмрджрд▓реЗ рдореЗрдВ рдорд╛рдЗрдХреНрд░реЛрд╕рд░реНрд╡рд┐рд╕реЗрдЬ рдореЗрдВ рд╡рд┐рднрд╛рдЬрд┐рдд рд╣реЛрдиреЗ рд▓рдЧрд╛, рдФрд░ рдлрд┐рд░ рдмрдбрд╝рд╛ рдХрд┐рдпрд╛ рдЧрдпрд╛. рд╕рдмрд╕реЗ рдкрд╣рд▓реЗ, рдпрд╣ рд╕рдм рдирдВрдЧреЗ рд╡реАрдкреАрдПрд╕ рдкрд░ рдХрд┐рдпрд╛ рдЧрдпрд╛ рдерд╛, рдЬрд┐рд╕ рдкрд░ рдХреЛрдб рд╕реНрдерд╛рдкрд┐рдд рдХрд░рдиреЗ рдФрд░ рддреИрдирд╛рдд рдХрд░рдиреЗ рдХреА рдкреНрд░рдХреНрд░рд┐рдпрд╛ Ansible рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рд╕реНрд╡рдЪрд╛рд▓рд┐рдд рдХреА рдЧрдИ рдереА, рдФрд░ рдкреНрд░рддреНрдпреЗрдХ рд╕реЗрд╡рд╛ рдХреЛ рдЖрд╡рд╢реНрдпрдХ рд╕реЗрдЯрд┐рдВрдЧреНрд╕ рдФрд░ рдХреБрдВрдЬрд┐рдпреЛрдВ рдХреЗ рд╕рд╛рде рдПрдХ YAML рдХреЙрдиреНрдлрд╝рд┐рдЧрд░реЗрд╢рди рдХреЗ рд╕рд╛рде рд╕рдВрдХрд▓рд┐рдд рдХрд┐рдпрд╛ рдЧрдпрд╛ рдерд╛, рдФрд░ рдПрдХ рд╕рдорд╛рди рдХреЙрдиреНрдлрд╝рд┐рдЧрд░реЗрд╢рди рдлрд╝рд╛рдЗрд▓ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд┐рдпрд╛ рдЧрдпрд╛ рдерд╛ рд╕реНрдерд╛рдиреАрдп рд▓реЙрдиреНрдЪ, рдЬреЛ рдмрд╣реБрдд рд╕реБрд╡рд┐рдзрд╛рдЬрдирдХ рдерд╛, рдХреНрдпреЛрдВрдХрд┐ .k рдпрд╣ рдХреЙрдиреНрдлрд╝рд┐рдЧрд░реЗрд╢рди рдПрдХ рд╡реИрд╢реНрд╡рд┐рдХ рдСрдмреНрдЬреЗрдХреНрдЯ рдореЗрдВ рд▓реЛрдб рдХрд┐рдпрд╛ рдЧрдпрд╛ рд╣реИ, рдЬреЛ рдкреНрд░реЛрдЬреЗрдХреНрдЯ рдореЗрдВ рдХрд╣реАрдВ рд╕реЗ рднреА рдкрд╣реБрдВрдЪ рдпреЛрдЧреНрдп рд╣реИред
рд╣рд╛рд▓рд╛рдБрдХрд┐, рдорд╛рдЗрдХреНрд░реЛрд╕рд░реНрд╡рд┐рд╕реЗрдЬ рдХреА рд╕рдВрдЦреНрдпрд╛, рдЙрдирдХреЗ рдХрдиреЗрдХреНрд╢рди рдФрд░ рдореЗрдВ рд╡реГрджреНрдзрд┐
рдЗрд╕ рд╕рдВрдмрдВрдз рдореЗрдВ, рдХреЙрдиреНрдлрд╝рд┐рдЧрд░реЗрд╢рди рдСрдмреНрдЬреЗрдХреНрдЯ рдХреЗ рдирд┐рд░реНрдорд╛рдг рдХреЗ рддрдВрддреНрд░ рдХреЛ рд╣рдорд╛рд░реА рдХреНрд▓рд╛рд╕рд┐рдХ рдХреЙрдиреНрдлрд╝рд┐рдЧрд░реЗрд╢рди рдлрд╝рд╛рдЗрд▓ рдФрд░ рдХреБрдмреЗрд░ рдХреЗ рд░рд╣рд╕реНрдпреЛрдВ рджреЛрдиреЛрдВ рдХреЗ рд╕рд╛рде рдХрд╛рдо рдХрд░рдиреЗ рдореЗрдВ рд╕рдХреНрд╖рдо рд╣реЛрдиреЗ рдХреЗ рд▓рд┐рдП рд╕рдВрд╢реЛрдзрд┐рдд рдХрд┐рдпрд╛ рдЧрдпрд╛ рдерд╛ред рддреАрд╕рд░реЗ рдкрд╛рдпрдерди рдХреА рднрд╛рд╖рд╛ рдореЗрдВ рдПрдХ рдЕрдзрд┐рдХ рдХрдареЛрд░ рдХреЙрдиреНрдлрд╝рд┐рдЧрд░реЗрд╢рди рд╕рдВрд░рдЪрдирд╛ рднреА рдирд┐рд░реНрджрд┐рд╖реНрдЯ рдХреА рдЧрдИ рдереА, рдЬреЛ рдЗрд╕ рдкреНрд░рдХрд╛рд░ рд╣реИ:
рдбрд┐рдХреНрдЯ[str, рдбрд┐рдХреНрдЯ[str, рдпреВрдирд┐рдпрди[str, int, рдлреНрд▓реЛрдЯ]]]
рдЕрд░реНрдерд╛рддреН, рдЕрдВрддрд┐рдо рдХреЙрдЧрдлрд┐рдЧ рдирд╛рдорд┐рдд рдЕрдиреБрднрд╛рдЧреЛрдВ рд╡рд╛рд▓рд╛ рдПрдХ рд╢рдмреНрджрдХреЛрд╢ рд╣реИ, рдЬрд┐рдирдореЗрдВ рд╕реЗ рдкреНрд░рддреНрдпреЗрдХ рд╕рд░рд▓ рдкреНрд░рдХрд╛рд░реЛрдВ рдХреЗ рдореВрд▓реНрдпреЛрдВ рд╡рд╛рд▓рд╛ рдПрдХ рд╢рдмреНрджрдХреЛрд╢ рд╣реИред рдФрд░ рдЕрдиреБрднрд╛рдЧ рдПрдХ рдирд┐рд╢реНрдЪрд┐рдд рдкреНрд░рдХрд╛рд░ рдХреЗ рд╕рдВрд╕рд╛рдзрдиреЛрдВ рдХреЗ рдХреЙрдиреНрдлрд╝рд┐рдЧрд░реЗрд╢рди рдФрд░ рдкрд╣реБрдВрдЪ рдХрд╛ рд╡рд░реНрдгрди рдХрд░рддреЗ рд╣реИрдВред рд╣рдорд╛рд░реЗ рдХреЙрдиреНрдлрд╝рд┐рдЧрд░реЗрд╢рди рдХреЗ рдПрдХ рдЯреБрдХрдбрд╝реЗ рдХрд╛ рдПрдХ рдЙрджрд╛рд╣рд░рдг:
adminka:
django_secret: "ExtraLongAndHardCode"
db_main:
engine: mysql
host: 256.128.64.32
user: cool_user
password: "SuperHardPassword"
redis:
host: 256.128.64.32
pw: "SuperHardPassword"
port: 26379
smtp:
server: smtp.gmail.com
port: 465
email: [email protected]
pw: "SuperHardPassword"
рдЙрд╕реА рд╕рдордп, рдореИрджрд╛рди engine
рдбреЗрдЯрд╛рдмреЗрд╕ рдХреЛ SQLite рдкрд░ рд╕реНрдерд╛рдкрд┐рдд рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ, рдФрд░ redis
рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рд╕реЗрдЯ mock
, рд╕рд╣реЗрдЬрдиреЗ рдХреЗ рд▓рд┐рдП рдлрд╝рд╛рдЗрд▓ рдХрд╛ рдирд╛рдо рднреА рдирд┐рд░реНрджрд┐рд╖реНрдЯ рдХрд░рдирд╛ - рдЗрди рдорд╛рдкрджрдВрдбреЛрдВ рдХреЛ рд╕рд╣реА рдврдВрдЧ рд╕реЗ рдкрд╣рдЪрд╛рдирд╛ рдФрд░ рд╕рдВрд╕рд╛рдзрд┐рдд рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ, рдЬрд┐рд╕рд╕реЗ рдбрд┐рдмрдЧрд┐рдВрдЧ, рдпреВрдирд┐рдЯ рдкрд░реАрдХреНрд╖рдг рдФрд░ рдХрд┐рд╕реА рднреА рдЕрдиреНрдп рдЖрд╡рд╢реНрдпрдХрддрд╛рдУрдВ рдХреЗ рд▓рд┐рдП рд╕реНрдерд╛рдиреАрдп рд░реВрдк рд╕реЗ рдХреЛрдб рдХреЛ рдЪрд▓рд╛рдирд╛ рдЖрд╕рд╛рди рд╣реЛ рдЬрд╛рддрд╛ рд╣реИред рдпрд╣ рд╣рдорд╛рд░реЗ рд▓рд┐рдП рд╡рд┐рд╢реЗрд╖ рд░реВрдк рд╕реЗ рдорд╣рддреНрд╡рдкреВрд░реНрдг рд╣реИ рдХреНрдпреЛрдВрдХрд┐ рдХрдИ рдЕрдиреНрдп рдЬрд╝рд░реВрд░рддреЗрдВ рд╣реИрдВ - рд╣рдорд╛рд░реЗ рдХреЛрдб рдХрд╛ рд╣рд┐рд╕реНрд╕рд╛ рд╡рд┐рднрд┐рдиреНрди рд╡рд┐рд╢реНрд▓реЗрд╖рдгрд╛рддреНрдордХ рдЧрдгрдирд╛рдУрдВ рдХреЗ рд▓рд┐рдП рд╣реИ, рдпрд╣ рди рдХреЗрд╡рд▓ рдСрд░реНрдХреЗрд╕реНрдЯреНрд░реЗрд╢рди рд╡рд╛рд▓реЗ рд╕рд░реНрд╡рд░ рдкрд░ рдЪрд▓рддрд╛ рд╣реИ, рдмрд▓реНрдХрд┐ рд╡рд┐рднрд┐рдиреНрди рд╕реНрдХреНрд░рд┐рдкреНрдЯ рдХреЗ рд╕рд╛рде, рдФрд░ рд╡рд┐рд╢реНрд▓реЗрд╖рдХреЛрдВ рдХреЗ рдХрдВрдкреНрдпреВрдЯрд░ рдкрд░ рднреА рдЪрд▓рддрд╛ рд╣реИ рдЬрд┐рдиреНрд╣реЗрдВ рдХрд╛рдо рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реЛрддреА рд╣реИ рдФрд░ рдмреИрдХрдПрдВрдб рд╕рдорд╕реНрдпрд╛рдУрдВ рдХреА рдЪрд┐рдВрддрд╛ рдХрд┐рдП рдмрд┐рдирд╛ рдЬрдЯрд┐рд▓ рдбреЗрдЯрд╛ рдкреНрд░реЛрд╕реЗрд╕рд┐рдВрдЧ рдкрд╛рдЗрдкрд▓рд╛рдЗрдиреЛрдВ рдХреЛ рдбреАрдмрдЧ рдХрд░реЗрдВред рд╡реИрд╕реЗ, рдпрд╣ рд╕рд╛рдЭрд╛ рдХрд░рдиреЗ рдореЗрдВ рдХреЛрдИ рд╣рд░реНрдЬ рдирд╣реАрдВ рд╣реЛрдЧрд╛ рдХрд┐ рдХреЙрдиреНрдлрд┐рдЧ рд▓реЗрдЖрдЙрдЯ рдХреЛрдб рд╕рд╣рд┐рдд рд╣рдорд╛рд░реЗ рдореБрдЦреНрдп рдЙрдкрдХрд░рдг рдЗрд╕рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ рдЗрдВрд╕реНрдЯреЙрд▓ рдХрд┐рдП рдЧрдП рд╣реИрдВ setup.py
- рд╕рд╛рде рдореЗрдВ рдпрд╣ рд╣рдорд╛рд░реЗ рдХреЛрдб рдХреЛ рдПрдХ рдПрдХрд▓ рдкрд╛рд░рд┐рд╕реНрдерд┐рддрд┐рдХреА рддрдВрддреНрд░ рдореЗрдВ рдПрдХрдЬреБрдЯ рдХрд░рддрд╛ рд╣реИ, рдЬреЛ рдкреНрд▓реЗрдЯрдлрд╝реЙрд░реНрдо рдФрд░ рдЙрдкрдпреЛрдЧ рдХреА рд╡рд┐рдзрд┐ рд╕реЗ рд╕реНрд╡рддрдВрддреНрд░ рд╣реИред
рдХреБрдмреЗрд░рдиреЗрдЯреНрд╕ рдкреЙрдб рдХрд╛ рд╡рд┐рд╡рд░рдг рдЗрд╕ рддрд░рд╣ рджрд┐рдЦрддрд╛ рд╣реИ:
containers:
- name : enter-api
image: enter-api:latest
ports:
- containerPort: 80
volumeMounts:
- name: db-main-secret-volume
mountPath: /etc/secrets/db-main
volumes:
- name: db-main-secret-volume
secret:
secretName: db-main-secret
рдЕрд░реНрдерд╛рддреН рдкреНрд░рддреНрдпреЗрдХ рд░рд╣рд╕реНрдп рдПрдХ рдЦрдгреНрдб рдХрд╛ рд╡рд░реНрдгрди рдХрд░рддрд╛ рд╣реИред рд░рд╣рд╕реНрдп рд╕реНрд╡рдпрдВ рдЗрд╕ рдкреНрд░рдХрд╛рд░ рдмрдирд╛рдпреЗ рдЧрдпреЗ рд╣реИрдВ:
apiVersion: v1
kind: Secret
metadata:
name: db-main-secret
type: Opaque
stringData:
db_main.yaml: |
engine: sqlite
filename: main.sqlite3
рдЗрд╕рдХреЗ рдкрд░рд┐рдгрд╛рдорд╕реНрд╡рд░реВрдк рдкрде рдкрд░ YAML рдлрд╝рд╛рдЗрд▓реЛрдВ рдХрд╛ рдирд┐рд░реНрдорд╛рдг рд╣реЛрддрд╛ рд╣реИ /etc/secrets/db-main/section_name.yaml
рдФрд░ рд╕реНрдерд╛рдиреАрдп рд▓реЙрдиреНрдЪ рдХреЗ рд▓рд┐рдП, рдХреЙрдиреНрдлрд╝рд┐рдЧрд░реЗрд╢рди рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ, рдЬреЛ рдкреНрд░реЛрдЬреЗрдХреНрдЯ рдХреА рд░реВрдЯ рдирд┐рд░реНрджреЗрд╢рд┐рдХрд╛ рдореЗрдВ рдпрд╛ рдкрд░реНрдпрд╛рд╡рд░рдг рдЪрд░ рдореЗрдВ рдирд┐рд░реНрджрд┐рд╖реНрдЯ рдкрде рдХреЗ рд╕рд╛рде рд╕реНрдерд┐рдд рд╣реЛрддрд╛ рд╣реИред рдЗрди рд╕реБрд╡рд┐рдзрд╛рдУрдВ рдХреЗ рд▓рд┐рдП рдЬрд┐рдореНрдореЗрджрд╛рд░ рдХреЛрдб рдХреЛ рд╕реНрдкреЙрдЗрд▓рд░ рдореЗрдВ рджреЗрдЦрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИред
config.py
__author__ = 'AivanF'
__copyright__ = 'Copyright 2020, AivanF'
import os
import yaml
__all__ = ['config']
PROJECT_DIR = os.path.abspath(__file__ + 3 * '/..')
SECRETS_DIR = '/etc/secrets'
KEY_LOG = '_config_log'
KEY_DBG = 'debug'
def is_yes(value):
if isinstance(value, str):
value = value.lower()
if value in ('1', 'on', 'yes', 'true'):
return True
else:
if value in (1, True):
return True
return False
def update_config_part(config, key, data):
if key not in config:
config[key] = data
else:
config[key].update(data)
def parse_big_config(config, filename):
'''
Parse YAML config with multiple section
'''
if not os.path.isfile(filename):
return False
with open(filename) as f:
config_new = yaml.safe_load(f.read())
for key, data in config_new.items():
update_config_part(config, key, data)
config[KEY_LOG].append(filename)
return True
def parse_tiny_config(config, key, filename):
'''
Parse YAML config with a single section
'''
with open(filename) as f:
config_tiny = yaml.safe_load(f.read())
update_config_part(config, key, config_tiny)
config[KEY_LOG].append(filename)
def combine_config():
config = {
# To debug config load code
KEY_LOG: [],
# To debug other code
KEY_DBG: is_yes(os.environ.get('DEBUG')),
}
# For simple local runs
CONFIG_SIMPLE = os.path.join(PROJECT_DIR, 'config.yaml')
parse_big_config(config, CONFIG_SIMPLE)
# For container's tests
CONFIG_ENVVAR = os.environ.get('CONFIG')
if CONFIG_ENVVAR is not None:
if not parse_big_config(config, CONFIG_ENVVAR):
raise ValueError(
f'No config file from EnvVar:n'
f'{CONFIG_ENVVAR}'
)
# For K8s secrets
for path, dirs, files in os.walk(SECRETS_DIR):
depth = path[len(SECRETS_DIR):].count(os.sep)
if depth > 1:
continue
for file in files:
if file.endswith('.yaml'):
filename = os.path.join(path, file)
key = file.rsplit('.', 1)[0]
parse_tiny_config(config, key, filename)
return config
def build_config():
config = combine_config()
# Preprocess
for key, data in config.items():
if key.startswith('db_'):
if data['engine'] == 'sqlite':
data['filename'] = os.path.join(PROJECT_DIR, data['filename'])
# To verify correctness
if config[KEY_DBG]:
print(f'** Loaded config:n{yaml.dump(config)}')
else:
print(f'** Loaded config from: {config[KEY_LOG]}')
return config
config = build_config()
рдпрд╣рд╛рдВ рддрд░реНрдХ рдХрд╛рдлреА рд╕рд░рд▓ рд╣реИ: рд╣рдо рдкрд░реНрдпрд╛рд╡рд░рдг рдЪрд░ рджреНрд╡рд╛рд░рд╛ рдкреНрд░реЛрдЬреЗрдХреНрдЯ рдирд┐рд░реНрджреЗрд╢рд┐рдХрд╛ рдФрд░ рдкрдереЛрдВ рд╕реЗ рдмрдбрд╝реЗ рдХреЙрдиреНрдлрд╝рд┐рдЧрд░реЗрд╢рди рдХреЛ рдЬреЛрдбрд╝рддреЗ рд╣реИрдВ, рдФрд░ рдХреБрдмреЗрд░ рд░рд╣рд╕реНрдпреЛрдВ рд╕реЗ рдЫреЛрдЯреЗ рдХреЙрдиреНрдлрд╝рд┐рдЧрд░реЗрд╢рди рдЕрдиреБрднрд╛рдЧреЛрдВ рдХреЛ рдЬреЛрдбрд╝рддреЗ рд╣реИрдВ, рдФрд░ рдлрд┐рд░ рдЙрдиреНрд╣реЗрдВ рдереЛрдбрд╝рд╛ рдкреНрд░реАрдкреНрд░реЛрд╕реЗрд╕ рдХрд░рддреЗ рд╣реИрдВред рд╕рд╛рде рд╣реА рдХреБрдЫ рдЪрд░ рднреАред рдореИрдВ рдзреНрдпрд╛рди рджреЗрддрд╛ рд╣реВрдВ рдХрд┐ рд░рд╣рд╕реНрдпреЛрдВ рд╕реЗ рдлрд╝рд╛рдЗрд▓реЛрдВ рдХреА рдЦреЛрдЬ рдХрд░рддреЗ рд╕рдордп, рдПрдХ рдЧрд╣рд░рд╛рдИ рд╕реАрдорд╛ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ, рдХреНрдпреЛрдВрдХрд┐ K8s рдкреНрд░рддреНрдпреЗрдХ рд░рд╣рд╕реНрдп рдореЗрдВ рдПрдХ рдЫрд┐рдкрд╛ рд╣реБрдЖ рдлрд╝реЛрд▓реНрдбрд░ рдмрдирд╛рддрд╛ рд╣реИ рдЬрд╣рд╛рдВ рд░рд╣рд╕реНрдп рд╕реНрд╡рдпрдВ рд╕рдВрдЧреНрд░рд╣реАрдд рд╣реЛрддреЗ рд╣реИрдВ, рдФрд░ рдмрд╕ рдПрдХ рд▓рд┐рдВрдХ рдЙрдЪреНрдЪ рд╕реНрддрд░ рдкрд░ рд╕реНрдерд┐рдд рд╣реЛрддрд╛ рд╣реИред
рдореБрдЭреЗ рдЖрд╢рд╛ рд╣реИ рдХрд┐ рдЬреЛ рд╡рд░реНрдгрд┐рдд рд╣реИ рд╡рд╣ рдХрд┐рд╕реА рдХреЗ рд▓рд┐рдП рдЙрдкрдпреЛрдЧреА рд╣реЛрдЧрд╛ :) рд╕реБрд░рдХреНрд╖рд╛ рдпрд╛ рд╕реБрдзрд╛рд░ рдХреЗ рдЕрдиреНрдп рдХреНрд╖реЗрддреНрд░реЛрдВ рдХреЗ рд╕рдВрдмрдВрдз рдореЗрдВ рдХреЛрдИ рднреА рдЯрд┐рдкреНрдкрдгреА рдФрд░ рд╕рд┐рдлрд╛рд░рд┐рд╢реЗрдВ рд╕реНрд╡реАрдХрд╛рд░ рдХреА рдЬрд╛рддреА рд╣реИрдВред рд╕рдореБрджрд╛рдп рдХреА рд░рд╛рдп рднреА рджрд┐рд▓рдЪрд╕реНрдк рд╣реИ, рд╢рд╛рдпрдж рдпрд╣ рдХреЙрдиреНрдлрд┐рдЧрдореИрдкреНрд╕ рдХреЗ рд▓рд┐рдП рд╕рдорд░реНрдерди рдЬреЛрдбрд╝рдиреЗ (рд╣рдорд╛рд░рд╛ рдкреНрд░реЛрдЬреЗрдХреНрдЯ рдЕрднреА рддрдХ рдЙрдирдХрд╛ рдЙрдкрдпреЛрдЧ рдирд╣реАрдВ рдХрд░рддрд╛ рд╣реИ) рдФрд░ GitHub / PyPI рдкрд░ рдХреЛрдб рдкреНрд░рдХрд╛рд╢рд┐рдд рдХрд░рдиреЗ рд▓рд╛рдпрдХ рд╣реИ? рд╡реНрдпрдХреНрддрд┐рдЧрдд рд░реВрдк рд╕реЗ, рдореБрдЭреЗ рд▓рдЧрддрд╛ рд╣реИ рдХрд┐ рдкрд░рд┐рдпреЛрдЬрдирд╛рдУрдВ рдХреЗ рд╕рд╛рд░реНрд╡рднреМрдорд┐рдХ рд╣реЛрдиреЗ рдХреЗ рд▓рд┐рдП рдРрд╕реА рдЪреАрдЬреЗрдВ рдмрд╣реБрдд рд╡реНрдпрдХреНрддрд┐рдЧрдд рд╣реИрдВ, рдФрд░ рдЕрдиреНрдп рд▓реЛрдЧреЛрдВ рдХреЗ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рдкрд░ рдереЛрдбрд╝рд╛ рдирдЬрд╝рд░ рдбрд╛рд▓рдирд╛, рдЬреИрд╕рд╛ рдХрд┐ рдпрд╣рд╛рдВ рджрд┐рдпрд╛ рдЧрдпрд╛ рд╣реИ, рдФрд░ рдмрд╛рд░реАрдХрд┐рдпреЛрдВ, рдпреБрдХреНрддрд┐рдпреЛрдВ рдФрд░ рд╕рд░реНрд╡реЛрддреНрддрдо рдкреНрд░рдерд╛рдУрдВ рдХреА рдЪрд░реНрдЪрд╛ рд╣реИ, рдЬрд┐рд╕реЗ рдореИрдВ рдЯрд┐рдкреНрдкрдгрд┐рдпреЛрдВ рдореЗрдВ рджреЗрдЦрдиреЗ рдХреА рдЙрдореНрдореАрдж рдХрд░рддрд╛ рд╣реВрдВ , рдХрд╛рдлреА рд╣реИ ЁЯШЙ
рдХреЗрд╡рд▓ рдкрдВрдЬреАрдХреГрдд рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рд╣реА рд╕рд░реНрд╡реЗрдХреНрд╖рдг рдореЗрдВ рднрд╛рдЧ рд▓реЗ рд╕рдХрддреЗ рд╣реИрдВред
рдХреНрдпрд╛ рдореБрдЭреЗ рдПрдХ рдкреНрд░реЛрдЬреЗрдХреНрдЯ/рд▓рд╛рдЗрдмреНрд░реЗрд░реА рдХреЗ рд░реВрдк рдореЗрдВ рдкреНрд░рдХрд╛рд╢рд┐рдд рдХрд░рдирд╛ рдЪрд╛рд╣рд┐рдП?
-
0,0% рддрдХ рд╣рд╛рдВ, рдореИрдВ /рдпреЛрдЧрджрд╛рди0 рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░реВрдВрдЧрд╛
-
33,3% рддрдХ рд╣рд╛рдБ, рдпрд╣ рдмрд╣реБрдд рдЕрдЪреНрдЫрд╛ рд▓рдЧрддрд╛ рд╣реИ4
-
41,7% рддрдХ рдирд╣реАрдВ, рдХрд┐рд╕реЗ рдЗрд╕реЗ рдЕрдкрдиреЗ рдкреНрд░рд╛рд░реВрдк рдореЗрдВ рдФрд░ рдЕрдкрдиреА рдЖрд╡рд╢реНрдпрдХрддрд╛рдУрдВ рдХреЗ рдЕрдиреБрд░реВрдк рд╕реНрд╡рдпрдВ рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ5
-
25,0% рддрдХ рдореИрдВ рдЙрддреНрддрд░ рджреЗрдиреЗ рд╕реЗ рдмрдЪреВрдВрдЧрд╛3
12 рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛рдУрдВ рдиреЗ рдорддрджрд╛рди рдХрд┐рдпрд╛ред 3 рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдЕрдиреБрдкрд╕реНрдерд┐рдд рд░рд╣реЗред
рд╕реНрд░реЛрдд: www.habr.com