Observed since 20 Oct, 15:26 UTC
No superseded metadata states collected. Unchanged observations do not create new revisions.
UI integration package

> pip install 2m
Переходим в рабочий каталог своего приложения:
> cd ../path_to_your_ui
Устанавливаем зависимые пакеты, сверяем соответствие, развёртываем пакет с модулями:
> python -c "from two_m_root.install import install;exec(install.main())"

Теперь в вашем текущем покете появился пакет two_m, содержащий несколько модулей, которые необходимо настроить.
Обращаю ваше внимание на официальную документацию Flask-SQLAlchemy https://flask-sqlalchemy.readthedocs.io/en/stable/legacy-quickstart/#define-models
Если нужно работать с хранимыми процедурами, декларируем их в виде экземпляров класса DDL.
Документация SqlAlchemy относительно объектов DDL https://docs.sqlalchemy.org/en/20/core/ddl.html#custom-ddl

После написания таблиц в models и хранимых процедур в procedures, нужно инициализировать их в базу даных.
> python -c "from two_m.models import create_db;create_db()"
> python -c "from two_m.procedures import init_procedures;init_procedures()"
from two_m_root.core import Tool
from two_m.models import SomeModel
...
...
...
class Something:
def __init__():
self.tool = Tool()
self.tool.set_model(SomeModel)
def ui_action_a():
self.tool.set_item(...)
def ui_action_b():
self.tool.set_item(...)
def ui_action_b():
items = self.tool.get_items(...)
...
Рассмотрим функционал, который является основной компетенций данного фреймворка
orm.set_item(_model=None, _ready=False, _insert=False, _update=False, _delete=False, _where=None, **values)Установить в очередь запись-кандидата, которая появится в базе данных при первой возможности
Пример: пользовательская функция-валидатор даёт ответ, готова ли данная запись на транзакцию во "внешний мир":

orm.get_items(_model=None, _db_only=False, _queue_only=False, **where)orm.join_select(*models, _db_only=False, _queue_only=False, _on=None, **where)Несколько слов о принципе работы внутренних механизмов, которые объединяют воедино записи из удалённого расположения (базы данных), и записи из локального хранилища. Рассмотрим 1 строку из таблицы А и 1 строку из таблицы B, чтобы понять, как будет происходить слияние.



Объекты результата, производные от класса BaseResult, возвращаемые методами orm.get_items и orm.join_select соответственно, являются ЛЕНИВЫМИ объектами, то есть не содержат никакого результата явным образом, но хранят в себе все детали запроса. При каждом взаимодействии с итератором, contains, getitem, bool, len и даже str, происходит новый запрос.
: - Что это, зачем, - зачем усложнять? Ведь можно написать запрос и получить ответ: здесь и сейчас :question:
Во-первых, я нахожу весьма удобным не писать отдельных пользовательских функций для мемоизации параметров запроса,
чтобы потом возвращаться к этому снова и снова, заполняя своё приложение потенциально лишним кодом.
Во-вторых, "под капотом" скрывается достаточно хитрая система, которая, если описать это просто, делает следующее:
В-третьих, эти ленивые экземпляры дают большое количество синтаксического сахара, который, по заветам pythonicway,
избавит ваш интерфейс от каждой лишней строчки!
Просто обратимся к экземпляру, чтобы узнать, есть ли изменения в данных:
Если значение хеш-суммы никогда не фигурировало в рамках текущего экземпляра результата, вернёт - None.
Также, можно с лёгкостью узнать, появились ли новые (или стали недоступны те, что получены) записи:

