Size: a a a

2020 October 19

DB

Dima Boger in PiterPy Meetup
Eugene
Кому-то ещё кроме меня кажется странным, что в pydantic.BaseSettings значения, переданные в конструктор, перекрывают значения, заданные через env? По (моей) логике должно быть наоборот: env имеет наивысший приоритет, ну или это должно быть хотя бы настраиваемо через Config, но нет, в коде захардкожен порядок обновления полей. И получается, что env-значения в низшем приоритете. Я не могу, скажем, построить конфигурацию, основанную на конфигурационных файлах+env, где env - имеет самый высокий приоритет, а конфиг-файлы менее высокий.

Типа пример кода:
class Settings(BaseSettings):
   ...

s = Settings(**load_from_config(config_path))


Сейчас в такой конструкции не cработают env-значения, они будут перекрыты тем, что я передал в конструктор.
```

🤷‍♂️
Хм, а у меня как раз другой юзкейс, у меня все из переменных окружения, а иногда я хочу параметром подхачить
источник

E

Eugene in PiterPy Meetup
Dima Boger
Хм, а у меня как раз другой юзкейс, у меня все из переменных окружения, а иногда я хочу параметром подхачить
Вот как мне кажется, такие вещи должны настраиваться. В текущих доках даже нет упоминания про переопределение метода для изменения этого поведения. Я им issue написал, скорее всего закроют, но интересно, что ответит автор библиотеки.
источник

FW

Foxy Woof in PiterPy Meetup
Очень странный кейс, как по мне, - передавать какие-то данные в конструктор, которые будут отброшены, при чем не очень понятно почему
источник

E

Eugene in PiterPy Meetup
Foxy Woof
Очень странный кейс, как по мне, - передавать какие-то данные в конструктор, которые будут отброшены, при чем не очень понятно почему
Почему? Чем "конструктор" отличается в этом случае от значений по умочланию, заданных в полях? А как ты по другому сделаешь перекрытие значений из конфиг файла переменными окружения? Переменные окружения в любом случае применяются неявно, а значения в конструктор задаются явно. Кто кого должен перекрывать - вопрос открытый.
источник

FW

Foxy Woof in PiterPy Meetup
Eugene
Почему? Чем "конструктор" отличается в этом случае от значений по умочланию, заданных в полях? А как ты по другому сделаешь перекрытие значений из конфиг файла переменными окружения? Переменные окружения в любом случае применяются неявно, а значения в конструктор задаются явно. Кто кого должен перекрывать - вопрос открытый.
В том то и дело, что явное должно перекрывать неявное)
источник

DB

Dima Boger in PiterPy Meetup
Foxy Woof
В том то и дело, что явное должно перекрывать неявное)
Ну переопределение поведения через переменные окружения распространенный кейс 🤷‍♂️

Не очень понимаю причём тут явное/неявное
источник

E

Eugene in PiterPy Meetup
Foxy Woof
В том то и дело, что явное должно перекрывать неявное)
То, что задано через конструктор (вообще в программировании, а не в конкретной библиотеке) зачастую можно переопределять через те же сеттеры. Это нормальная практика, когда дефолтные значения при конструировании перезаписываются впоследствии. А переменные окружения как раз часто используются для переопределения поведения в зависимости от окружения и инфраструктуры. И если у меня есть система конфигурации, в которой есть ещё и файлы конфигурации, то переменные окружения (если используются) всё же должны иметь приоритет над файлами конфигурации. По крайней мере с таким поведением я сталкиваюсь в своей практике.

С другой стороны, как говорил Дима, у него всё на переменных окружения, но иногда нужно что-то изменить через код. Вот с таким кейсом я в своей практике пока не сталкивался, но не отрицаю, что такое тоже не редкость. Поэтому и предлагаю конфигурируемость этого поведения.
источник

A🚀

Andrey 🚀🚀🚀 Popp... in PiterPy Meetup
Если default значение (явно заданное) переопределяется через окружение то ок, но если аргумент куда-то — как то опасно
источник

DB

Dima Boger in PiterPy Meetup
Eugene
То, что задано через конструктор (вообще в программировании, а не в конкретной библиотеке) зачастую можно переопределять через те же сеттеры. Это нормальная практика, когда дефолтные значения при конструировании перезаписываются впоследствии. А переменные окружения как раз часто используются для переопределения поведения в зависимости от окружения и инфраструктуры. И если у меня есть система конфигурации, в которой есть ещё и файлы конфигурации, то переменные окружения (если используются) всё же должны иметь приоритет над файлами конфигурации. По крайней мере с таким поведением я сталкиваюсь в своей практике.

С другой стороны, как говорил Дима, у него всё на переменных окружения, но иногда нужно что-то изменить через код. Вот с таким кейсом я в своей практике пока не сталкивался, но не отрицаю, что такое тоже не редкость. Поэтому и предлагаю конфигурируемость этого поведения.
🙏
источник

FW

Foxy Woof in PiterPy Meetup
Да, видимо я не сталкивался с такими кейсами)
Я тоже использую переменные окружения, но мне пока хватает одного уровня конфигов через dotenv и изменение конкретных параметров через cli-параметры
источник

Б

Боброний in PiterPy Meetup
Stan
Звучит как что-то очень узкое. Можно всегда самому сделать из gather, при желании
Ну вот да, слепил сегодня такую штуку. А почему узкое?
источник

E

Eugene in PiterPy Meetup
Какая же хрень эти ваши метаклассы в питоне 😒😂
from typing import NamedTuple
from typing_extensions import Protocol

class Record(Protocol):
   @staticmethod
   def parse(raw_record: str) -> 'Record':
       pass

class MyRecord(NamedTuple, Record):
   name: str
   score: float

   @staticmethod
   def parse(raw_record: str) -> 'MyRecord':
      ...

E   TypeError: metaclass conflict: the metaclass of a derived class must be a (non-strict) subclass of the metaclasses of all its bases

"Explicitly declaring implementation" говорили они. 😏
источник

Б

Боброний in PiterPy Meetup
Eugene
Какая же хрень эти ваши метаклассы в питоне 😒😂
from typing import NamedTuple
from typing_extensions import Protocol

class Record(Protocol):
   @staticmethod
   def parse(raw_record: str) -> 'Record':
       pass

class MyRecord(NamedTuple, Record):
   name: str
   score: float

   @staticmethod
   def parse(raw_record: str) -> 'MyRecord':
      ...

E   TypeError: metaclass conflict: the metaclass of a derived class must be a (non-strict) subclass of the metaclasses of all its bases

"Explicitly declaring implementation" говорили они. 😏
А от протокола нужно наследоваться 🤔?
источник

E

Eugene in PiterPy Meetup
Боброний
А от протокола нужно наследоваться 🤔?
не обязательно, но можно. в pep есть такие примеры в главе про explicity declaring
источник

DB

Dima Boger in PiterPy Meetup
Боброний
А от протокола нужно наследоваться 🤔?
Можно, чтобы делать свои типы-протоколы
источник

E

Eugene in PiterPy Meetup
со своими типами скорее всего проблем не будет, а вот с явным наследованием реализации то же самое что и с ABC. конфликт метаклассов легко получить.
источник

DB

Dima Boger in PiterPy Meetup
Так протокол же это тип, его нельзя инстанцировать. Или я что-то не понял про "наследование реализации"
источник

E

Eugene in PiterPy Meetup
Dima Boger
Так протокол же это тип, его нельзя инстанцировать. Или я что-то не понял про "наследование реализации"
так я и не истанцирую, тут он как миксин и определяет интерфейс. там же нет реализации
источник

E

Eugene in PiterPy Meetup
инстанцируется от NamedTuple
источник

E

Eugene in PiterPy Meetup
просто в питоне при множественном наследовании легко получить конфликт метаклассов. Интересно, Protocol из py38 тоже конфликтует с NamedTuple? Пока не проверял
источник