yoyogram 0.0.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. yoyogram-0.0.0/LICENSE +3 -0
  2. yoyogram-0.0.0/MANIFEST.in +1 -0
  3. yoyogram-0.0.0/PKG-INFO +23 -0
  4. yoyogram-0.0.0/pyproject.toml +3 -0
  5. yoyogram-0.0.0/setup.cfg +4 -0
  6. yoyogram-0.0.0/setup.py +31 -0
  7. yoyogram-0.0.0/src/_yoyo_cli/__init__.py +0 -0
  8. yoyogram-0.0.0/src/_yoyo_cli/cli.py +46 -0
  9. yoyogram-0.0.0/src/_yoyo_cli/core.py +88 -0
  10. yoyogram-0.0.0/src/_yoyo_cli/templates/__init__.py +0 -0
  11. yoyogram-0.0.0/src/_yoyo_cli/templates/bot/__init__.py +91 -0
  12. yoyogram-0.0.0/src/_yoyo_cli/templates/bot/config.py +78 -0
  13. yoyogram-0.0.0/src/_yoyo_cli/templates/bot/models/__init__.py +19 -0
  14. yoyogram-0.0.0/src/_yoyo_cli/templates/bot/routers/__init__.py +31 -0
  15. yoyogram-0.0.0/src/_yoyo_cli/templates/bot/routers/base/__init__.py +30 -0
  16. yoyogram-0.0.0/src/_yoyo_cli/templates/bot/routers/base/handlers/__init__.py +18 -0
  17. yoyogram-0.0.0/src/_yoyo_cli/templates/bot/routers/base/middlewares/__init__.py +9 -0
  18. yoyogram-0.0.0/src/_yoyo_cli/templates/bot/routers/base/scripts/__init__.py +6 -0
  19. yoyogram-0.0.0/src/_yoyo_cli/templates/bot/routers/middlewares/__init__.py +10 -0
  20. yoyogram-0.0.0/src/_yoyo_cli/templates/bot/scripts/__init__.py +20 -0
  21. yoyogram-0.0.0/src/_yoyo_cli/templates/bot/utils/__init__.py +0 -0
  22. yoyogram-0.0.0/src/_yoyo_cli/templates/bot/utils/menu.py +13 -0
  23. yoyogram-0.0.0/src/_yoyo_cli/templates/bot/utils/scheduler/__init__.py +25 -0
  24. yoyogram-0.0.0/src/_yoyo_cli/templates/project/__init__.py +0 -0
  25. yoyogram-0.0.0/src/_yoyo_cli/templates/project/main.py +7 -0
  26. yoyogram-0.0.0/src/_yoyo_cli/templates/project/tgbot/__init__.py +0 -0
  27. yoyogram-0.0.0/src/_yoyo_cli/templates/project/tgbot/bot.py +21 -0
  28. yoyogram-0.0.0/src/_yoyo_cli/templates/project/tgbot/bots/__init__.py +41 -0
  29. yoyogram-0.0.0/src/_yoyo_cli/templates/project/tgbot/data/__init__.py +0 -0
  30. yoyogram-0.0.0/src/_yoyo_cli/templates/project/tgbot/data/texts.py +11 -0
  31. yoyogram-0.0.0/src/_yoyo_cli/templates/project/tgbot/data/web_apps.py +2 -0
  32. yoyogram-0.0.0/src/_yoyo_cli/templates/project/tgbot/models/__init__.py +19 -0
  33. yoyogram-0.0.0/src/_yoyo_cli/templates/router/__init__.py +30 -0
  34. yoyogram-0.0.0/src/_yoyo_cli/templates/router/handlers/__init__.py +18 -0
  35. yoyogram-0.0.0/src/_yoyo_cli/templates/router/middlewares/__init__.py +9 -0
  36. yoyogram-0.0.0/src/_yoyo_cli/templates/router/routers/__init__.py +28 -0
  37. yoyogram-0.0.0/src/_yoyo_cli/templates/router/scripts/__init__.py +6 -0
  38. yoyogram-0.0.0/src/yoyo/__init__.py +0 -0
  39. yoyogram-0.0.0/src/yoyo/handlers/__init__.py +0 -0
  40. yoyogram-0.0.0/src/yoyo/keyboards/__init__.py +0 -0
  41. yoyogram-0.0.0/src/yoyo/logger.py +64 -0
  42. yoyogram-0.0.0/src/yoyo/middlewares/__init__.py +0 -0
  43. yoyogram-0.0.0/src/yoyo/models/__init__.py +0 -0
  44. yoyogram-0.0.0/src/yoyo/tools.py +16 -0
  45. yoyogram-0.0.0/src/yoyogram.egg-info/PKG-INFO +23 -0
  46. yoyogram-0.0.0/src/yoyogram.egg-info/SOURCES.txt +50 -0
  47. yoyogram-0.0.0/src/yoyogram.egg-info/dependency_links.txt +1 -0
  48. yoyogram-0.0.0/src/yoyogram.egg-info/entry_points.txt +2 -0
  49. yoyogram-0.0.0/src/yoyogram.egg-info/requires.txt +6 -0
  50. yoyogram-0.0.0/src/yoyogram.egg-info/top_level.txt +2 -0
  51. yoyogram-0.0.0/test/test.py +3 -0