Объект запроса к 1 таблице.
Объект запроса к нескольким таблицам. В рамках результирующего списка каждый ResultORMCollection представляет внутри себя связку PK-FK.
Ассоциируйте строку, представляющую данные, со ссылкой на получение этих данных. Работает как для запросов к 1 таблице, так и для запросов к нескольким таблицам одновременно.
Экземпляр Pointer инкапсулируется в экземпляр результата и предназначен для чтения только по свойству, - не следует пытаться сделать на него ещё одну ссылку :rage:
any_result.pointer = ["список", "совпадающий", "по", "длине", "с", "содержимым"]
Каждый элемент этого списка будет ассоциирован с содержимым внутри результата 1 к 1.
any_result.pointer["содержимым"] - получить [-1] элементany_result.pointer["список"] - получить [0] элементany_result.pointer["совпадающий"] - получить [1] элемент
"длине" in any_result.pointer # True"strstr" in any_result.pointer # False"с" in any_result.pointer # True"совпадающий" in any_result.pointer # True
any_result.pointer.has_changes(name: str) -> Optional[bool] - Передаём сюда полную хеш сумму и получаем ответ на вопрос: есть ли какие-нибудь изменения (с момента последнего вопрошания или инициализации).any_result.pointer.is_valid() -> bool. Узнать о текущем состоянии текущего экземпляра Pointer: закрылся он или нет.
any_result.pointer.wrap_items -> list. Исходный список строк. Если данный Pointer закрыт, список будет пустым.any_result.pointer.items -> Полный словарь содержимого в виде: {"одна_из_строк_wrap": контейнер_с_содержимым}any_result.pointer.replace_wrap(item: str, old_wrapper: Optional[str] = None, hash_: Optional[int] = None, primary_key_hash: Optional[int] = None, index: Optional[int] = None) -> None. Заменить строку указатель на новую.И всё было бы хорошо, но как только из базы данных придёт результат количественно другой, или, с записями, которые содержат другие первичные ключи; Если то же самое произойдет и со стороны локальных элементов,- объект сразу же откажется сотрудничать с вами. Всеми своими методами он будет отвечать - None. Всё что можно сделать в этой ситуации - создать новый :)
Контейнеры с данными, возвращаемый объектом результата - Result или JoinSelectResult. Иммутабелен.
Призываю не использовать метод all_nodes, он нужен для служебного пользования :rage:
{столбец: значение}{столбец: значение}. Или что-то одноимя_столбца:значениеvalue = node["table_column"]Postgresql в качестве базы данных

