# -*- coding: utf-8 -*-
from setuptools import setup

packages = \
['garnet',
 'garnet.callbacks',
 'garnet.events',
 'garnet.filters',
 'garnet.functions',
 'garnet.helpers',
 'garnet.router',
 'garnet.storages']

package_data = \
{'': ['*']}

install_requires = \
['Telethon>=1.10.8,<2.0']

setup_kwargs = {
    'name': 'telegram-garnet',
    'version': '0.2.2',
    'description': 'Garnet - cool add-on for Telethon',
    'long_description': '🍷 Garnet\n===================================\n\nGarnet — bot-friendly telethon\n-----------------------------------\n\n.. invisible-content-till-nel\n.. _aioredis: https://github.com/aio-libs/aioredis\n.. _cryptg: https://pypi.org/project/cryptg/\n.. _telethon: https://pypi.org/project/Telethon/\n.. _orjson: https://pypi.org/project/orjson/\n.. _ujson: https://pypi.org/project/ujson/\n.. _hachoir: https://pypi.org/project/hachoir/\n.. _aiohttp: https://pypi.org/project/aiohttp/\n.. _Alex: https://github.com/JrooTJunior\n\n.. image:: https://raw.githubusercontent.com/uwinx/garnet/master/static/pomegranate.jpg\n\n.. image:: https://img.shields.io/badge/code%20style-black-000000.svg\n    :target: https://github.com/python/black\n    :alt: aioqiwi-code-style\n\n\nInstall::\n\n    pip install telegram-garnet\n\n\n**Dependencies:**\n    - ``telethon`` - main dependency telethon_\n**Extras:**\n    - ``aioredis`` - redis driver if you use RedisStorage* aioredis_\n    - ``orjson`` || ``ujson`` - RedisStorage/JSONStorage de-&& serialization orjson_ ujson_\n    - ``cryptg``, ``hachoir``, ``aiohttp`` - boost telethon itself cryptg_ hachoir_ aiohttp_\n\n---------------------------------\n🌚 🌝 FSM-Storage types\n---------------------------------\n\n- File - json storage, the main idea behind JSON storage is a custom reload of file and usage of memory session for writing, so the data in json storage not always actual\n\n- Memory - powerful in-memory map<str> based storage, only thing - not persistent\n\n- Redis - (requires aioredis_) - redis is fast key-value storage, if you\'re using your data is durable and persistent\n\n\nPomegranate implements updates dispatching and checks callback\'s filters wrapping all callbacks into ``garnet::Callback`` object\n\n----------------\n😋 Filters\n----------------\n\n``Filter`` object is the essential part of Pomegranate, the do state checking and other stuff.\n\nBasically, it\'s ``func`` from ``MyEventBuilder(func=lambda self: <bool>)`` but a way more complicated and not stored in EventBuilder, it\'s stored in callback object\n\n\nUseful filters\n\n1) 📨 **Messages**\n\n\n`Following examples will include pattern`\n\n\n.. code:: python\n\n    from garnet import MessageText, TelegramClient\n    bot = TelegramClient.from_env().start_as_bot()\n\n    # // our code here //\n\n    bot.run_until_disconnected()\n\n.. code:: python\n\n    # handling /start and /help\n    @bot.on(MessageText.commands("help", "start"))\n    async def cmd_handler(message: custom.Message):\n        await message.reply("Hey there!")\n\n    # handling exact words\n    my_secret = "abcxyz"\n    @bot.on(MessageText.exact(my_secret))\n    async def secret_handler(message: custom.Message):\n        await message.reply("Secret entered correctly! Welcome!")\n\nMessageText or text(``from garnet import text``) includes following comparisons all returning <bool>\n - ``.exact(x)`` -> ``event.raw_text == x``\n - ``.commands(*x)`` -> ``event.raw_text.split()[0][1:] in x``\n - ``.match(x)`` -> ``re.compile(x).match(event.raw_text)``\n - ``.between(*x)`` -> ``event.raw_text in x``\n - ``.isdigit()`` -> ``(event.raw_text or "").isdigit()``\n - ``.startswith(x)`` -> ``event.raw_text.startswith(x)``\n\n\n\n2) 👀 **CurrentState class**  [``from garnet import CurrentState``]\n\nOnce great minds decided that state checking will be in filters without adding ``state`` as handler decorator parameter and further storing state in ``callback.(arg)``\n``CurrentState`` class methods return ``Filter``. There are two problems that Filter object really solves, ``Filter``\'s function can be any kind of callable(async,sync), filters also have a flag ``requires_context``, FSMProxy is passed if true\n\nSee `FSM example <https://github.com/uwinx/garnet/blob/master/examples/fsm.py>`_ to understand how CurrentState works\n\nIncludes following methods all returning <bool>\n - ``.exact(x)`` or ``CurrentState == x`` -> ``await context.get_state() == x``\n - ``CurrentState == [x, y, z]`` -> ``await context.get_state() in [x, y, z]``\n - ``CurrentState == all`` or ``CurrentState == any`` -> ``await context.get_state() is not None``\n\n\n3) 🦔 Custom **Filter**\n\nIf you want to write your own filter, do it.\n\n\n.. code:: python\n\n    from garnet import Filter, FSMProxy\n\n    async def myFunc(event): ...\n    async def myFuncContextRequires(event, context: FSMProxy): ...\n    def normal_func(event): ...\n\n    @bot.on(Filter(normal_func), Filter(myFunc), Filter(myFuncContextRequires, requires_context=True))\n    async def handler(event, context: FSMProxy): ...\n    # same as\n    @bot.on(normal_func, myFunc, Filter(myFuncContextRequires, requires_context=True))\n    async def handler(event): ...\n\nSo the handler can take strict ``context`` argument and also ignore it\n\n-----------------------\nOn start|finish\n-----------------------\n\n``garnet::TelegramClient`` contains three lists on_start on_background and on_finish, their instance is ``PseudoFrozenList`` which freezes at calling ``.run_until_disconnected``\n``PseudoFrozenList`` has three main methods::\n\n    .append(*items)\n    .remove(*items)\n    .freeze()\n    .__call__(func)   # for shiny decorator\n\n``items`` in case of TelegramClient means unpacked container of async-defined functions taking on position arguments\n\nUsage example:\n\n.. code-block:: python\n\n    # my_module.py\n    class MyPostgresDatabase:\n        ...\n        async def close_pool(self, bot): await self.pool.safe_close()\n        async def open_pool(self, bot): await self.pool.open_conn_pool()\n\n    # garnethon.py\n    from garnet import TelegramClient\n    from my_module import MyPostgresDatabase\n\n    db = MyPostgresDatabase()\n    bot = TelegramClient.from_env().start_as_bot()\n    bot.on_start.append(db.open_pool)\n    bot.on_finish.append(db.close_pool)\n    ...\n\n    @bot.on_background\n    async def xyz(cl: TelegramClient):\n        while True:\n           ...\n\n    bot.run_until_connected()\n\n\n-------------------------------------------------\n📦 Router and Migrating to garnet using Router\n-------------------------------------------------\n\nThink of router as just a dummy container of handlers(callbacks)\n\n`garnet::router::Router` may be helpful if you have telethon\'s `event.register` registered handlers. One thing: Router, I believe, is correct and more obvious way of registering event handlers. Example:\n\n**Migrate from telethon to garnet, also use for bot.on cases(soon better example)**\n\n.. code-block:: python\n\n    # my_handlers.py\n\n    # telethon register(bad) will raise Warning in garnet\n    from telethon import events\n\n    @events.register(event_type)\n    async def handler(event): ...\n\n    # garnet\'s telethon-like router\n    from garnet.router import TelethonRouter\n\n    router = TelethonRouter()\n\n    @router(event_type)\n    async def handler(event): ...\n\n\n\nThe advantage of routers is evidence of registering handlers when you have module-separated handlers. `events.register` was doing well, but blindly importing modules to register handlers and don\'t use them(modules) doesn\'t seem like a good idea.\n\n\nExample of registering router in bot application\n\n\n.. code-block:: python\n\n    # handlers/messages.py\n    from garnet.router import Router\n\n    router = Router()\n\n    @router()\n    async def handler(event): ...\n\n    # handlers/cb_query.py\n    from garnet.events import CallbackQuery\n    from garnet.router import Router\n\n    router = Router()\n\n    @router(event=CallbackQuery())\n    async def handler(event): ...\n\n    # entry.py ()\n    from garnet import TelegramClient\n\n    from handlers import messages, cb_query\n\n    tg = TelegramClient.from_env().start_as_bot()\n    tg.bind_routers(messages, cb_query)\n    ...\n\n`TelethonRouter` and `Router` both have following remarkable methods:\n\n::\n\n    .message_handler(*filters)\n    .callback_query_handler(*filters)\n    .chat_action_handler(*filters)\n    .message_edited_handler(*filters)\n    .album_handler(*filters)\n\n--------------------\n🍬 Context magic\n--------------------\n\nOne of the sweetest parts of garnet. Using `contextvars` we reach incredibly beautiful code :D\n*this is not FSMContext don\'t confuse with context magic provided by contextvars*\n\nAs an example, bot that doesn\'t requires `TelegramClient` to answer messages directly.\n\n.. code-block:: python\n\n    from garnet.functions.messages import reply, message, respond\n\n    @bot.message_handler()\n    async def handler():\n        # message() - function to get current Message event\n        await message().respond("ok")\n        await message().reply("ok")\n        # the same result, but shortcuts\n        await respond("ok")\n        await reply("Ok")\n\n\n\n-----------------\nWhat\'s more ❓\n-----------------\n\nClass-based handlers are also can be implemented with garnet conveniently. Use your imagination and ``garnet::callbacks::base::Callback`` as a parent class\n\nAwesome bitwise operation supported filters(I highly recommend to use them)::\n\n    # & (conjunction), | (disjunction), ~ (inversion), ^ (exclusive disjunction)\n    # also: ==, != (idk why)\n    @bot.on(MessageText.exact(".") | MessageText.exact(".."))\n\n\n``Len`` attribute in ``MessageText`` which has cmp methods::\n\n\n    @bot.on((MessageText.Len <= 14) | (MessageText.Len >= 88))\n\n\nUsing `client = TelegramClient.start` assignment and start client on the fly, make annotation or typing.cast to have better hints.\n\n---------------\nAbout\n---------------\n\nYou can find me in tg by `@martin_winks <https://telegram.me/martin_winks>`_ and yeah I receive donates as well as all contributors do(support `lonamiwebs <http://paypal.me/lonamiwebs>`_ and `JRootJunior <https://opencollective.com/aiogram/organization/0/website>`_).\n\n\n---------------------\n🤗 Credits\n---------------------\n\nFinite-state machine was ported from cool BotAPI library \'aiogram\', special thanks to Alex_\n',
    'author': 'Martin Winks',
    'author_email': 'cat@snejugal.ru',
    'maintainer': None,
    'maintainer_email': None,
    'url': 'https://github.com/uwinx/garnet',
    'packages': packages,
    'package_data': package_data,
    'install_requires': install_requires,
    'python_requires': '>=3.7,<4.0',
}


setup(**setup_kwargs)
