SecondThundeR / shikithon

Yet another Python wrapper for Shikimori API
https://pypi.org/project/shikithon/
MIT License
8 stars 0 forks source link

Add config stores, update authentification flow, remove obsolete code, etc. #11

Closed ren3104 closed 1 year ago

ren3104 commented 1 year ago

@SecondThundeR, решил не документировать классы и методы, пока не утвердим реализацию. Вообще хотел бы это оставить на тебя, потому что мой бедный английский, в связке с DeepL, с трудом справляется.

Примеры использования:

from shikithon import ShikimoriAPI, JsonStore

api = ShikimoriAPI(app_name="Api Test", store=JsonStore(), logging=False)

async def main():

    # Без авторизации
    async with api:
        ...

    # async with api.auth(...) нельзя вкладывать друг в друга

    # При авторизации app_name будет использовано из __init__
    # scopes можно не указывать, т.к оно будет получено при запросе токена
    # scopes разделяются пробелами
    async with api.auth(
        client_id="...",
        client_secret="...",
        auth_code="..."
    ):
        ...

    api_2 = ShikimoriAPI(app_name="Api Test", store=None, logging=False)
    # app_name в __init__ не будет перезаписан
    # Токен будет обновлен при ошибке 401
    api_auth_maker = api_2.auth(
        app_name="...",
        client_id="...",
        client_secret="...",
        access_token="...",
        refresh_token="..."
    )
    # Можно использовать сколько угодно раз
    async with api_auth_maker:
        ...

asyncio.run(main())

Можно еще добавить клиенту property для store и config. Не обновлять токен, если refresh_token == None и выводить ошибку 401. (Это не сделано)

ren3104 commented 1 year ago

Добавить property store для таких случаев:

api = ShikimoriAPI(app_name="Api Test", store=JsonStore(), logging=False)

# Будет работать и проблем возникнуть не должно
api.store = None
api.store = MemoryStore()

# Могут быть проблемы, потому что предыдущий store при
# async with был открыт, но не закрыт, т.к. мы изменили store
# находясь в контекстном менеджере
# (добавить в store property status, чтобы отследить этот момент?)
async with api.auth(...):
    ...
    # Будут ли ошибки, если мы так изменим store? (Думаю нет)
    api.store = JsonStore()
    ...

...

В property config можно делать валидацию конфига.

Еще вспомнил, что можно добавить property scopes.

Напишу FAQ по сторам чуть позже. Если ты согласен с добавлением этих property, то сделаю это.

SecondThundeR commented 1 year ago

В принципе можно попробовать добавить такие property, так как подобный юзкейс все же может в теории возникнуть

ren3104 commented 1 year ago

Думаю правильнее всего будет добавить property store и добавить опциональный параметр store для метода auth, если он назначен, то он будет использован при авторизации и обновлении токена, пока мы находимся в контекстном менеджере.

api = ShikimoriAPI(app_name="Api Test", logging=False)

print(api.store) # NullStore()

api.store = MemoryStore()

print(api.store) # MemoryStore()

async with api.auth(...):
    api.store = JsonStore()

    print(api.store) # JsonStore()

print(api.store) # JsonStore() !!!
api = ShikimoriAPI(app_name="Api Test", logging=False)

print(api.store) # NullStore()

api.store = MemoryStore()

print(api.store) # MemoryStore()

async with api.auth(..., store=JsonStore()):
    print(api.store) # JsonStore()

print(api.store) # MemoryStore()
SecondThundeR commented 1 year ago

Да, лучше сделать так, чтобы уже по надобности для контекста выбирать другое хранилище

ren3104 commented 1 year ago

Скорее всего сделаю перерыв на день.

Что имеем на текущий момент:

В memory хранилище изменить метод close на это:

async def close(self) -> None:
        self._configs.clear()
        return await super().close()
SecondThundeR commented 1 year ago

Добавил пока базовую документацию к хранилищам, новым методам в BaseClient, подправил документацию у некоторых текущих методов и переименовал JsonStore в JSONStore чтобы было все таки немного правильно с точки зрения того, что это аббревиатура.

Еще добавил пару исключений, чтобы не использовать базовый Exception и в хранилищах немного почистил код с помощью ранних выходов, чтобы слегка убрать вложенность в условиях

ren3104 commented 1 year ago

Сохранение конфигов для авторизации

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

api = ShikimoriAPI(store=JSONStore())


Все хранилища закрываются при выходе из контекстного менеджера `.auth()`! Напрмер `MemoryStore` будет очищен при закрытии, что может стать причиной ошибок в последующих авторизациях.
Это поведение можно отключить изменив при инициализации клиента параметр `auto_close_store` на `False`.

## Создание своего хранилища
Если вам не подходит ни одно из готовых хранилищ, то вы можете реализовать свое хранилище создав класс, который наследует абстрактный класс `Store` и переопределяет его методы.
```python
# Создаем класс своего хранилища и наследуем Store
class MyStore(Store):
    # Переопределяем методы класса Store
    ...
ren3104 commented 1 year ago

Думаю это все. Не стал добавлять возможность изменить store, т.к. с этим много проблем и не особо нужно

SecondThundeR commented 1 year ago

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

p.s. чет веб интерфейс херово резолвит конфликты, поэтому потом это починю

SecondThundeR commented 1 year ago

Спасибо еще раз за такой классный пулл реквест! Через пару часов отредачу ридми и уже сделаю релиз