Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Передача context #8

Open
Debianov opened this issue Apr 24, 2023 · 8 comments
Open

Передача context #8

Debianov opened this issue Apr 24, 2023 · 8 comments
Assignees
Labels
help wanted Extra attention is needed

Comments

@Debianov
Copy link
Owner

Проблема.
Сейчас передача осуществляется через атрибут aconn.adapters.discord_context. Жизненно необходим, поскольку используется для преобразования id в объект. В дальнейшем также будет записываться в БД.

@Debianov Debianov added the help wanted Extra attention is needed label Apr 24, 2023
@idealism44
Copy link
Contributor

idealism44 commented Apr 25, 2023

Обязательно ли использование адаптеров Loader и Dumper?
В БД всё равно будут хранится только id целей: при загрузке отдаём id объектов, при выгрузке получаем id целей и при надобности образуем в Member или Channel.
И делать это не в адаптерах, а отдельными функциями до и после взаимодействия с БД. Чтобы этим не занимался psycopg.


Почитал документацию psycopg и я могу вынести предположение, как сделать это с помощью адаптеров:

В теме про конфигурации адаптации данных есть абзац:

By default, connections obtain an adapters map from the global map exposed as psycopg.adapters: changing the content of this object will affect every connection created afterwards. You may specify a different template adapters map using the context parameter on connect().

Говорят, мол, по умолчанию каждое соединение к БД берёт адаптеры из глобальной карты адаптеров в psycopg.adapters. Если хочется добавить свои глобально, то добавляйте адаптеры в psycopg.adapters: при каждом соединении будут ваши адаптеры. Если хотите адаптеры, зависящие от контекста, указывайте context при получении соединения БД connect().
Тип context при получении соединения это psycopg.adapt.AdaptersMap, который хранит в себе адаптеры для соединения. Именно его вы используете, чтобы добавить свои адаптеры.

Получается, при новом соединении к БД можно указать в качестве context эту карту адаптеров, которую мы создадим перед указанием context, и в неё будут добавлены адаптеры, преобразующие данные в зависимости от контекста. Но как сделать сами адаптеры преобразовывающими от контекста?
register_dumper() и register_loader() принимают только классы соответсвующих адаптеров: не получится сделать объект адаптера. И в этом адаптере должен быть ctx от бота, чтобы обрабатывать данные в зависимости от контекста.

Далее, моё предположение реализации:

Для динамического создания классов в Python есть функция type(). Её и буду использовать.
При вызове нового соединения в качестве context будем указывать вызов функции, который вернёт psycopg.adapt.AdaptersMap, в котором будут наши контекстные адаптеры. Для создания контекстных адаптеров буду преобразовывать текущие DiscordObjectsDumper и DiscordObjectsLoader в новый класс со своим атрибутом ctx.
В итоге получится что-то вроде такого:

class DiscordObjectsLoader:
    ctx = None

    def load(self, to_load):
        print("With context:", self.ctx)
        print("Loading:", to_load)


class DiscordObjectsDumper:
    ctx = None

    def dump(self, to_dump):
        print("With context:", self.ctx)
        print("Dumping:", to_dump)


def context_factory(ctx):
    return (
        type(
             'CtxDiscordObjectsLoader',
             (DiscordObjectsLoader,),
             {'ctx': ctx}
        ),
        type(
             'CtxDiscordObjectsDumper',
             (DiscordObjectsDumper,),
             {'ctx': ctx}
        )
    )


def context_adapters(ctx):
    adapters = []
    Loader, Dumper = context_factory(ctx)
    adapters.append(Loader)
    adapters.append(Dumper)
    return adapters
    

ctx = "my_ctx"

# with psycopg.connect(connection_string=..., context=context_adapters(ctx)):
# Load something
# Dump sometning
# hided
adapters = context_adapters(ctx)
Loader, Dumper = adapters
a = Loader()
a.load("foo")
b = Dumper()
b.dump("bar")
# hided

В зависимости от ctx будем получать разные сообщения:

With context: my_ctx
Loading: foo
With context: my_ctx
Dumping: bar

Так как вы используете только одно соединение, то можно адаптировать вариант под cursor: после создания курсора добавить в него адаптеры, так как он тоже поддерживает psycopg.adapt.AdaptersMap (почему).

Возможно я что-то упустил в документации, но мне больше нечего сказать.

@Debianov Debianov self-assigned this Apr 27, 2023
@Debianov Debianov pinned this issue Jun 9, 2023
@Debianov
Copy link
Owner Author

Довольно накладно выходит делать на каждый ctx по своему объекту. К сожалению, передать второй аргумент никак нельзя, передавать как-то кортежем через data вместе с основными данными к преобразованию не является нормой, поэтому решено убрать эти два класса из регистрации и вызывать их методы вручную.

@Debianov Debianov added this to the Первый релиз milestone Jun 14, 2023
@Debianov Debianov reopened this Jun 14, 2023
@Debianov
Copy link
Owner Author

Убирать два этих класса тоже не вариант. Они нужны, иначе придётся прописывать обработку вручную во многих местах кода.

@Debianov
Copy link
Owner Author

Реализовано через Locator. commit

@idealism44
Copy link
Contributor

То что вы реализовали - это глобальная переменная, ссылку на которую вы дали в классе адаптера Loader.
Так как бот асинхронный, то в момент выгрузки данных с ctx первого соединения может вмешаться второе, которое вставит своё ctx в Provider, и первое соединение теперь будет пользоваться ctx от второго соединения, что может послужить многим проблемам.

Убирать два этих класса тоже не вариант. Они нужны, иначе придётся прописывать обработку вручную во многих местах кода.

Можете рассказать, как вы взаимодействуете с полученными id объектов из БД? Зачем их превращать в Discord объекты?
Я не понимаю всей ситуации и предлагаю решения основываясь только на тексте из этого issue, из-за чего решения могут не подойти к настоящей обстановке.

@Debianov
Copy link
Owner Author

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

Да, я собираюсь делать словарь с извлечением контекста по объекту сообщения.

Можете рассказать, как вы взаимодействуете с полученными id объектов из БД? Зачем их превращать в Discord объекты?

Ну хотя бы взять извлечение объектов из БД по схожим критериям для поиска совпадений.

@Debianov Debianov reopened this Jun 16, 2023
@idealism44
Copy link
Contributor

idealism44 commented Jun 16, 2023

Да, я собираюсь делать словарь с извлечением контекста по объекту сообщения.

Тогда можете, пожалуйста, это сделать? Или как-то покажите, что данная проблема ещё не решена, например оставить этот issue открытым. Ведь если всё так и оставить будут соответствующие проблемы.

Ну хотя бы взять извлечение объектов из БД по схожим критериям для поиска совпадений.

Классно придумано.

@Debianov
Copy link
Owner Author

оставить этот issue открытым

Понял

@Debianov Debianov removed this from the Первый релиз milestone Aug 18, 2023
@Debianov Debianov added this to the 2.0.0 milestone Oct 29, 2023
@Debianov Debianov removed this from the 2.0.0 milestone Jul 12, 2024
@Debianov Debianov unpinned this issue Jul 12, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
help wanted Extra attention is needed
Projects
Status: Backlog
Development

No branches or pull requests

2 participants