Package: jgram
JGramAbout the projectJgram was created to be able to quickly and conveniently write telegram bots, placing their structure in .json files
Jgram based onAIOgram-2.21frameworkfor development info seeTODOandCHANGESTable of contentsInstallationFrom sourcesGetting startedInitializationRegistryWindows managerStorageLoaderWindowsFieldsLoading windowsMiddlewaresFiltersAioram's filtersMiddleware as filterinstallationFrom sourcesgitclonehttps://github.com/GrehBan/jgram.gitcdjgram
poetryinstall--no-devSpeedupspipinstalluvloopcchardetaiodnsujsonGetting startedwindows.json{"locale":"en","start":{"text":"Hello unknown user","markup":{"type":"inline","markup":[[{"text":"Register","callback_data":"write_name"}]]}},"write_name":{"text":"Write your name please","markup":{"type":"inline","markup":[[{"text":"back","callback_data":"start"}]]},"next_step":"write_age"},"write_age":{"text":"Your name is {name}\nwrite your age please","markup":{"type":"inline","markup":[[{"text":"back","callback_data":"write_name"}]]},"allowed_updates":["text"],"next_step":"save_data"},"save_data":{"text":"Your name is {name}\nYou {age} years old\nThank you!","allowed_updates":["text"]}}simple.pyimportasyncioimportosfromjgramimportRegistryfromjgram.contextimportContextfromjgram.managerimportWindowsManagerasyncdefname_formatter(update,manager:WindowsManager,context:Context):context.data['name']=update.textasyncdefage_formatter(update,manager:WindowsManager,context:Context):context.data['age']=update.textasyncdefmain():registry=Registry(token=os.getenv('BOT_TOKEN'))registry.manager.load_windows('windows.json')registry.register_middleware(name_formatter,name='write_age')registry.register_middleware(age_formatter,name='save_data')try:awaitregistry.start()finally:awaitregistry.close()if__name__=='__main__':asyncio.run(main())InitializationRegistryfromjgramimportRegistryregistry=Registry()# initialization arguments# registry initialize bot and dispatcher from one of this arguments, and must have one of itbot->typing.Optional[aiogram.Bot]# current aiogram's botdispatcher->typing.Optional[aiogram.Dispatcher]# current aiogram's dispatchertoken->typing.Optional[str]# bot's token# registry initialize new jgram.WindowsManager instance, if manager argument is not providedmanager->typing.Optional[jgram.WindowsManager]# current manager for manage windowsWindows managerfromjgramimportWindowsManagermanager=WindowsManager()# initialization arguments# manager initialize new jgram.loader.JsonLoader instance, if loader arguemnt is not providedloader->typing.Optional[jgram.loader.protocols.LoaderProto]# current loader for load raw json# manager initialize new jgram.storage.memory.MemoryStorage, if storage argument is not providedstorage->typing.Optional[jgram.storage.protocols.BaseStorage]# current users data storagestart_window->str# name of window than be rendered when /start command is handleddefault="start"Storagefromjgram.storage.memoryimportMemoryStorage# memory storage for examplestorage=MemoryStorage()Loaderfromjgram.loaderimportJsonLoaderloader=JsonLoader()# initialization argumentsdefault_locale->typing.Optional[str]# locale which will be used if "locale" field in window is not provided, if set to None, all of windows must have "locale" fielddefault='en'json_loads->typing.Callable[...,Any]# function to loads json from stringdefault=json.loads# python's built-in json's module funcWindowsStructure{"lang":"{lang}","{text_name}":{"text":"{text}","media":{"type":"{media_type}","url":"{media_url}","path":"{media_path}","file_id":"{media_file_id}"}"markup":{"type":"{type}","markup":[[{"text":"Button text","callback_data":"{next_step callback data}"}],[{"text":"Url button","url":"{url}"}],[{"text":"Reply button"}]],"parse_mode":null,"web_preview":false,"allowed_updates":["{update_type}"],"filters":[{"{filter_name}":"{value}","next_step":"{value}"}],"next_step":"{value}","reset_context":false}}}Fields"lang"->typing.Optional[str]# Locale of windows"text"->typing.Optional[str]# bot message text, uses as a caption to media, if it set"media"->typing.Optional[typing.Dict]# bot message media"type"->str# media typevalues=["photo","video","animation","audio","document"]# media must have one of this fields"url"->typing.Optional[str]# media url"path"->typing.Optional[str]# path to media file"file_id"->typing.Optional[str]# media file id"markup"->typing.Optional[typing.Dict]# bot message reply markup"type"->str# markup typevalues=["inline","reply"]"markup"typing.List[typing.List[typing.Dict[str,str]]]# list of lists of markup buttons"parse_mode"->typing.Optional[str]# bot message parse modevalues=["HTML","MARKDOWN","MARKDOWN_V2"]"web_preview"->bool# bot message disable or enable web previewdefault=False"allowed_updates"->typing.List[str]# list of content types allowed for processingdefault=[]values=["text","photo","video","animation","audio","document"]"filters"->typing.List[typing.Dict]# list of dicts than represents aiogram's filtersdefault=[]"{filter_name}"->str# Aiogram's filter value..."next_step"->str# name of window than be rendered when filters passed"next_step"->typing.Optional[str]# name of window than be rendered if any filter not passed or filters not found"reset_context"->bool# reset current user contextdefault=FalseLoading windowsfromjgramimportWindowsManagermanager=WindowsManager()manager.load_windows("path/to/file/windows.json")Middlewaresmiddlewares call before window rendered, and in middleware you can change user context data or manipulate window processingmiddlewares can return a True or False, if returns True, update handler will continue render window, but if returns False, window will not be renderedfor examplefromaiogram.typesimportMessage,CallbackQueryfromjgramimportRegistryfromjgram.contextimportContextfromjgram.managerimportWindowsManagerasyncdefmiddleware(update:typing.Union[Message,CallbackQuery],manager:WindowsManager,context:Context):ifisinstance(update,CallbackQuery):returnTrue# skip middleware processing, and render windowcontext.data['name']=update.text# save current message text to "name" fieldregistry=Registry()registry.register_middleware(middleware)# middleware will be processed for all windows# if you can process middleware only for one windowregistry.register_middleware(middleware,name="window_name")Filtersyou have two ways to filter updateAiogram's filtersyou can use aiogram's filters, to filter update, but only if filter have key fieldfor example{"filtered":{"text":"Hello","filters":[{"chat_id":123,"next_step":"chat_123"}],"next_step":"any_another_chat"}}if current update chat id is 123 renders "chat_123" window, in another situations renders "any_another_chat" windowMiddleware as filteryou can use jgram's middleware as filterfor examplefromaiogram.typesimportMessage,CallbackQueryfromjgram.contextimportContextfromjgram.managerimportWindowsManagerasyncdefmiddleware(update:typing.Union[Message,CallbackQuery],manager:WindowsManager,context:Context):ifisinstance(update,CallbackQuery):returnTrue# skip middleware processing, and render windowtry:age=int(update.text)# try to convert text to age intexceptValueError:returnFalse# skip window rendering# context.window_name = "error_window" # or switch window