How to continue the code if there is an error? Telethon - telegram

I have a simple program that allows user to join multiple chats/channel. User just inputs links of channels to join. But i have some troubles with channels that are private/not exist/deleted and etc. The program immideatly stops if can't join some chanel, but how can i make the program ignore these errors and continue its work until the end?

Use python simple try and except :
try:
#code
except:
pass

Related

Is there any way to get system messages such as "joined the group" using telebot?

I want to get messages about joined users and delete them. I tried to do this by getting message.new_chat_members but it didn't work. There is no errors in console, just nothing.
def delall(message: types.Message):
bot.delete_message(message.chat.id, message.message_id)

Discord Bot python 3.6 report command

I am making a custom discord bot in python. I am trying to add a !report command.
I am very confused and cant find the answer anywhere. Can anyone help me make it?
I want any user to be able to do !report #example reason.
and save it in a database such as excel or sql3 or preferably in a staff channel.
how would I do this?
I have tried to use on_message()
You could use the on_message() command:
#client.event
async def on_message(message):
if message.content.startswith("!report"):
report_channel = client.get_channel(channel id)
member = text.split(" ")[1]
reason = ' '.join(text.split(" ")[1:])
await report_channel.send(f"Member: {member}, Reason: {reason}")
So the first thing is to look to see if the person used the "!report" command with an if statement.
Next, you find the member by taking the second word of the message.
After that, you find the reason by taking the rest of the words in the message.
Then you send it to the pre-defined report channel on discord.

How can I log sql execution results in airflow?