Pointer
Добавлен метод replace_wrap. wrap_items теперь список, а не кортеж. Более мягкое поведение относительно возбуждения WrapperLengthException, если данных нет. pymemcache.RetryingClient вместо pymemcache.Client в свойстве Tool.cache.
Отказ от идеи наследования класса Tool в пользовательский пакет two_m, модуль main. Напротив, из two_m.main теперь импортируются константы в two_m_root.core.
Result.order_by(...), JoinSelectResult.order_by(...)
Result и JoinSelectResult получили метод order_by от миксина OrderByMixin Сортировка возможна по длине строк, времени добавления, или в алфавитном порядке. По любому столбцу в таблице или просто по первичному ключу.
Пример использования:
lazy_result = my_tool_instance.get_items(table_name, ...)
lazy_result.order_by(...)
Экземплярам класса Result и JoinSelectResult добавлены методы:
BaseResult получил константу ITER_ONLY_VISIBLE_ITEMS_AS_DEFAULT, определяющую поведение относительно скрытых нод. Обратим внимание, что это, в свою очередь, затрагивает работу Pointer.
ConnectionManager
Все соединения с внешними сервисами вынесены в отдельный класс. Открытые подключения закрываются по таймерам, не засоряя пул. Можно настроить срок жизни подключения.
pypistats · 50 observations shown. Missing days are unknown. Source category: overall: without mirrors.
| Date / source period | Value | Observed at |
|---|---|---|
| 2026-10-16 – 2026-10-16 | 1 | 2026-10-20T16:21:42.6225585Z |
| 2026-10-15 – 2026-10-15 | 1 | 2026-10-20T16:21:42.6225585Z |
| 2026-10-13 – 2026-10-13 | 1 | 2026-10-20T16:21:42.6225585Z |
| 2026-10-11 – 2026-10-11 | 2 | 2026-10-20T16:21:42.6225585Z |
| 2026-10-10 – 2026-10-10 | 1 | 2026-10-20T16:21:42.6225585Z |
| 2026-10-09 – 2026-10-09 | 1 | 2026-10-20T16:21:42.6225585Z |
| 2026-10-07 – 2026-10-07 | 1 | 2026-10-20T16:21:42.6225585Z |
| 2026-10-06 – 2026-10-06 | 2 | 2026-10-20T16:21:42.6225585Z |
| 2026-09-30 – 2026-09-30 | 3 | 2026-10-20T16:21:42.6225585Z |
| 2026-09-26 – 2026-09-26 | 1 | 2026-10-20T16:21:42.6225585Z |
| 2026-09-24 – 2026-09-24 | 2 | 2026-10-20T16:21:42.6225585Z |
| 2026-09-20 – 2026-09-20 | 1 | 2026-10-20T16:21:42.6225585Z |
| 2026-09-18 – 2026-09-18 | 1 | 2026-10-20T16:21:42.6225585Z |
| 2026-09-16 – 2026-09-16 | 1 | 2026-10-20T16:21:42.6225585Z |
| 2026-09-12 – 2026-09-12 | 2 | 2026-10-20T16:21:42.6225585Z |
| 2026-09-10 – 2026-09-10 | 2 | 2026-10-20T16:21:42.6225585Z |
| 2026-09-09 – 2026-09-09 | 2 | 2026-10-20T16:21:42.6225585Z |
| 2026-09-07 – 2026-09-07 | 2 | 2026-10-20T16:21:42.6225585Z |
| 2026-09-05 – 2026-09-05 | 1 | 2026-10-20T16:21:42.6225585Z |
| 2026-09-03 – 2026-09-03 | 2 | 2026-10-20T16:21:42.6225585Z |
| 2026-09-01 – 2026-09-01 | 1 | 2026-10-20T16:21:42.6225585Z |
| 2026-08-31 – 2026-08-31 | 3 | 2026-10-20T16:21:42.6225585Z |
| 2026-08-28 – 2026-08-28 | 1 | 2026-10-20T16:21:42.6225585Z |
| 2026-08-24 – 2026-08-24 | 9 | 2026-10-20T16:21:42.6225585Z |
| 2026-08-23 – 2026-08-23 | 4 | 2026-10-20T16:21:42.6225585Z |
| 2026-08-22 – 2026-08-22 | 1 | 2026-10-20T16:21:42.6225585Z |
| 2026-08-20 – 2026-08-20 | 1 | 2026-10-20T16:21:42.6225585Z |
| 2026-08-19 – 2026-08-19 | 1 | 2026-10-20T16:21:42.6225585Z |
| 2026-08-18 – 2026-08-18 | 10 | 2026-10-20T16:21:42.6225585Z |
| 2026-08-17 – 2026-08-17 | 3 | 2026-10-20T16:21:42.6225585Z |
| 2026-08-16 – 2026-08-16 | 1 | 2026-10-20T16:21:42.6225585Z |
| 2026-08-15 – 2026-08-15 | 1 | 2026-10-20T16:21:42.6225585Z |
| 2026-08-14 – 2026-08-14 | 3 | 2026-10-20T16:21:42.6225585Z |
| 2026-08-13 – 2026-08-13 | 3 | 2026-10-20T16:21:42.6225585Z |
| 2026-08-11 – 2026-08-11 | 1 | 2026-10-20T16:21:42.6225585Z |
| 2026-08-06 – 2026-08-06 | 1 | 2026-10-20T16:21:42.6225585Z |
| 2026-08-04 – 2026-08-04 | 4 | 2026-10-20T16:21:42.6225585Z |
| 2026-08-03 – 2026-08-03 | 3 | 2026-10-20T16:21:42.6225585Z |
| 2026-08-02 – 2026-08-02 | 1 | 2026-10-20T16:21:42.6225585Z |
| 2026-08-01 – 2026-08-01 | 2 | 2026-10-20T16:21:42.6225585Z |
| 2026-07-30 – 2026-07-30 | 2 | 2026-10-20T16:21:42.6225585Z |
| 2026-07-29 – 2026-07-29 | 11 | 2026-10-20T16:21:42.6225585Z |
| 2026-07-28 – 2026-07-28 | 1 | 2026-10-20T16:21:42.6225585Z |
| 2026-07-27 – 2026-07-27 | 2 | 2026-10-20T16:21:42.6225585Z |
| 2026-07-25 – 2026-07-25 | 1 | 2026-10-20T16:21:42.6225585Z |
| 2026-07-24 – 2026-07-24 | 1 | 2026-10-20T16:21:42.6225585Z |
| 2026-07-23 – 2026-07-23 | 1 | 2026-10-20T16:21:42.6225585Z |
| 2026-07-22 – 2026-07-22 | 3 | 2026-10-20T16:21:42.6225585Z |
| 2026-07-21 – 2026-07-21 | 2 | 2026-10-20T16:21:42.6225585Z |
| 2026-07-20 – 2026-07-20 | 4 | 2026-10-20T16:21:42.6225585Z |
| Version | Published | Direct dependencies | Open version |
|---|---|---|---|
| 1.2.5 | 3 Jun 2026 | 9 |
This describes our collected data; it is not a security assessment.
Observed since 20 Oct, 15:26 UTC
No superseded metadata states collected. Unchanged observations do not create new revisions.
package:13b57d0ed6cd9b608791c17af47092c07754997335bae44326b7a8a996f2bbef