2022-05-12 11:30:56 +00:00
<!doctype html>
< html lang = "en" >
< head >
< meta charset = "utf-8" >
< meta name = "viewport" content = "width=device-width, initial-scale=1, minimum-scale=1" / >
< meta name = "generator" content = "pdoc 0.10.0" / >
< title > telegram_bot.bot_updates API documentation< / title >
< meta name = "description" content = "script for regularly sending updates on shares and news based on user interval" / >
< link rel = "preload stylesheet" as = "style" href = "https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/11.0.1/sanitize.min.css" integrity = "sha256-PK9q560IAAa6WVRRh76LtCaI8pjTJ2z11v0miyNNjrs=" crossorigin >
< link rel = "preload stylesheet" as = "style" href = "https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/11.0.1/typography.min.css" integrity = "sha256-7l/o7C8jubJiy74VsKTidCy1yBkRtiUGbVkYBylBqUg=" crossorigin >
2022-09-17 22:58:59 +00:00
< link rel = "stylesheet preload" as = "style" href = "https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.6.0/styles/github.min.css" crossorigin >
2022-05-12 11:30:56 +00:00
< style > : root { --highlight-color : #fe9 } . flex { display : flex !important } body { line-height : 1.5 em } # content { padding : 20 px } # sidebar { padding : 30 px ; overflow : hidden } # sidebar > * : last-child { margin-bottom : 2 cm } . http-server-breadcrumbs { font-size : 130 % ; margin : 0 0 15 px 0 } # footer { font-size : .75 em ; padding : 5 px 30 px ; border-top : 1 px solid #ddd ; text-align : right } # footer p { margin : 0 0 0 1 em ; display : inline-block } # footer p : last-child { margin-right : 30 px } h1 , h2 , h3 , h4 , h5 { font-weight : 300 } h1 { font-size : 2.5 em ; line-height : 1.1 em } h2 { font-size : 1.75 em ; margin : 1 em 0 .50 em 0 } h3 { font-size : 1.4 em ; margin : 25 px 0 10 px 0 } h4 { margin : 0 ; font-size : 105 % } h1 : target , h2 : target , h3 : target , h4 : target , h5 : target , h6 : target { background : var ( - - highlight - color ) ; padding : .2 em 0 } a { color : #058 ; text-decoration : none ; transition : color .3 s ease-in-out } a : hover { color : #e82 } . title code { font-weight : bold } h2 [ id ^ = "header-" ] { margin-top : 2 em } . ident { color : #900 } pre code { background : #f8f8f8 ; font-size : .8 em ; line-height : 1.4 em } code { background : #f2f2f1 ; padding : 1 px 4 px ; overflow-wrap : break-word } h1 code { background : transparent } pre { background : #f8f8f8 ; border : 0 ; border-top : 1 px solid #ccc ; border-bottom : 1 px solid #ccc ; margin : 1 em 0 ; padding : 1 ex } # http-server-module-list { display : flex ; flex-flow : column } # http-server-module-list div { display : flex } # http-server-module-list dt { min-width : 10 % } # http-server-module-list p { margin-top : 0 } . toc ul , # index { list-style-type : none ; margin : 0 ; padding : 0 } # index code { background : transparent } # index h3 { border-bottom : 1 px solid #ddd } # index ul { padding : 0 } # index h4 { margin-top : .6 em ; font-weight : bold } @ media ( min-width : 200ex ) { # index . two-column { column-count : 2 } } @ media ( min-width : 300ex ) { # index . two-column { column-count : 3 } } dl { margin-bottom : 2 em } dl dl : last-child { margin-bottom : 4 em } dd { margin : 0 0 1 em 3 em } # header-classes + dl > dd { margin-bottom : 3 em } dd dd { margin-left : 2 em } dd p { margin : 10 px 0 } . name { background : #eee ; font-weight : bold ; font-size : .85 em ; padding : 5 px 10 px ; display : inline-block ; min-width : 40 % } . name : hover { background : #e0e0e0 } dt : target . name { background : var ( - - highlight - color ) } . name > span : first-child { white-space : nowrap } . name . class > span : nth-child ( 2 ) { margin-left : .4 em } . inherited { color : #999 ; border-left : 5 px solid #eee ; padding-left : 1 em } . inheritance em { font-style : normal ; font-weight : bold } . desc h2 { font-weight : 400 ; font-size : 1.25 em } . desc h3 { font-size : 1 em } . desc dt code { background : inherit } . source summary , . git-link-div { color : #666 ; text-align : right ; font-weight : 400 ; font-size : .8 em ; text-transform : uppercase } . source summary > * { white-space : nowrap ; cursor : pointer } . git-link { color : inherit ; margin-left : 1 em } . source pre { max-height : 500 px ; overflow : auto ; margin : 0 } . source pre code { font-size : 12 px ; overflow : visible } . hlist { list-style : none } . hlist li { display : inline } . hlist li : after { content : ',\2002' } . hlist li : last-child : after { content : none } . hlist . hlist { display : inline ; padding-left : 1 em } img { max-width : 100 % } td { padding : 0 .5 em } . admonition { padding : .1 em .5 em ; margin-bottom : 1 em } . admonition-title { font-weight : bold } . admonition . note , . admonition . info , . admonition . important { background : #aef } . admonition . todo , . admonition . versionadded , . admonition . tip , . admonition . hint { background : #dfd } . admonition . warning , . admonition . versionchanged , . admonition . deprecated { background : #fd4 } . admonition . error , . admonition . danger , . admonition . caution { background : lightpink } < / style >
< style media = "screen and (min-width: 700px)" > @ media screen and ( min-width : 700px ) { # sidebar { width : 30 % ; height : 100 vh ; overflow : auto ; position : sticky ; top : 0 } # content { width : 70 % ; max-width : 100 ch ; padding : 3 em 4 em ; border-left : 1 px solid #ddd } pre code { font-size : 1 em } . item . name { font-size : 1 em } main { display : flex ; flex-direction : row-reverse ; justify-content : flex-end } . toc ul ul , # index ul { padding-left : 1.5 em } . toc > ul > li { margin-top : .5 em } } < / style >
< style media = "print" > @ media print { # sidebar h1 { page-break-before : always } . source { display : none } } @ media print { * { background : transparent !important ; color : #000 !important ; box-shadow : none !important ; text-shadow : none !important } a [ href ] : after { content : " (" attr ( href ) ")" ; font-size : 90 % } a [ href ] [ title ] : after { content : none } abbr [ title ] : after { content : " (" attr ( title ) ")" } . ir a : after , a [ href ^ = "javascript:" ] : after , a [ href ^ = "#" ] : after { content : "" } pre , blockquote { border : 1 px solid #999 ; page-break-inside : avoid } thead { display : table-header-group } tr , img { page-break-inside : avoid } img { max-width : 100 % !important } @ page { margin : 0 . 5cm } p , h2 , h3 { orphans : 3 ; widows : 3 } h1 , h2 , h3 , h4 , h5 , h6 { page-break-after : avoid } } < / style >
2022-09-17 22:58:59 +00:00
< script defer src = "https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.6.0/highlight.min.js" integrity = "sha512-gU7kztaQEl7SHJyraPfZLQCNnrKdaQi5ndOyt4L4UPL/FHDd/uB9Je6KDARIqwnNNE27hnqoWLBq+Kpe4iHfeQ==" crossorigin > < / script >
2022-05-12 11:30:56 +00:00
< script > window . addEventListener ( 'DOMContentLoaded' , ( ) => hljs . initHighlighting ( ) ) < / script >
< / head >
< body >
< main >
< article id = "content" >
< header >
< h1 class = "title" > Module < code > telegram_bot.bot_updates< / code > < / h1 >
< / header >
< section id = "section-intro" >
< p > script for regularly sending updates on shares and news based on user interval< / p >
< details class = "source" >
< summary >
< span > Expand source code< / span >
< / summary >
< pre > < code class = "python" > " " "
script for regularly sending updates on shares and news based on user interval
" " "
__author__ = " Florian Kellermann, Linus Eickhoff"
__date__ = " 10.05.2022"
__version__ = " 1.0.2"
__license__ = " None"
import os
import sys
import time
from apscheduler.schedulers.background import BackgroundScheduler # scheduler for cron
from dotenv import load_dotenv
import telegram_bot.helper_functions as hf
import telegram_bot.news.news_fetcher as news_fetcher
import telegram_bot.shares.share_fetcher as share_fetcher
from telegram_bot.api_handling.api_handler import API_Handler
from telegram_bot.bot import bot
' ' '
* * * * * code
┬ ┬ ┬ ┬ ┬
│ │ │ │ │
│ │ │ │ └──── weekday (0-> Monday, 7-> Sunday)
│ │ │ └────── Month (1-12)
│ │ └──────── Day (1-31)
│ └────────── Hour (0-23)
└──────────── Minute (0-59)
example 0 8 * * * -> daily update at 8am
' ' '
user_ids = []
user_crontab = []
load_dotenv(dotenv_path=' .env' )
def start_updater():
" " " starting function for regularly sending updates
:raises: none
:rtype: none
" " "
print(" Bot updates started" )
my_handler = API_Handler(" https://gruppe1.testsites.info/api" , str(os.getenv(" BOT_EMAIL" )), str(os.getenv(" BOT_PASSWORD" )))
update_crontab(my_handler)
def update_crontab(p_my_handler):
" " " Updating crontab lists every hour
:type pCurrent_Time: time when starting crontab update
:param pCurrent_Time: datetime
:raises: none
:rtype: none
" " "
global user_crontab
global user_ids
all_users = p_my_handler.get_all_users() # get all users so crontabs can update for everybody
user_ids = []
user_crontab = []
for element in all_users:
if element[" cron" ] != ' ' and element[" telegram_user_id" ] != ' ' : # check if both values are existing so I have consistent data
try:
user_ids.append(int(element[" telegram_user_id" ]))
try:
user_crontab.append(str(element[" cron" ]))
except:
user_ids.pop() # if something goes wrong with cron I have to delete matching user id
except: continue
print(user_ids)
update_based_on_crontab(user_ids, user_crontab, p_my_handler)
update_crontab(p_my_handler) # restart the update after time sleep
def update_based_on_crontab(p_user_ids, p_user_crontab, p_my_handler):
" " " Check all the crontab codes and add jobs to start in time
:type p_user_ids: array
:param p_user_ids: user id array of all users
:type p_user_crontab: array
:param p_user_crontab: crontabs for all users equivalent to the user array
:type p_my_handler: Api_Handler
:param p_my_handler: get database stuff
:raises: none
:rtype: none
" " "
my_scheduler = BackgroundScheduler() # schedule sends based on cron
for i in range(len(p_user_ids)):
cron_split = p_user_crontab[i].split(" " ) # split it up to use in scheduler
print(cron_split[4], cron_split[1], cron_split[0], cron_split[3], cron_split[2])
my_scheduler.add_job(update_for_user, ' cron' , day_of_week=cron_split[4], hour=cron_split[1], minute=cron_split[0], month=cron_split[3], day=cron_split[2], args=(p_user_ids[i], p_my_handler))
my_scheduler.start()
time.sleep( 600 ) # scheduler runs in background and I wait 10mins
my_scheduler.shutdown() # after this the new crontabs will be loaded
def update_for_user(p_user_id, p_my_handler):
" " " Pull shares and send updates for specific user id
:type p_user_id: integer
:param p_user_id: user id of user that shall receive update
:type p_my_handler: Api_Handler
:param p_my_handler: handle the api and pull from database
:raises: none
:rtype: none
" " "
share_symbols = []
share_amounts = []
my_portfolio = p_my_handler.get_user_portfolio(p_user_id) # get all existing shares for user
for element in my_portfolio:
if element[" count" ] != ' ' and element[" isin" ] != ' ' :
print(element[" count" ], element[" isin" ])
share_symbols.append(element[" isin" ])
share_amounts.append(element[" count" ])
my_user = p_my_handler.get_user(p_user_id)
send_to_user(" Hello %s this is your share update for today:" %str(my_user[" username" ]), pUser_id=p_user_id)
shares = p_my_handler.get_user_shares(p_user_id) # all interest shares
if len(share_symbols) != 0: # iterate through all shares
for i in range(len(share_symbols)):
my_price = share_fetcher.get_share_price_no_currency(share_symbols[i])
my_update_message = f' {share_fetcher.get_share_information_markdown(share_symbols[i])}\ncount: {hf.make_markdown_proof(share_amounts[i])}\nTotal: {hf.make_markdown_proof(round(float(my_price) * float(share_amounts[i]), 2))} EUR'
bot.send_message(chat_id=p_user_id, text=my_update_message, parse_mode=" MARKDOWNV2" )
else:
send_to_user(" No shares found for your account. Check https://gruppe1.testsites.info to change your settings and add shares." , pUser_id=p_user_id)
if len(shares) != 0: # Send updates on watchlist shares if existing
send_to_user(" Your watchlist shares:" , pUser_id=p_user_id)
for element in shares:
send_to_user(share_fetcher.get_share_information_markdown(element), pUser_id=p_user_id, md_mode=True)
keywords = p_my_handler.get_user_keywords(p_user_id) # get keywords as array
if (keywords): # if keywords exist and array is not empty
send_to_user(" If you haven' t read yet: \nHere are some interesting news according to your keywords:" , pUser_id=p_user_id)
for keyword in keywords:
news = news_fetcher.get_top_news_by_keyword(keyword)[" articles" ]
keyword = hf.make_markdown_proof(keyword)
if not news: # if empty news array
send_to_user(f" No news found for keyword _{keyword}_\." , pUser_id=p_user_id, md_mode=True)
elif news == None: # if news is none
send_to_user(f" Server error for keyword _{keyword}_\." , pUser_id=p_user_id, md_mode=True)
else:
news_formatted = news_fetcher.format_article(news[0]) # format for message, only use the most popular article
send_to_user(f" _keyword: {keyword}_\n\n{news_formatted}" , pUser_id=p_user_id, md_mode=True) # send news with related keyword in Markdown
def send_to_user(pText, pUser_id, md_mode=False):
" " " Send message to user
:type pText: string
:param pText: Text to send to user
:type pUser_id: int
:param pUser_id: user to send to. per default me (Florian Kellermann)
:type md_mode: boolean
:param md_mode: if true, parse_mode is markdown
:raises: none
:rtype: none
" " "
if md_mode:
bot.send_message(chat_id=pUser_id, text=pText, parse_mode=" MARKDOWNV2" )
else:
bot.send_message(chat_id=pUser_id, text=pText)
if __name__ == " __main__" :
try:
start_updater()
sys.exit(-1)
except KeyboardInterrupt:
print(" Ending" )
sys.exit(-1)< / code > < / pre >
< / details >
< / section >
< section >
< / section >
< section >
< / section >
< section >
< h2 class = "section-title" id = "header-functions" > Functions< / h2 >
< dl >
< dt id = "telegram_bot.bot_updates.send_to_user" > < code class = "name flex" >
< span > def < span class = "ident" > send_to_user< / span > < / span > (< span > pText, pUser_id, md_mode=False)< / span >
< / code > < / dt >
< dd >
< div class = "desc" > < p > Send message to user
:type pText: string
:param pText: Text to send to user< / p >
< p > :type pUser_id: int
:param pUser_id: user to send to. per default me (Florian Kellermann)< / p >
< p > :type md_mode: boolean
:param md_mode: if true, parse_mode is markdown< / p >
< p > :raises: none< / p >
< p > :rtype: none< / p > < / div >
< details class = "source" >
< summary >
< span > Expand source code< / span >
< / summary >
< pre > < code class = "python" > def send_to_user(pText, pUser_id, md_mode=False):
" " " Send message to user
:type pText: string
:param pText: Text to send to user
:type pUser_id: int
:param pUser_id: user to send to. per default me (Florian Kellermann)
:type md_mode: boolean
:param md_mode: if true, parse_mode is markdown
:raises: none
:rtype: none
" " "
if md_mode:
bot.send_message(chat_id=pUser_id, text=pText, parse_mode=" MARKDOWNV2" )
else:
bot.send_message(chat_id=pUser_id, text=pText)< / code > < / pre >
< / details >
< / dd >
< dt id = "telegram_bot.bot_updates.start_updater" > < code class = "name flex" >
< span > def < span class = "ident" > start_updater< / span > < / span > (< span > )< / span >
< / code > < / dt >
< dd >
< div class = "desc" > < p > starting function for regularly sending updates
:raises: none< / p >
< p > :rtype: none< / p > < / div >
< details class = "source" >
< summary >
< span > Expand source code< / span >
< / summary >
< pre > < code class = "python" > def start_updater():
" " " starting function for regularly sending updates
:raises: none
:rtype: none
" " "
print(" Bot updates started" )
my_handler = API_Handler(" https://gruppe1.testsites.info/api" , str(os.getenv(" BOT_EMAIL" )), str(os.getenv(" BOT_PASSWORD" )))
update_crontab(my_handler)< / code > < / pre >
< / details >
< / dd >
< dt id = "telegram_bot.bot_updates.update_based_on_crontab" > < code class = "name flex" >
< span > def < span class = "ident" > update_based_on_crontab< / span > < / span > (< span > p_user_ids, p_user_crontab, p_my_handler)< / span >
< / code > < / dt >
< dd >
< div class = "desc" > < p > Check all the crontab codes and add jobs to start in time
:type p_user_ids: array
:param p_user_ids: user id array of all users< / p >
< p > :type p_user_crontab: array
:param p_user_crontab: crontabs for all users equivalent to the user array< / p >
< p > :type p_my_handler: Api_Handler
:param p_my_handler: get database stuff< / p >
< p > :raises: none< / p >
< p > :rtype: none< / p > < / div >
< details class = "source" >
< summary >
< span > Expand source code< / span >
< / summary >
< pre > < code class = "python" > def update_based_on_crontab(p_user_ids, p_user_crontab, p_my_handler):
" " " Check all the crontab codes and add jobs to start in time
:type p_user_ids: array
:param p_user_ids: user id array of all users
:type p_user_crontab: array
:param p_user_crontab: crontabs for all users equivalent to the user array
:type p_my_handler: Api_Handler
:param p_my_handler: get database stuff
:raises: none
:rtype: none
" " "
my_scheduler = BackgroundScheduler() # schedule sends based on cron
for i in range(len(p_user_ids)):
cron_split = p_user_crontab[i].split(" " ) # split it up to use in scheduler
print(cron_split[4], cron_split[1], cron_split[0], cron_split[3], cron_split[2])
my_scheduler.add_job(update_for_user, ' cron' , day_of_week=cron_split[4], hour=cron_split[1], minute=cron_split[0], month=cron_split[3], day=cron_split[2], args=(p_user_ids[i], p_my_handler))
my_scheduler.start()
time.sleep( 600 ) # scheduler runs in background and I wait 10mins
my_scheduler.shutdown() # after this the new crontabs will be loaded< / code > < / pre >
< / details >
< / dd >
< dt id = "telegram_bot.bot_updates.update_crontab" > < code class = "name flex" >
< span > def < span class = "ident" > update_crontab< / span > < / span > (< span > p_my_handler)< / span >
< / code > < / dt >
< dd >
< div class = "desc" > < p > Updating crontab lists every hour
:type pCurrent_Time: time when starting crontab update
:param pCurrent_Time: datetime< / p >
< p > :raises: none< / p >
< p > :rtype: none< / p > < / div >
< details class = "source" >
< summary >
< span > Expand source code< / span >
< / summary >
< pre > < code class = "python" > def update_crontab(p_my_handler):
" " " Updating crontab lists every hour
:type pCurrent_Time: time when starting crontab update
:param pCurrent_Time: datetime
:raises: none
:rtype: none
" " "
global user_crontab
global user_ids
all_users = p_my_handler.get_all_users() # get all users so crontabs can update for everybody
user_ids = []
user_crontab = []
for element in all_users:
if element[" cron" ] != ' ' and element[" telegram_user_id" ] != ' ' : # check if both values are existing so I have consistent data
try:
user_ids.append(int(element[" telegram_user_id" ]))
try:
user_crontab.append(str(element[" cron" ]))
except:
user_ids.pop() # if something goes wrong with cron I have to delete matching user id
except: continue
print(user_ids)
update_based_on_crontab(user_ids, user_crontab, p_my_handler)
update_crontab(p_my_handler) # restart the update after time sleep< / code > < / pre >
< / details >
< / dd >
< dt id = "telegram_bot.bot_updates.update_for_user" > < code class = "name flex" >
< span > def < span class = "ident" > update_for_user< / span > < / span > (< span > p_user_id, p_my_handler)< / span >
< / code > < / dt >
< dd >
< div class = "desc" > < p > Pull shares and send updates for specific user id
:type p_user_id: integer
:param p_user_id: user id of user that shall receive update< / p >
< p > :type p_my_handler: Api_Handler
:param p_my_handler: handle the api and pull from database< / p >
< p > :raises: none< / p >
< p > :rtype: none< / p > < / div >
< details class = "source" >
< summary >
< span > Expand source code< / span >
< / summary >
< pre > < code class = "python" > def update_for_user(p_user_id, p_my_handler):
" " " Pull shares and send updates for specific user id
:type p_user_id: integer
:param p_user_id: user id of user that shall receive update
:type p_my_handler: Api_Handler
:param p_my_handler: handle the api and pull from database
:raises: none
:rtype: none
" " "
share_symbols = []
share_amounts = []
my_portfolio = p_my_handler.get_user_portfolio(p_user_id) # get all existing shares for user
for element in my_portfolio:
if element[" count" ] != ' ' and element[" isin" ] != ' ' :
print(element[" count" ], element[" isin" ])
share_symbols.append(element[" isin" ])
share_amounts.append(element[" count" ])
my_user = p_my_handler.get_user(p_user_id)
send_to_user(" Hello %s this is your share update for today:" %str(my_user[" username" ]), pUser_id=p_user_id)
shares = p_my_handler.get_user_shares(p_user_id) # all interest shares
if len(share_symbols) != 0: # iterate through all shares
for i in range(len(share_symbols)):
my_price = share_fetcher.get_share_price_no_currency(share_symbols[i])
my_update_message = f' {share_fetcher.get_share_information_markdown(share_symbols[i])}\ncount: {hf.make_markdown_proof(share_amounts[i])}\nTotal: {hf.make_markdown_proof(round(float(my_price) * float(share_amounts[i]), 2))} EUR'
bot.send_message(chat_id=p_user_id, text=my_update_message, parse_mode=" MARKDOWNV2" )
else:
send_to_user(" No shares found for your account. Check https://gruppe1.testsites.info to change your settings and add shares." , pUser_id=p_user_id)
if len(shares) != 0: # Send updates on watchlist shares if existing
send_to_user(" Your watchlist shares:" , pUser_id=p_user_id)
for element in shares:
send_to_user(share_fetcher.get_share_information_markdown(element), pUser_id=p_user_id, md_mode=True)
keywords = p_my_handler.get_user_keywords(p_user_id) # get keywords as array
if (keywords): # if keywords exist and array is not empty
send_to_user(" If you haven' t read yet: \nHere are some interesting news according to your keywords:" , pUser_id=p_user_id)
for keyword in keywords:
news = news_fetcher.get_top_news_by_keyword(keyword)[" articles" ]
keyword = hf.make_markdown_proof(keyword)
if not news: # if empty news array
send_to_user(f" No news found for keyword _{keyword}_\." , pUser_id=p_user_id, md_mode=True)
elif news == None: # if news is none
send_to_user(f" Server error for keyword _{keyword}_\." , pUser_id=p_user_id, md_mode=True)
else:
news_formatted = news_fetcher.format_article(news[0]) # format for message, only use the most popular article
send_to_user(f" _keyword: {keyword}_\n\n{news_formatted}" , pUser_id=p_user_id, md_mode=True) # send news with related keyword in Markdown< / code > < / pre >
< / details >
< / dd >
< / dl >
< / section >
< section >
< / section >
< / article >
< nav id = "sidebar" >
< h1 > Index< / h1 >
< div class = "toc" >
< ul > < / ul >
< / div >
< ul id = "index" >
< li > < h3 > Super-module< / h3 >
< ul >
< li > < code > < a title = "telegram_bot" href = "index.html" > telegram_bot< / a > < / code > < / li >
< / ul >
< / li >
< li > < h3 > < a href = "#header-functions" > Functions< / a > < / h3 >
< ul class = "" >
< li > < code > < a title = "telegram_bot.bot_updates.send_to_user" href = "#telegram_bot.bot_updates.send_to_user" > send_to_user< / a > < / code > < / li >
< li > < code > < a title = "telegram_bot.bot_updates.start_updater" href = "#telegram_bot.bot_updates.start_updater" > start_updater< / a > < / code > < / li >
< li > < code > < a title = "telegram_bot.bot_updates.update_based_on_crontab" href = "#telegram_bot.bot_updates.update_based_on_crontab" > update_based_on_crontab< / a > < / code > < / li >
< li > < code > < a title = "telegram_bot.bot_updates.update_crontab" href = "#telegram_bot.bot_updates.update_crontab" > update_crontab< / a > < / code > < / li >
< li > < code > < a title = "telegram_bot.bot_updates.update_for_user" href = "#telegram_bot.bot_updates.update_for_user" > update_for_user< / a > < / code > < / li >
< / ul >
< / li >
< / ul >
< / nav >
< / main >
< footer id = "footer" >
< p > Generated by < a href = "https://pdoc3.github.io/pdoc" title = "pdoc: Python API documentation generator" > < cite > pdoc< / cite > 0.10.0< / a > .< / p >
< / footer >
< / body >
< / html >