EnvServ: Мой первый удобный велосипед

23fc748c21170cd4906dd0726a5308c8

Предисловие

Это мой первый пост на Хабре и мой первый проект для PyPI. Заранее прошу прощения, если где-то допустил оплошность.

Приятного чтения!

Цель проекта

На работе я часто сталкивался с переменными окружения. С одной стороны они удобные и безопасные и к ним вопросов нет. Но с другой стороны, работа с ними в коде мне показалась сложной в плане самой записи.

Чтобы мне было легче объяснить, рассмотрим пример:

import os, dotenv

dotenv.load_dotenv()

projectid = int(os.environ.get("PROJECT_ID"))
switch = bool(os.environ.get("SWITCH"))
sql_user = os.environ.get('SQL_USER')
sql_pass = os.environ.get('SQL_PASSWORD')

Здесь указаны несколько переменных, которые потом будут указаны в проекте.
Но дело в том, что если переменных потребуется больше, то самих таких строк будет больше. И тем самым читать такой код можно, но потребуется время и внимательность.

Также сталкивался с проблемой своей невнимательности по поводу перевода в другой тип данных, ведь с переменными окружения Python работает сразу как со строкой, что не всегда удобно и понятно.

Моей целью было упрощение чтения своего кода и увеличение скорости разработки, а так же простого душевного спокойствия насчёт чтение этого кода. И поэтому меня заинтересовало написать данную библиотеку.

Реализация

Весь концепт реализации я взял из библиотеки Pydantic, которая меня в своё время заинтересовала и стала моим помощником в работе. Поэтому я начал строить у себя в голове и в редакторе красивую схему.

Как она выглядела (Ниже псевокод):

class МойКласс(Библиотека):
  __подключаемфайл__ = 'файл'
  
  Переменная1:тип
  Переменная2:тип
  

Остановившись на этом, принялся к реализации проекта. Но через некоторое время понял, что также нужен экземпляр класса, ведь это улучшит работу с данными классами и реализация будет быстрее.

Готовый проект

После выполнения получилось следующее:

# .env file
String = Hello, world!
Integer = 23
Float = 45.0
Boolean = True
from envserv import EnvBase

class MyEnv(EnvBase):
    __envfile__ = '.env' # Путь к файлу
    
    String:str
    Integer:int
    Float:float
    Boolean:bool
    
env = MyEnv() # Создаём экземпляр класса
print(env)
print(env.String, env.Integer, env.Float, env.Boolean)
print(type(env.String), type(env.Integer), type(env.Float), type(env.Boolean))

# Вывод:
# EnvServ(String: = Hello, world!, Integer: = 23, Float: = 45.0, Boolean: = True)
# Hello, world! 23 45.0 True
#    

Восхитившись своим проектом, уже был готов его оставить, ведь не видел для него нововведения. Но, показав готовый проект, коллеги попросили внести в него некоторые изменения, для ещё более удобной работы — алиасы и изменения переменных.

Первоначально алиасы были нужны только для замены имён переменных, ведь в Python запрещено использовать ключевые слова для записи их как переменные (pass, def, async и т.п.). Но в дальнейшем осознал, что их можно использовать куда интереснее. Поэтому эта реализация была включена в проект.

Изменение переменных составило чуть больше проблем с их реализацией, но именно эта часть является чуть ли не самой интересной.
Чаще всего переменные окружения являются статичными данными, и лишь в некоторых случаях их есть смысл менять на другие значения. Но после реализации изменения начал задумываться, что ведь что-то вообще нельзя менять для работы всего проекта. И при ошибке в этом понимании, можно сломать тот же продакшн.
Поэтому одновременно к этой реализации был добавлен запрет на изменение переменной.

Результат дополнительных реализаций:

# .env file
user = test
pass = passtesting
from envserv import EnvBase, variable

class MyEnv(EnvBase):
    __envfile__ = '.env' # Путь к файлу
    
    user:str = variable(overwrite=False) # Здесь запрещаем изменять переменную
    password:str = variable(alias="pass") # Здесь указываем, что переменная окружения называется pass
    
env = MyEnv()
print(env) # Вывод: EnvServ(user: = test, password: = passtesting)
env.password = "newpass"
print(env.user, env.password) # Вывод: test newpass

env.user = 'newuser' # Исключение: envserv.errors.EnvVariableError: Error overwriting variable user: It cannot be overwritten

Итоги

Плюсы данной реализации:

  • Код легко читается

  • Тип переменной автоматически подставляется

  • Типом переменной может быть что угодно, включая пользовательский (Перевод осуществляется через: тип (значение))

  • Автоматическое подключение переменных (Если переменные не в файле, а к примеру в docker-compose, то переменную envfie указывать не надо)

  • Лёгкое присвоение новых значений

  • Назначение алиасов и запреты на изменения

Но как же без минусов:

  • Удалять переменные окружения в коде нельзя — будет нарушено целостность класса

  • Реализация последнего плюса через кэш (бета-версия)

Послесловие

Надеюсь данная библиотека будет помогать не только моим проектам, но и вашим.

Ссылка на библиотеку в PyPI: https://pypi.org/project/envserv/

Также оставляйте свои отзывы по данной статье и если вас она заинтересовала — можете предложить свои реализации, обязательно вместе их обдумаем :)

Всем приятной работы и поменьше багов!

© Habrahabr.ru