yoyogram-0.0.0/LICENSE ADDED
@@ -0,0 +1,3 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025
@@ -0,0 +1 @@
1
+ recursive-include yoyo_cli/templates *
@@ -0,0 +1,23 @@
1
+ Metadata-Version: 2.4
2
+ Name: yoyogram
3
+ Version: 0.0.0
4
+ Summary: The framework to ease the work with huge projects with aiogram
5
+ Author: dhmmmhb
6
+ Classifier: Programming Language :: Python :: 3
7
+ Classifier: License :: OSI Approved :: MIT License
8
+ Requires-Python: >=3.7
9
+ Description-Content-Type: text/markdown
10
+ License-File: LICENSE
11
+ Requires-Dist: aiogram
12
+ Requires-Dist: redis
13
+ Requires-Dist: environs
14
+ Requires-Dist: aiosqlite
15
+ Requires-Dist: APScheduler
16
+ Requires-Dist: rich
17
+ Dynamic: author
18
+ Dynamic: classifier
19
+ Dynamic: description-content-type
20
+ Dynamic: license-file
21
+ Dynamic: requires-dist
22
+ Dynamic: requires-python
23
+ Dynamic: summary
@@ -0,0 +1,3 @@
1
+ [build-system]
2
+ requires = ["setuptools", "wheel"]
3
+ build-backend = "setuptools.build_meta"
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,31 @@
1
+ from setuptools import setup, find_packages
2
+
3
+ setup(
4
+ name="yoyogram",
5
+ version="0.0.0",
6
+ description="The framework to ease the work with huge projects with aiogram",
7
+ long_description=open('README.md', 'r', encoding='utf-8').read(),
8
+ long_description_content_type="text/markdown",
9
+ author="dhmmmhb",
10
+ package_dir={"": "src"},
11
+ packages=find_packages(where="src"),
12
+ include_package_data=True,
13
+ entry_points={
14
+ "console_scripts": [
15
+ "yoyo = _yoyo_cli.cli:main"
16
+ ]
17
+ },
18
+ install_requires=[
19
+ "aiogram",
20
+ "redis",
21
+ "environs",
22
+ "aiosqlite",
23
+ "APScheduler",
24
+ "rich"
25
+ ],
26
+ classifiers=[
27
+ "Programming Language :: Python :: 3",
28
+ "License :: OSI Approved :: MIT License",
29
+ ],
30
+ python_requires=">=3.7",
31
+ )
File without changes
@@ -0,0 +1,46 @@
1
+
2
+ import argparse
3
+
4
+ from rich.console import Console
5
+
6
+ from _yoyo_cli.core import init_project, help_command, create_bot, establish_router
7
+
8
+
9
+ def main():
10
+ # Initializing custom Console by rich module
11
+ console = Console()
12
+
13
+ # Creating parser and subparsers for CLI
14
+ parser = argparse.ArgumentParser(prog="yoyo", description="🛠 YoYoGram CLI — Generate Templates")
15
+ subparsers = parser.add_subparsers(dest="command")
16
+
17
+ # Help Command
18
+ subparsers.add_parser("help", help="Show list of available commands")
19
+
20
+ # Init Command
21
+ init_parser = subparsers.add_parser("init", help="Create a new project")
22
+
23
+ # Bot Command
24
+ bot_parser = subparsers.add_parser("bot", help="Create a new bot")
25
+ bot_parser.add_argument("name", help="The name of the bot")
26
+
27
+ # Router Command
28
+ router_parser = subparsers.add_parser("router", help="Establish a new router")
29
+ router_parser.add_argument("name", help="The name of the router")
30
+ router_parser.add_argument("index", nargs='?', help="The index of the router", default=-1)
31
+ router_parser.add_argument("bot_name", nargs='?', help="The name of the bot", default=None)
32
+
33
+ # Get Request
34
+ args = parser.parse_args()
35
+
36
+ # Handle Request
37
+ if args.command == "init":
38
+ init_project(console)
39
+ elif args.command == "bot":
40
+ create_bot(console, args.name)
41
+ elif args.command == "router":
42
+ establish_router(console, args.name, args.index, args.bot_name)
43
+ elif args.command == "help" or args.command is None:
44
+ help_command(console)
45
+ else:
46
+ help_command(console)
@@ -0,0 +1,88 @@
1
+
2
+ import shutil
3
+ from pathlib import Path
4
+ import importlib.resources as pkg_resources
5
+
6
+ from rich.console import Console
7
+ from rich.table import Table
8
+
9
+ from _yoyo_cli import templates
10
+
11
+
12
+ def get_project_root():
13
+ current = Path.cwd()
14
+ for parent in [current] + list(current.parents):
15
+ if (parent / "main.py").exists() or (parent / ".git").exists():
16
+ return parent
17
+ return current
18
+
19
+
20
+ def init_project(console: Console):
21
+ dst_path = Path.cwd()
22
+ with pkg_resources.path(templates, "project") as template_path:
23
+ shutil.copytree(template_path, dst_path, dirs_exist_ok=True)
24
+ (dst_path / "__init__.py").unlink(missing_ok=True)
25
+ console.print("[green]✅ Project has been created![/green]")
26
+
27
+
28
+ def help_command(console: Console):
29
+ table = Table(title="🛠 Доступные команды YoYoGram CLI", style="magenta")
30
+ table.add_column("Command", style="cyan3", no_wrap=True)
31
+ table.add_column("Arguments", style="deep_sky_blue1")
32
+ table.add_column("Description", style="white")
33
+ table.add_row("init", "", "Create a new project")
34
+ table.add_row("bot", "bot_name", "Create a new bot")
35
+ table.add_row("router", "name Optional:index Optional:bot_name\nProviding bot_name it will create router by tgbot/bots/bot_name/routers/router_name path\nNot providing bot_name, it established router by the current path\nNot providing index means the last position", "Establish a new router")
36
+ console.print(table)
37
+
38
+
39
+ def create_bot(console: Console, bot_name: str):
40
+ with pkg_resources.path(templates, "bot") as template_path:
41
+ bots_dir = get_project_root() / "tgbot" / "bots" / bot_name
42
+
43
+ for item in template_path.rglob("*"):
44
+ if item.is_file():
45
+ rel_path = item.relative_to(template_path)
46
+ dst_file = bots_dir / rel_path
47
+ dst_file.parent.mkdir(parents=True, exist_ok=True)
48
+
49
+ try:
50
+ content = item.read_text(encoding="utf-8")
51
+ content = content.replace("{bot_name}", bot_name)
52
+ dst_file.write_text(content, encoding="utf-8")
53
+ except UnicodeDecodeError:
54
+ shutil.copyfile(item, dst_file)
55
+
56
+ console.print(f"[green]✅ {bot_name} has been created by tgbot/bots/{bot_name} directory![/green]")
57
+
58
+
59
+ def establish_router(console: Console, router_name: str, router_index: int = -1, bot_name: str = None):
60
+ with pkg_resources.path(templates, "router") as template_path:
61
+ if bot_name:
62
+ bots_dir = get_project_root() / "tgbot" / "bots" / bot_name / "routers" / router_name
63
+ else:
64
+ for parent in [Path.cwd()] + list(Path.cwd().parents):
65
+ if (parent / "routers").exists():
66
+ bots_dir = parent / "routers" / router_name
67
+ break
68
+ else:
69
+ bots_dir = get_project_root() / "tgbot" / "bots" / bot_name / "routers" / router_name
70
+
71
+ for item in template_path.rglob("*"):
72
+ if item.is_file():
73
+ rel_path = item.relative_to(template_path)
74
+ dst_file = bots_dir / rel_path
75
+ dst_file.parent.mkdir(parents=True, exist_ok=True)
76
+ try:
77
+ content = item.read_text(encoding="utf-8")
78
+ content = content.replace("{bot_name}", bot_name)
79
+ content = content.replace("{router_name}", router_name)
80
+ content = content.replace("{router_index}", str(router_index))
81
+ dst_file.write_text(content, encoding="utf-8")
82
+ except UnicodeDecodeError:
83
+ shutil.copyfile(item, dst_file)
84
+
85
+ if bot_name:
86
+ console.print(f"[green]✅ {router_name} has been established by tgbot/bots/{bot_name}/routers/{router_name} directory![/green]")
87
+ else:
88
+ console.print(f"[green]✅ {router_name} has been established by {str(bots_dir)} directory![/green]")
File without changes
@@ -0,0 +1,91 @@
1
+ import asyncio
2
+
3
+ from aiogram import Bot, Dispatcher
4
+ from aiogram.fsm.storage.base import DefaultKeyBuilder
5
+ from aiogram.fsm.storage.memory import MemoryStorage
6
+ from aiogram.fsm.storage.redis import RedisStorage
7
+ from aiogram.webhook.aiohttp_server import setup_application
8
+ from aiohttp import web
9
+ from redis import Redis
10
+
11
+ from tgbot.bots.{bot_name}.config import get_config
12
+
13
+
14
+ def build() -> [Bot, Dispatcher]:
15
+ config = get_config()
16
+
17
+ bot = Bot(
18
+ token=config.tgbot.token
19
+ )
20
+
21
+ if config.tgbot.use_redis:
22
+ redis = Redis(
23
+ host=config.redis.host,
24
+ port=config.redis.port,
25
+ password=config.redis.password
26
+ )
27
+ key_builder = None
28
+ if config.redis.is_prefix:
29
+ key_builder = DefaultKeyBuilder(prefix=config.redis.prefix)
30
+ storage = RedisStorage(redis, key_builder=key_builder)
31
+ else:
32
+ storage = MemoryStorage()
33
+
34
+ dp = Dispatcher(
35
+ storage=storage
36
+ )
37
+
38
+ from tgbot.bots.{bot_name}.scripts import register_scripts
39
+ register_scripts(bot, dp)
40
+ from tgbot.bots.{bot_name}.utils.scheduler import register_scheduler
41
+ register_scheduler(bot)
42
+ from tgbot.bots.{bot_name}.routers import register_routers
43
+ register_routers(dp)
44
+
45
+ return bot, dp
46
+
47
+
48
+ async def start(bot: Bot, dp: Dispatcher):
49
+ from tgbot.bots.{bot_name}.models import connect_models
50
+ await connect_models()
51
+
52
+ from tgbot.bots.{bot_name}.utils.menu import register_my_commands
53
+ await register_my_commands(bot)
54
+
55
+ config = get_config()
56
+
57
+ if config.tgbot.use_webhook:
58
+
59
+ async def on_startup(app):
60
+ await bot.set_webhook(app["webhook_url"])
61
+
62
+ async def on_cleanup(app):
63
+ await bot.delete_webhook()
64
+ await dp.storage.close()
65
+ await bot.session.close()
66
+
67
+ app = web.Application()
68
+ app["bot"] = bot
69
+ app["dp"] = dp
70
+ app["webhook_url"] = config.webhook.url
71
+
72
+ setup_application(app, dp, bot=bot)
73
+ app.on_startup.append(on_startup)
74
+ app.on_cleanup.append(on_cleanup)
75
+
76
+ runner = web.AppRunner(app)
77
+ await runner.setup()
78
+ site = web.TCPSite(runner, "0.0.0.0", 8080)
79
+ await site.start()
80
+
81
+ try:
82
+ await asyncio.Event().wait()
83
+ finally:
84
+ await runner.cleanup()
85
+
86
+ else:
87
+ try:
88
+ await dp.start_polling(bot)
89
+ finally:
90
+ await dp.storage.close()
91
+ await bot.session.close()
@@ -0,0 +1,78 @@
1
+ from dataclasses import dataclass
2
+ from environs import Env
3
+ from yoyo.logger import Logger
4
+
5
+
6
+ @dataclass
7
+ class Tgbot:
8
+ token: str
9
+ admins: list[int]
10
+ group_id: int
11
+ use_redis: bool
12
+ use_webhook: bool
13
+
14
+
15
+ @dataclass
16
+ class Redis:
17
+ host: str
18
+ port: int
19
+ password: str
20
+ is_prefix: bool
21
+ prefix: str
22
+
23
+
24
+ @dataclass
25
+ class Webhook:
26
+ url: str
27
+
28
+
29
+ @dataclass
30
+ class Payment:
31
+ token: str
32
+ currency: str
33
+
34
+
35
+ @dataclass
36
+ class Misc:
37
+ tz: str
38
+
39
+
40
+ @dataclass
41
+ class Config:
42
+ tgbot: Tgbot
43
+ redis: Redis
44
+ payment: Payment
45
+ misc: Misc
46
+
47
+
48
+ def get_config() -> Config:
49
+ env = Env()
50
+ path = './tgbot/bots/{bot_name}/.env'
51
+ env.read_env(path)
52
+
53
+ return Config(
54
+ tgbot=Tgbot(
55
+ token=env.str("TOKEN"),
56
+ admins=list(map(int, env.str("ADMINS").split(' '))),
57
+ group_id=env.int("GROUP_ID"),
58
+ use_redis=env.bool("USE_REDIS"),
59
+ use_webhook=env.bool("USE_WEBHOOK"),
60
+ ),
61
+ redis=Redis(
62
+ host=env.str("REDIS_HOST"),
63
+ port=env.int("REDIS_PORT"),
64
+ password=env.str("REDIS_PASSWORD"),
65
+ is_prefix=env.bool("REDIS_IS_PREFIX"),
66
+ prefix=env.str("REDIS_PREFIX"),
67
+ ),
68
+ payment=Payment(
69
+ token=env.str("PAYMENT_PROVIDER_TOKEN"),
70
+ currency=env.str("PAYMENT_CURRENCY"),
71
+ ),
72
+ misc=Misc(
73
+ tz=env.str("SCHEDULER_TZ")
74
+ )
75
+ )
76
+
77
+
78
+ log = Logger()
@@ -0,0 +1,19 @@
1
+ import importlib
2
+ from copy import deepcopy
3
+ import yoyo
4
+
5
+
6
+ async def connect_models():
7
+ python_models = yoyo.tools.listdir(__file__)
8
+
9
+ for el in deepcopy(python_models):
10
+ if not el[-3:] == ".py":
11
+ python_models.remove(el)
12
+ python_models.remove("__init__.py")
13
+ python_models = list(map(lambda x: x[:-3], python_models))
14
+
15
+ package = yoyo.tools.package(__file__)
16
+
17
+ for module in python_models:
18
+ import_connect = importlib.import_module(f".{module}", package=package).main
19
+ await import_connect()
@@ -0,0 +1,31 @@
1
+ import importlib
2
+ from src import yoyo
3
+
4
+ from aiogram import Dispatcher, Router
5
+
6
+
7
+ def register_routers(dp: Dispatcher):
8
+ # Register middlewares of dispatcher (global middlewares)
9
+ from .middlewares import register_dp_middlewares
10
+ register_dp_middlewares(dp)
11
+
12
+ # Include routers to dispatcher
13
+ routers_list = yoyo.tools.listdir(__file__)
14
+ routers_list.remove("__init__.py")
15
+ try:
16
+ routers_list.remove("__pycache__")
17
+ except ValueError:
18
+ pass
19
+ routers_list.remove("middlewares")
20
+
21
+ routers: list[tuple[int, Router]] = []
22
+
23
+
24
+ package = yoyo.tools.package(__file__)
25
+ for module in routers_list:
26
+ import_get_router = importlib.import_module(f".{module}", package=package).get_router
27
+ router.append(import_get_router())
28
+
29
+ max_i = max(i for i, _ in routers if i != -1) + 1
30
+ for _, router in sorted(routers, key=lambda x: max_i if x[0] == -1 else x[0]):
31
+ dp.include_router(router)
@@ -0,0 +1,30 @@
1
+ import importlib
2
+ import os
3
+ import yoyo
4
+
5
+ from aiogram import Router
6
+
7
+ from .middlewares import register_middlewares
8
+ from .handlers import register_handlers
9
+
10
+
11
+ def get_router() -> tuple[int, Router]:
12
+ router = Router(name=yoyo.tools.basename(__file__))
13
+
14
+ # Register middlewares, handlers and errors
15
+ register_middlewares(router)
16
+ register_handlers(router)
17
+
18
+ # Include to router another routers
19
+ path = yoyo.tools.listpath(__file__)
20
+ path.append("routers")
21
+ try:
22
+ routers = os.listdir("\\".join(path))
23
+ package = yoyo.tools.package(path)
24
+ for module in routers:
25
+ import_get_router = importlib.import_module(f".{module}", package=package).get_router
26
+ router.include_router(import_get_router())
27
+ except (FileNotFoundError, TypeError):
28
+ pass
29
+
30
+ return 1, router
@@ -0,0 +1,18 @@
1
+ import importlib
2
+ from src import yoyo
3
+
4
+ from aiogram import Router
5
+
6
+
7
+ def register_handlers(router: Router):
8
+ modules: list[str] = list(map(lambda x: x[:-3], yoyo.tools.listdir(__file__)))
9
+ modules.remove('__init__')
10
+ try:
11
+ modules.remove('__pycach')
12
+ except:
13
+ pass
14
+
15
+ package = yoyo.tools.package(__file__)
16
+ for module in modules:
17
+ import_register = importlib.import_module(f".{module}", package=package).register
18
+ import_register(router)
@@ -0,0 +1,9 @@
1
+ from aiogram import Dispatcher
2
+
3
+
4
+ def register_middlewares(dp: Dispatcher):
5
+ """
6
+ Strict order
7
+ dp.message.middleware.register(YourMiddleware())
8
+ """
9
+ ...
@@ -0,0 +1,6 @@
1
+ from aiogram import Bot, Dispatcher
2
+
3
+ from tgbot.bots.{bot_name}.scripts import bot, dp
4
+
5
+ bot: Bot = bot
6
+ dp: Dispatcher = dp
@@ -0,0 +1,10 @@
1
+
2
+ from aiogram import Dispatcher
3
+
4
+
5
+ def register_dp_middlewares(dp: Dispatcher):
6
+ """
7
+ Strict order
8
+ dp.message.middleware.register(YourMiddleware())
9
+ """
10
+ ...
@@ -0,0 +1,20 @@
1
+ from aiogram import Bot, Dispatcher
2
+
3
+ """
4
+ Public Scripts to use it for any routers,
5
+ or to call it from other pieces of structure,
6
+ like another code (not tgbot)
7
+ """
8
+
9
+ bot: Bot
10
+ dp: Dispatcher
11
+
12
+
13
+ def register_scripts(work_bot: Bot, work_dp: Dispatcher):
14
+ global bot, dp
15
+
16
+ bot = work_bot
17
+ dp = work_dp
18
+
19
+
20
+ __all__ = ['register_scripts', 'bot', 'dp']
@@ -0,0 +1,13 @@
1
+ from aiogram import Bot
2
+ from aiogram.types import BotCommand
3
+
4
+
5
+ async def register_my_commands(bot: Bot):
6
+ return await bot.set_my_commands(
7
+ [
8
+ BotCommand(
9
+ command="start",
10
+ description="Starts bot"
11
+ )
12
+ ]
13
+ )
@@ -0,0 +1,25 @@
1
+ import importlib
2
+ from src import yoyo
3
+
4
+ from aiogram import Bot
5
+ from apscheduler.schedulers.asyncio import AsyncIOScheduler
6
+
7
+ from tgbot.bots.{bot_name}.data.config import get_config
8
+
9
+ scheduler: AsyncIOScheduler
10
+
11
+
12
+ def register_scheduler(bot: Bot):
13
+ global scheduler
14
+ scheduler = AsyncIOScheduler(timezone=get_config().misc.tz)
15
+
16
+ tasks = list(map(lambda x: x[:-3], yoyo.tools.listdir(__file__)))
17
+ tasks.remove('__init__')
18
+ tasks.remove('__pycach')
19
+
20
+ package = yoyo.tools.package(__file__)
21
+ for module in tasks:
22
+ import_register = importlib.import_module(f'.{module}', package=package).register
23
+ import_register(scheduler, bot)
24
+
25
+ scheduler.start()
@@ -0,0 +1,7 @@
1
+ import asyncio
2
+
3
+ from tgbot.bot import main
4
+
5
+
6
+ if __name__ == "__main__":
7
+ asyncio.run(main())
@@ -0,0 +1,21 @@
1
+ import asyncio
2
+ from asyncio import CancelledError
3
+
4
+ from aiogram import Bot, Dispatcher
5
+ from aiogram.fsm.storage.memory import MemoryStorage
6
+ from aiogram.fsm.storage.redis import RedisStorage
7
+ from redis import Redis
8
+
9
+ from tgbot.bots import build_bots, start_bots
10
+
11
+
12
+ async def build() -> list[tuple[Bot, Dispatcher]]:
13
+ return await build_bots()
14
+
15
+
16
+ async def start(bots: list[tuple[Bot, Dispatcher]]):
17
+ await start_bots(bots)
18
+
19
+
20
+ async def main():
21
+ await start(await build())
@@ -0,0 +1,41 @@
1
+ import importlib
2
+ import os
3
+ import yoyo
4
+
5
+ from aiogram import Bot, Dispatcher
6
+
7
+
8
+ async def build_bots() -> list[tuple[Bot, Dispatcher]]:
9
+ bots_list = yoyo.tools.listdir(__file__)
10
+ bots_list.remove("__init__.py")
11
+ try:
12
+ bots_list.remove("__pycache__")
13
+ except:
14
+ pass
15
+
16
+ bots: list[tuple[Bot, Dispatcher]] = []
17
+
18
+ package = yoyo.tools.package(__file__)
19
+
20
+ for module in bots_list:
21
+ import_build_bot = importlib.import_module(f".{module}", package=package).build_bot
22
+ bots.append(await import_build_bot())
23
+
24
+ return bots
25
+
26
+
27
+ async def start_bots(bots: list[tuple[Bot, Dispatcher]]):
28
+ bots_list = yoyo.tools.listdir(__file__)
29
+
30
+
31
+ bots_list.remove("__init__.py")
32
+ try:
33
+ bots_list.remove("__pycache__")
34
+ except:
35
+ pass
36
+
37
+ package = yoyo.tools.package(__file__)
38
+
39
+ for module, bot, dp in zip(bots_list, bots):
40
+ import_start_bot = importlib.import_module(f".{module}", package=package).start_bot
41
+ await import_start_bot(bot, dp)
@@ -0,0 +1,11 @@
1
+ DEFAULT_LANGUAGE = 'en'
2
+
3
+ FIRST_TEXT = {
4
+ 'en': "Hello!",
5
+ 'ru': "Привет!"
6
+ }
7
+
8
+ def get_text(lang_code: str, text: dict[str, str]) -> str:
9
+ if not lang_code in text.keys():
10
+ lang_code = DEFAULT_LANGUAGE
11
+ return text[lang_code]
@@ -0,0 +1,2 @@
1
+
2
+ MY_WEB_APP = "https://example.com/"
@@ -0,0 +1,19 @@
1
+ import importlib
2
+ from copy import deepcopy
3
+ import yoyo
4
+
5
+
6
+ async def connect_models():
7
+ python_models = yoyo.tools.listdir(__file__)
8
+
9
+ for el in deepcopy(python_models):
10
+ if not el[-3:] == ".py":
11
+ python_models.remove(el)
12
+ python_models.remove("__init__.py")
13
+ python_models = list(map(lambda x: x[:-3], python_models))
14
+
15
+ package = yoyo.tools.package(__file__)
16
+
17
+ for module in python_models:
18
+ import_connect = importlib.import_module(f".{module}", package=package).main
19
+ await import_connect()
@@ -0,0 +1,30 @@
1
+ import importlib
2
+ import os
3
+ import yoyo
4
+
5
+ from aiogram import Router
6
+
7
+ from .middlewares import register_middlewares
8
+ from .handlers import register_handlers
9
+
10
+
11
+ def get_router() -> tuple[int, Router]:
12
+ router = Router(name=yoyo.tools.basename(__file__))
13
+
14
+ # Register middlewares, handlers and errors
15
+ register_middlewares(router)
16
+ register_handlers(router)
17
+
18
+ # Include to router another routers
19
+ path = yoyo.tools.listpath(__file__)
20
+ path.append("routers")
21
+ try:
22
+ routers = os.listdir("\\".join(path))
23
+ package = yoyo.tools.package(path)
24
+ for module in routers:
25
+ import_get_router = importlib.import_module(f".{module}", package=package).get_router
26
+ router.include_router(import_get_router())
27
+ except (FileNotFoundError, TypeError):
28
+ pass
29
+
30
+ return {router_index}, router
@@ -0,0 +1,18 @@
1
+ import importlib
2
+ from src import yoyo
3
+
4
+ from aiogram import Router
5
+
6
+
7
+ def register_handlers(router: Router):
8
+ modules: list[str] = list(map(lambda x: x[:-3], yoyo.tools.listdir(__file__)))
9
+ modules.remove('__init__')
10
+ try:
11
+ modules.remove('__pycach')
12
+ except:
13
+ pass
14
+
15
+ package = yoyo.tools.package(__file__)
16
+ for module in modules:
17
+ import_register = importlib.import_module(f".{module}", package=package).register
18
+ import_register(router)
@@ -0,0 +1,9 @@
1
+ from aiogram import Dispatcher
2
+
3
+
4
+ def register_middlewares(dp: Dispatcher):
5
+ """
6
+ Strict order
7
+ dp.message.middleware.register(YourMiddleware())
8
+ """
9
+ ...
@@ -0,0 +1,28 @@
1
+ import importlib
2
+ from src import yoyo
3
+
4
+ from aiogram import Dispatcher, Router
5
+
6
+
7
+ def register_routers(dp: Dispatcher):
8
+ # Register middlewares of dispatcher (global middlewares)
9
+
10
+ # Include routers to dispatcher
11
+ routers_list = yoyo.tools.listdir(__file__)
12
+ routers_list.remove("__init__.py")
13
+ try:
14
+ routers_list.remove("__pycache__")
15
+ except ValueError:
16
+ pass
17
+
18
+ routers: list[tuple[int, Router]] = []
19
+
20
+
21
+ package = yoyo.tools.package(__file__)
22
+ for module in routers_list:
23
+ import_get_router = importlib.import_module(f".{module}", package=package).get_router
24
+ router.append(import_get_router())
25
+
26
+ max_i = max(i for i, _ in routers if i != -1) + 1
27
+ for _, router in sorted(routers, key=lambda x: max_i if x[0] == -1 else x[0]):
28
+ dp.include_router(router)
@@ -0,0 +1,6 @@
1
+ from aiogram import Bot, Dispatcher
2
+
3
+ from tgbot.bots.{bot_name}.scripts import bot, dp
4
+
5
+ bot: Bot = bot
6
+ dp: Dispatcher = dp
File without changes
File without changes
File without changes
@@ -0,0 +1,64 @@
1
+ import sys
2
+ import os
3
+ import logging
4
+
5
+ from datetime import datetime
6
+
7
+
8
+ class Logger(object):
9
+ log_file = bytes
10
+ EXCEPTION = 100
11
+ CRITICAL = 50
12
+ ERROR = 40
13
+ WARNING = 30
14
+ INFO = 20
15
+ DEBUG = 10
16
+ NOTSET = 0
17
+
18
+ def __init__(self):
19
+ today = datetime.strftime(datetime.now(), "%d-%m-%y-%H_%M_%S")
20
+
21
+ if not os.path.exists("logs"):
22
+ os.mkdir("logs")
23
+
24
+ LOGS_FOLDER = f"logs/log-{today}.log"
25
+ LOGGER_NAME = "YoYoLogger"
26
+
27
+ logging.basicConfig(
28
+ filename=LOGS_FOLDER,
29
+ filemode="w",
30
+ format="[%(asctime)s] [%(levelname)s] -- %(message)s",
31
+ datefmt="%d/%b/%y %H:%M:%S",
32
+ encoding="utf-8"
33
+ )
34
+
35
+
36
+ self.__log = logging.getLogger(LOGGER_NAME)
37
+ formatter = logging.Formatter(
38
+ "[%(asctime)s] [%(levelname)s] -- %(message)s", datefmt="%d/%b/%y %H:%M:%S"
39
+ )
40
+ ch = logging.StreamHandler(sys.stderr)
41
+ ch.setFormatter(formatter)
42
+
43
+ self.__log.setLevel(self.INFO)
44
+ self.__methods_map = {
45
+ self.DEBUG: self.__log.debug,
46
+ self.INFO: self.__log.info,
47
+ self.WARNING: self.__log.warning,
48
+ self.ERROR: self.__log.error,
49
+ self.CRITICAL: self.__log.critical,
50
+ self.EXCEPTION: self.__log.exception,
51
+ }
52
+
53
+
54
+ def __call__(self, lvl, msg, *args, **kwargs):
55
+ if lvl in self.__methods_map:
56
+ self.__methods_map[lvl](msg, *args, **kwargs)
57
+ else:
58
+ self.__log.log(lvl, msg, *args, **kwargs)
59
+
60
+
61
+ def set_level(self, level=None):
62
+ if level is None:
63
+ level = self.INFO
64
+ self.__log.setLevel(level)
File without changes
File without changes
@@ -0,0 +1,16 @@
1
+ import os
2
+ import sys
3
+ from pathlib import Path
4
+
5
+
6
+ def listdir(file: __file__):
7
+ return os.listdir(os.path.dirname(file))
8
+
9
+ def package(file: __file__):
10
+ project_root = Path(sys.modules['__main__'].file).resolve().parent
11
+ current_path = Path(file).resolve()
12
+ relative_path = current_path.relative_to(project_root)
13
+ return ".".join(relative_path.with_suffix('').parts)
14
+
15
+ def basename(file: __file__):
16
+ return file.split(os.sep)[-2]
@@ -0,0 +1,23 @@
1
+ Metadata-Version: 2.4
2
+ Name: yoyogram
3
+ Version: 0.0.0
4
+ Summary: The framework to ease the work with huge projects with aiogram
5
+ Author: dhmmmhb
6
+ Classifier: Programming Language :: Python :: 3
7
+ Classifier: License :: OSI Approved :: MIT License
8
+ Requires-Python: >=3.7
9
+ Description-Content-Type: text/markdown
10
+ License-File: LICENSE
11
+ Requires-Dist: aiogram
12
+ Requires-Dist: redis
13
+ Requires-Dist: environs
14
+ Requires-Dist: aiosqlite
15
+ Requires-Dist: APScheduler
16
+ Requires-Dist: rich
17
+ Dynamic: author
18
+ Dynamic: classifier
19
+ Dynamic: description-content-type
20
+ Dynamic: license-file
21
+ Dynamic: requires-dist
22
+ Dynamic: requires-python
23
+ Dynamic: summary
@@ -0,0 +1,50 @@
1
+ LICENSE
2
+ MANIFEST.in
3
+ README
4
+ pyproject.toml
5
+ setup.py
6
+ src/_yoyo_cli/__init__.py
7
+ src/_yoyo_cli/cli.py
8
+ src/_yoyo_cli/core.py
9
+ src/_yoyo_cli/templates/__init__.py
10
+ src/_yoyo_cli/templates/bot/__init__.py
11
+ src/_yoyo_cli/templates/bot/config.py
12
+ src/_yoyo_cli/templates/bot/models/__init__.py
13
+ src/_yoyo_cli/templates/bot/routers/__init__.py
14
+ src/_yoyo_cli/templates/bot/routers/base/__init__.py
15
+ src/_yoyo_cli/templates/bot/routers/base/handlers/__init__.py
16
+ src/_yoyo_cli/templates/bot/routers/base/middlewares/__init__.py
17
+ src/_yoyo_cli/templates/bot/routers/base/scripts/__init__.py
18
+ src/_yoyo_cli/templates/bot/routers/middlewares/__init__.py
19
+ src/_yoyo_cli/templates/bot/scripts/__init__.py
20
+ src/_yoyo_cli/templates/bot/utils/__init__.py
21
+ src/_yoyo_cli/templates/bot/utils/menu.py
22
+ src/_yoyo_cli/templates/bot/utils/scheduler/__init__.py
23
+ src/_yoyo_cli/templates/project/__init__.py
24
+ src/_yoyo_cli/templates/project/main.py
25
+ src/_yoyo_cli/templates/project/tgbot/__init__.py
26
+ src/_yoyo_cli/templates/project/tgbot/bot.py
27
+ src/_yoyo_cli/templates/project/tgbot/bots/__init__.py
28
+ src/_yoyo_cli/templates/project/tgbot/data/__init__.py
29
+ src/_yoyo_cli/templates/project/tgbot/data/texts.py
30
+ src/_yoyo_cli/templates/project/tgbot/data/web_apps.py
31
+ src/_yoyo_cli/templates/project/tgbot/models/__init__.py
32
+ src/_yoyo_cli/templates/router/__init__.py
33
+ src/_yoyo_cli/templates/router/handlers/__init__.py
34
+ src/_yoyo_cli/templates/router/middlewares/__init__.py
35
+ src/_yoyo_cli/templates/router/routers/__init__.py
36
+ src/_yoyo_cli/templates/router/scripts/__init__.py
37
+ src/yoyo/__init__.py
38
+ src/yoyo/logger.py
39
+ src/yoyo/tools.py
40
+ src/yoyo/handlers/__init__.py
41
+ src/yoyo/keyboards/__init__.py
42
+ src/yoyo/middlewares/__init__.py
43
+ src/yoyo/models/__init__.py
44
+ src/yoyogram.egg-info/PKG-INFO
45
+ src/yoyogram.egg-info/SOURCES.txt
46
+ src/yoyogram.egg-info/dependency_links.txt
47
+ src/yoyogram.egg-info/entry_points.txt
48
+ src/yoyogram.egg-info/requires.txt
49
+ src/yoyogram.egg-info/top_level.txt
50
+ test/test.py
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ yoyo = _yoyo_cli.cli:main
@@ -0,0 +1,6 @@
1
+ aiogram
2
+ redis
3
+ environs
4
+ aiosqlite
5
+ APScheduler
6
+ rich
@@ -0,0 +1,2 @@
1
+ _yoyo_cli
2
+ yoyo
@@ -0,0 +1,3 @@
1
+ from pathlib import Path
2
+
3
+ print(list(Path.cwd().parents))