I use airflow python operators to execute sql queries against a redshift/postgres database. In order to debug, I'd like the DAG to return the results of the sql execution, similar to what you would see if executing locally in a console:
I'm using psycop2 to create a connection/cursor and execute the sql. Having this logged would be extremely helpful to confirm the parsed parameterized sql, and confirm that data was actually inserted (I have painfully experiences issues where differences in environments caused unexpected behavior)
I do not have deep knowledge of airflow or the low level workings of the python DBAPI, but the pscyopg2 documentation does seem to refer to some methods and connection configurations that may allow this.
I find it very perplexing that this is difficult to do, as I'd imagine it would be a primary use case of running ETLs on this platform. I've heard suggestions to simply create additional tasks that query the table before and after, but this seems clunky and ineffective.
Could anyone please explain how this may be possible, and if not, explain why? Alternate methods of achieving similar results welcome. Thanks!
So far I have tried the connection.status_message() method, but it only seems to return the first line of the sql and not the results. I have also attempted to create a logging cursor, which produces the sql, but not the console results
import logging
import psycopg2 as pg
from psycopg2.extras import LoggingConnection
conn = pg.connect(
connection_factory=LoggingConnection,
...
)
conn.autocommit = True
logging.basicConfig(level=logging.DEBUG)
logger = logging.getLogger(__name__)
logger.addHandler(logging.StreamHandler(sys.stdout))
conn.initialize(logger)
cur = conn.cursor()
sql = """
INSERT INTO mytable (
SELECT *
FROM other_table
);
"""
cur.execute(sql)
I'd like the logger to return something like:
sql> INSERT INTO mytable (
SELECT ...
[2019-07-25 23:00:54] 912 rows affected in 4 s 442 ms
Let's assume you are writing an operator that uses postgres hook to do something in sql.
Anything printed inside an operator is logged.
So, if you want to log the statement, just print the statement in your operator.
print(sql)
If you want to log the result, fetch the result and print the result.
E.g.
result = cur.fetchall()
for row in result:
print(row)
Alternatively you can use self.log.info in place of print, where self refers to the operator instance.
Ok, so after some trial and error I've found a method that works for my setup and objective. To recap, my goal is to run ETL's via python scripts, orchestrated in Airflow. Referring to the documentation for statusmessage:
Read-only attribute containing the message returned by the last command:
The key is to manage logging in context with transactions executed on the server. In order for me to do this, I had to specifically set con.autocommit = False, and wrap SQL blocks with BEGIN TRANSACTION; and END TRANSACTION;. If you insert cur.statusmessage directly following a statement that deletes or inserts, you will get a response such as 'INSERT 0 92380'.
This still isn't as verbose as I would prefer, but it is a much better than nothing, and is very useful for troubleshooting ETL issues within Airflow logs.
Side notes:
- When autocommit is set to False, you must explicitly commit transactions.
- It may not be necessary to state transaction begin/end in your SQL. It may depend on your DB version.
con = psy.connect(...)
con.autocommit = False
cur = con.cursor()
try:
cur.execute([some_sql])
logging.info(f"Cursor statusmessage: {cur.statusmessage})
except:
con.rollback()
finally:
con.close()
There is some buried functionality within psycopg2 that I'm sure can be utilized, but the documentation is pretty thin and there are no clear examples. If anyone has suggestions on how to utilize things such as logobjects, or returning join PID to somehow retrieve additional information.

How am I sure that my process has a user interface?

When running a class which can be used interactively or silently by batch, I want to display a hourglass, only if in interactive mode.
I found the function xGlobal::clientKind() , read below, but not sure it is sufficient (can't batches also run on Client ?)
if (xGlobal::clientKind() == ClientType::Client)
startLengthyOperation();
// here do the process
if (xGlobal::clientKind() == ClientType::Client)
endLengthyOperation();
Do not bother to test client kind when using startLengthyOperation, the method does a sufficient test itself.
Testing should be like this:
if (clientKind() == ClientType::Client)
...
Don't use xGlobal::clientKind, use without qualification.
The ClientType has four values, matching what you see in "Online Users".
Batch can be called interactively in Basic/Periodic/Batch, but it should be rarely used.

How do I have my Bot respond with arguments?

So I've built a Telegram bot, which can receive the following commands:
/list
/info 123
This works great, as I can catch /info and pass the additional arguments as ints. But, sadly, the Telegram clients don't see /info 123 as a complete command, but just the /info part. Is there a way to make it recognize the entirety of the command as the command?
I've tried Markdown-ing it: [/info 123](/info 123), but no joy. Is this possible?
I've reached out to #BotSupport with the same question, and he/they/it responded swiftly with the following answer:
Hi, at the moment it is not possible to highlight parameters of a command. I any case, you may can find a workaround if you use correct custom keyboards ;)
— #BotSupport
Custom keyboards may be an option for someone, but not for me. The solution I've gone for is to give the command as /info123. As the bot receives all / commands, I check if the received command starts with info, and if so, I remove the info part. I convert the remaining string/int to arguments, and pass that along to the relevant command.
If you mean to pass the 123 as an argument for your command info and if you happen to use the python-telegram-bot, then here's how you do it:
dispatcher.add_handler(CommandHandler('hello', SayHello, pass_args=True))
According to the documentation: pass_args Determines whether the handler should be passed the arguments passed to the command as a keyword argument called args. It will contain a list of strings, which is the text following the command split on single or consecutive whitespace characters. Default is False.
you can use RegexHandler() to do this.
Here is an example
def info(bot, update):
id = update.message.text.replace('/info_', '')
update.message.reply_text(id, parse_mode='Markdown')
def main():
updater = Updater(TOKEN)
updater.dispatcher.add_handler(RegexHandler('^(/info_[\d]+)$', info))
updater.start_polling()
Usage
The command /info_120 will return 120
and /info_007 will return 007
UPDATE
for newer versions, you may use this method instead!
MessageHandler(filters.Regex(r'^(/info_[\d]+)$'), info)
To get the argument of command you don't even need to use pass_args as said Moein you can simply get it from context.args look at Github page. So you can pass as many arguments as you want and you will get a list of arguments! Here is an example from Github.
def start_callback(update, context):
user_says = " ".join(context.args)
update.message.reply_text("You said: " + user_says)
...
dispatcher.add_handler(CommandHandler("start", start_callback))
ForceReply
Upon receiving a message with this object, Telegram clients will display a reply interface to the user (act as if the user has selected the bot's message and tapped 'Reply'). This can be extremely useful if you want to create user-friendly step-by-step interfaces without having to sacrifice privacy mode.
a simple shot
In this case, a user should send a valid number with /audio command (e.g. /audio 3, if they forgot it, we can inform and force them to do so.
source:
https://core.telegram.org/bots/api#forcereply
This is a fairly rudimentary way of creating kwargs from user input.
Unfortunately, it does require the user to be aware of the fields that can be used as parameters, but if you can provide informative response when the user doesnt provide any detectable kwarg style messages then you could probably make a better experience.
As I say, extremely rudimentary idea, and would probably be achieved faster with the regex filters available. And this would be much more reliable when checking input from the user of the "pesky" variety.
The script relies on || delimiter preceeding the command and as is shown will trim any extra characters like new lines and spaces
You can remove the extra check for commit as this is provided in order to tell the bot that you want to save your input to the database explicitly.
def parse_kwargs(update):
commit = False
kwargs = {}
if update.message:
for args in update.message.text.split('||')[1:]:
for kw_pair in args.split(','):
key, value = kw_pair.split('=')
if key.strip() != 'commit':
kwargs[key.strip()] = value.strip()
elif key.strip() == 'commit' and value.strip().lower() == 'true':
commit = True
return kwargs, commit

Resources