Size: a a a

2020 October 18

DB

Dima Boger in PiterPy Meetup
Eugene
в самом pytest есть опция --pdb, запускает интерактивный отладчик, если тест завершается фейлом или происходит исключение.
Я попытался вникнуть в его исходники, но чёт очень сложно. Раскуриваю _pytest.capture, именно он отвечает за перенаправление стдина: In addition, stdin is set to a “null” object which will fail on attempts to read from it because it is rarely desired to wait for interactive input when running automated tests.
источник

DB

Dima Boger in PiterPy Meetup
Окей, я нашёл как на время выключить capture 🎉:
cm: CaptureManager = self.request.config.pluginmanager.getplugin("capturemanager")
cm.stop_global_capturing()
interactive_input = input('hey?')
cm.start_global_capturing()
источник

A

Anatoly in PiterPy Meetup
Dima Boger
Окей, я нашёл как на время выключить capture 🎉:
cm: CaptureManager = self.request.config.pluginmanager.getplugin("capturemanager")
cm.stop_global_capturing()
interactive_input = input('hey?')
cm.start_global_capturing()
А можно поинтересоваться, когда нужен инпут в тестах? Для себя, на будущее🙄
источник

DB

Dima Boger in PiterPy Meetup
А мне не для тестов, мне для плагина к тестам.

Есть такая классная штука как снепшот-тестирование — в тестах вместо assert value == expected пишешь assert value == snapshot(), и при первом запуске оно запомнит значение value как эталонное, а при следующих будет сравнивать. Поменяется — упадёт. В питоне есть парочка библиотек-плагинов, которые прикручиваются и позволяют делать такое, но нет ни одной интерактивной, чтобы per-test смотреть диффы разошедшихся снепшотов и валидировать их.

Хороший пример, как это выглядит в jest: https://jestjs.io/docs/ru/snapshot-testing#interactive-snapshot-mode
источник

DB

Dima Boger in PiterPy Meetup
А pytest вообще не предполагает никакого интерактивного мода, CLI в нём работает только на output :(

Поэтому задача нетривиальная, если писать наружу это ещё ладно, то вот спрашивать что-то у разработчика удобно не получится. Колдую, может чего получится 🤷‍♂️
источник

A

Anatoly in PiterPy Meetup
Dima Boger
А мне не для тестов, мне для плагина к тестам.

Есть такая классная штука как снепшот-тестирование — в тестах вместо assert value == expected пишешь assert value == snapshot(), и при первом запуске оно запомнит значение value как эталонное, а при следующих будет сравнивать. Поменяется — упадёт. В питоне есть парочка библиотек-плагинов, которые прикручиваются и позволяют делать такое, но нет ни одной интерактивной, чтобы per-test смотреть диффы разошедшихся снепшотов и валидировать их.

Хороший пример, как это выглядит в jest: https://jestjs.io/docs/ru/snapshot-testing#interactive-snapshot-mode
интересно, спасибо)
источник

E

Eugene in PiterPy Meetup
Dima Boger
А мне не для тестов, мне для плагина к тестам.

Есть такая классная штука как снепшот-тестирование — в тестах вместо assert value == expected пишешь assert value == snapshot(), и при первом запуске оно запомнит значение value как эталонное, а при следующих будет сравнивать. Поменяется — упадёт. В питоне есть парочка библиотек-плагинов, которые прикручиваются и позволяют делать такое, но нет ни одной интерактивной, чтобы per-test смотреть диффы разошедшихся снепшотов и валидировать их.

Хороший пример, как это выглядит в jest: https://jestjs.io/docs/ru/snapshot-testing#interactive-snapshot-mode
Что-то похожее я использую, когда надо тестировать алгоритмы, где на выходе картинки. Есть удобный плагин для mpl

https://github.com/matplotlib/pytest-mpl
источник

DB

Dima Boger in PiterPy Meetup
Мне вот хочется написать generic-штуку, чтобы туда можно было разные типы данных подключать и дописывать их по надобности

Но одно дело хочется, а другое дело написать 😅
источник

V

Vera in PiterPy Meetup
Dima Boger
Мне вот хочется написать generic-штуку, чтобы туда можно было разные типы данных подключать и дописывать их по надобности

Но одно дело хочется, а другое дело написать 😅
источник

PR

Paul Rudnitskiy in PiterPy Meetup
о да
источник

N

Nikolai in PiterPy Meetup
+
источник

p

pragus in PiterPy Meetup
В голос ))
источник

E

Eugene in PiterPy Meetup
Кому-то ещё кроме меня кажется странным, что в 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
во, не я один такой!
https://github.com/samuelcolvin/pydantic/issues/340
источник

E

Eugene in PiterPy Meetup
в общем, автор предлагает менять это поведение самостоятельно
https://github.com/samuelcolvin/pydantic/pull/343

This behaviour can be changed by overriding the ``_build_values`` method on ``BaseSettings``.
источник
2020 October 19

p

pragus in PiterPy Meetup
источник

AO

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

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

s = Settings(**load_from_config(config_path))


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

🤷‍♂️
Там и Strict Types не по умолчанию, библиотеку какой-то JS-формошлёпер писал
источник

AO

Alexander Ovchinniko... in PiterPy Meetup
Alexander Ovchinnikov 🦁
Там и Strict Types не по умолчанию, библиотеку какой-то JS-формошлёпер писал
Причём раньше про это в документации не писали и когда я про такое поведение по умолчанию узнал, у меня очень «пригорело», как будто обманули
источник

Б

Боброний in PiterPy Meetup
Неужели нет какой-то либы которая имплементрует gather_results или что-то похожее?

То есть собирает из структуры данных футуры или специальные объекты, асинхронно получает их резултаты и возвращает структуру данных с результатами

Есть какие-то причины так не делать?

async def get_list(*items):
   return [*items]


async def get_dict(*keys):
   return dict.fromkeys(keys, ...)


async def main():
   return await gather_results(
       {
           'combined_dicts': {
               **result_of(get_dict('a', 'b')),
               **result_of(get_dict('c', 'd')),
           },
           'combined_lists': [
               *result_of(get_list(1, 2)),
               *result_of(get_list(3, 4)),
           ]
       }
   )


>>> asyncio.run(main())

{
   'combined_dicts': {
       'a': ...,
       'b': ...,
       'c': ...,
       'd': ...,
   },
   'combined_lists': [
       1, 2, 3, 4
   ]
}
источник

S

Stan in PiterPy Meetup
Боброний
Неужели нет какой-то либы которая имплементрует gather_results или что-то похожее?

То есть собирает из структуры данных футуры или специальные объекты, асинхронно получает их резултаты и возвращает структуру данных с результатами

Есть какие-то причины так не делать?

async def get_list(*items):
   return [*items]


async def get_dict(*keys):
   return dict.fromkeys(keys, ...)


async def main():
   return await gather_results(
       {
           'combined_dicts': {
               **result_of(get_dict('a', 'b')),
               **result_of(get_dict('c', 'd')),
           },
           'combined_lists': [
               *result_of(get_list(1, 2)),
               *result_of(get_list(3, 4)),
           ]
       }
   )


>>> asyncio.run(main())

{
   'combined_dicts': {
       'a': ...,
       'b': ...,
       'c': ...,
       'd': ...,
   },
   'combined_lists': [
       1, 2, 3, 4
   ]
}
Звучит как что-то очень узкое. Можно всегда самому сделать из gather, при желании
источник