Im working on a slack bot using the new slack 2.0 python library. I am new to python decorators and I suspect that is part of my problem.
Here is my code...
#!/opt/rh/rh-python36/root/usr/bin/python
import os
import slack
# instantiate Slack client
slack_token = os.environ['SLACK_BOT_TOKEN']
rtmclient = slack.RTMClient(token=slack_token)
webclient = slack.WebClient(token=slack_token)
# get the id of my user
bot_id = webclient.auth_test()['user_id']
print('Bot ID: {0}'.format(bot_id))
def get_user_info(user_id):
user_info = webclient.users_info(user=user_id)['ok']
return user_info
#slack.RTMClient.run_on(event='message')
def parse_message(**payload):
data = payload['data']
user_id = data['user']
print(get_user_info(user_id))
rtmclient.start()
It outputs the Bot ID(using the webclient) when started but then crashes with RuntimeError: This event loop is already running when I make another call to webclient.
[root#slackbot-01 bin]# scl enable rh-python36 /root/slackbot/bin/slackbot.py
Bot ID: UBT547D31
Traceback (most recent call last):
File "/root/slackbot/bin/slackbot.py", line 24, in <module>
rtmclient.start()
File "/opt/rh/rh-python36/root/usr/lib/python3.6/site-packages/slack/rtm/client.py", line 197, in start
return self._event_loop.run_until_complete(future)
File "/opt/rh/rh-python36/root/usr/lib64/python3.6/asyncio/base_events.py", line 467, in run_until_complete
return future.result()
File "/opt/rh/rh-python36/root/usr/lib/python3.6/site-packages/slack/rtm/client.py", line 339, in _connect_and_read
await self._read_messages()
File "/opt/rh/rh-python36/root/usr/lib/python3.6/site-packages/slack/rtm/client.py", line 390, in _read_messages
await self._dispatch_event(event, data=payload)
File "/opt/rh/rh-python36/root/usr/lib/python3.6/site-packages/slack/rtm/client.py", line 440, in _dispatch_event
self._execute_in_thread(callback, data)
File "/opt/rh/rh-python36/root/usr/lib/python3.6/site-packages/slack/rtm/client.py", line 465, in _execute_in_thread
future.result()
File "/opt/rh/rh-python36/root/usr/lib64/python3.6/concurrent/futures/_base.py", line 425, in result
return self.__get_result()
File "/opt/rh/rh-python36/root/usr/lib64/python3.6/concurrent/futures/_base.py", line 384, in __get_result
raise self._exception
File "/opt/rh/rh-python36/root/usr/lib64/python3.6/concurrent/futures/thread.py", line 56, in run
result = self.fn(*self.args, **self.kwargs)
File "/root/slackbot/bin/slackbot.py", line 22, in parse_message
print(get_user_info(user_id))
File "/root/slackbot/bin/slackbot.py", line 15, in get_user_info
user_info = webclient.users_info(user=user_id)
File "/opt/rh/rh-python36/root/usr/lib/python3.6/site-packages/slack/web/client.py", line 1368, in users_info
return self.api_call("users.info", http_verb="GET", params=kwargs)
File "/opt/rh/rh-python36/root/usr/lib/python3.6/site-packages/slack/web/base_client.py", line 154, in api_call
return self._event_loop.run_until_complete(future)
File "/opt/rh/rh-python36/root/usr/lib64/python3.6/asyncio/base_events.py", line 454, in run_until_complete
self.run_forever()
File "/opt/rh/rh-python36/root/usr/lib64/python3.6/asyncio/base_events.py", line 408, in run_forever
raise RuntimeError('This event loop is already running')
RuntimeError: This event loop is already running
The really confusing part to me is that if I comment out the line that makes the first call to webclient.auth_test(), I have no issues at all. My call to webclient.users_info() works every time rtmclient sends me data.
#!/opt/rh/rh-python36/root/usr/bin/python
import os
import slack
# instantiate Slack client
slack_token = os.environ['SLACK_BOT_TOKEN']
rtmclient = slack.RTMClient(token=slack_token)
webclient = slack.WebClient(token=slack_token)
# get the id of my user
#bot_id = webclient.auth_test()['user_id']
#print('Bot ID: {0}'.format(bot_id))
def get_user_info(user_id):
user_info = webclient.users_info(user=user_id)['ok']
return user_info
#slack.RTMClient.run_on(event='message')
def parse_message(**payload):
data = payload['data']
user_id = data['user']
print(get_user_info(user_id))
rtmclient.start()
[root#slackbot-01 bin]# scl enable rh-python36 /root/slackbot/bin/slackbot.py
True
True
^C[root#slackbot-01 bin]#
I need to get the bot id so that I can make sure it doesnt answer it's own messages. I don't why my code doesnt work after I get the bot id outside of the parse message function with a decorator.
What am I doing wrong here?
The python event loop is a tricky thing to program libraries around and there are some issues with the way the event queue is managed in the 2.0 version of SlackClient. It looks like some improvements were made with 2.1 but it appears to be a work in progress, and I still encounter this. I'd expect there will be future updates to make it more robust.
In the meantime, the following code at the top of your file (use pip to install) usually resolves it for me:
import nest_asyncio
nest_asyncio.apply()
Keep in mind this will alter the way the rest of your application is handling the event queue, if that's a factor.
If you're using RTM, the RTMClient creates a WebClient for you. The handle for it should be getting passed to you in the payload when you handle an event. You can check your ID by looking for the 'open' event which is always dispatched after RTM successfully connects and doing the lookup inside your 'open' event handler.
Related
I want to extract the user stats from unofficial tiktokapi (https://github.com/davidteather/TikTok-Api)
the code i used is below
from TikTokApi.tiktok import TikTokApi
with TikTokApi() as api: # .get_instance no longer exists
for trending_video in api.trending.videos():
user_stats = trending_video.author.info_full['stats']
if user_stats['followerCount'] >= 10000:
print(user_stats)
but i keep on getting this error -
RuntimeError: This event loop is already running
Task exception was never retrieved
future: <Task finished name='Task-5' coro=<Connection.run() done, defined at C:\Users\siddh\anaconda3\lib\site-packages\playwright\_impl\_connection.py:240> exception=NotImplementedError()>
Traceback (most recent call last):
File "C:\Users\siddh\anaconda3\lib\site-packages\playwright\_impl\_connection.py", line 247, in run
await self._transport.connect()
File "C:\Users\siddh\anaconda3\lib\site-packages\playwright\_impl\_transport.py", line 132, in connect
raise exc
File "C:\Users\siddh\anaconda3\lib\site-packages\playwright\_impl\_transport.py", line 120, in connect
self._proc = await asyncio.create_subprocess_exec(
File "C:\Users\siddh\anaconda3\lib\asyncio\subprocess.py", line 236, in create_subprocess_exec
transport, protocol = await loop.subprocess_exec(
File "C:\Users\siddh\anaconda3\lib\asyncio\base_events.py", line 1676, in subprocess_exec
transport = await self._make_subprocess_transport(
File "C:\Users\siddh\anaconda3\lib\asyncio\base_events.py", line 498, in _make_subprocess_transport
raise NotImplementedError
NotImplementedError
i tried using asyncio but the error keeps on coming any fixes to this
please note that if you're running the code in Jupyter Notebook - it won't work. As the documentation of this library says:
Note: Jupyter (ipynb) only works on linux
Paste your code into .py file and try running it as a Python script instead with:
python tiktok_script.py
I've been banging my head against my keyboard for a day now, so I'm giving up and asking for help.
I've got a working consumer using confluence kafka, but I need to make it run as a coroutine so I can get things working with FastAPI. I really wanted to try out AIOKafka for this, but for the life of me, I can't get it to work with a self-signed certificate (this is in our dev env).
Here is the working config for my confluence kafka consumer:
conf = {
"bootstrap.servers": "10.142.252.214:9093",
"group.id": "myConsumerID",
"security.protocol": "SASL_SSL",
"sasl.username": kafkaUser,
"sasl.password": kafkaPass,
"sasl.mechanisms": "PLAIN",
"enable.ssl.certificate.verification": "False",
"on_commit": commit_completed,
"heartbeat.interval.ms": "1000",
"socket.connection.setup.timeout.ms": "10000",
"auto.offset.reset": "earliest"
}
Here is the code I'm trying to use for AIOKafka
async def consume():
cert = "../foo/cert/certificate.pem"
key = "../foo/cert/key.pem"
context2 = ssl.create_default_context()
context2.load_cert_chain(certfile=cert, keyfile=key)
context2.check_hostname = False
context2.verify_mode = CERT_NONE
#context2.ssl_cafile="../foo/cert/CARoot.pem"
context2.ssl_certfile = "cert.pem"
context2.ssl_keyfile = "key.pem"
context2.ssl_password = kafkaKey
context2.ssl_keystore_type = "PEM"
consumer = AIOKafkaConsumer(
'TopicA', 'TopicB',
bootstrap_servers="10.142.252.214:9093",
group_id="myConsumerGroup",
sasl_plain_username="kafkaUser",
sasl_plain_password="kafkaPass",
sasl_mechanism="PLAIN",
security_protocol="SASL_SSL",
ssl_context=context2)
await consumer.start()
try:
# Consume messages
async for msg in consumer:
print("consumed: ", msg.topic, msg.partition, msg.offset,
msg.key, msg.value, msg.timestamp)
finally:
# Will leave consumer group; perform autocommit if enabled.
await consumer.stop()
When I try to run this, I just get the most cryptic errors ever and I can't make any sense on where to start trying to figure out what's wrong.
$ python test-main.py
Traceback (most recent call last):
File "/Users/myUser/.pyenv/versions/3.10.5/lib/python3.10/site-packages/aiokafka/conn.py", line 375, in _on_read_task_error
read_task.result()
File "/Users/myUser/.pyenv/versions/3.10.5/lib/python3.10/site-packages/aiokafka/conn.py", line 518, in _read
resp = await reader.readexactly(4)
File "/Users/myUser/.pyenv/versions/3.10.5/lib/python3.10/asyncio/streams.py", line 706, in readexactly
raise exceptions.IncompleteReadError(incomplete, n)
asyncio.exceptions.IncompleteReadError: 0 bytes read on a total of 4 expected bytes
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "/Users/myUser/scripts/ansible-hello-world/test-main.py", line 165, in <module>
asyncio.run(consume())
File "/Users/myUser/.pyenv/versions/3.10.5/lib/python3.10/asyncio/runners.py", line 44, in run
return loop.run_until_complete(main)
File "/Users/myUser/.pyenv/versions/3.10.5/lib/python3.10/asyncio/base_events.py", line 646, in run_until_complete
return future.result()
File "/Users/myUser/scripts/ansible-hello-world/test-main.py", line 155, in consume
await consumer.start()
File "/Users/myUser/.pyenv/versions/3.10.5/lib/python3.10/site-packages/aiokafka/consumer/consumer.py", line 346, in start
await self._client.bootstrap()
File "/Users/myUser/.pyenv/versions/3.10.5/lib/python3.10/site-packages/aiokafka/client.py", line 210, in bootstrap
bootstrap_conn = await create_conn(
File "/Users/myUser/.pyenv/versions/3.10.5/lib/python3.10/site-packages/aiokafka/conn.py", line 96, in create_conn
await conn.connect()
File "/Users/myUser/.pyenv/versions/3.10.5/lib/python3.10/site-packages/aiokafka/conn.py", line 234, in connect
await self._do_sasl_handshake()
File "/Users/myUser/.pyenv/versions/3.10.5/lib/python3.10/site-packages/aiokafka/conn.py", line 314, in _do_sasl_handshake
auth_bytes = await self._send_sasl_token(
File "/Users/myUser/.pyenv/versions/3.10.5/lib/python3.10/asyncio/tasks.py", line 445, in wait_for
return fut.result()
kafka.errors.KafkaConnectionError: KafkaConnectionError: Connection at 10.142.252.214:9093 closed
Unclosed AIOKafkaConsumer
consumer: <aiokafka.consumer.consumer.AIOKafkaConsumer object at 0x107338670>
I have same error in python code when i start code
I try write telegram bot with python-telegram-bot
This is my code :
from telegram.ext import Updater , CommandHandler , CallbackContext
from telegram import Update
from telegram.chataction import ChatAction
#bot API
token = "*********:*************" #Im hide API
#bot commands and messages
messages_and_commands = {
"start" : "Hello {} {} wellcome to my bot !"
}
def start_bot(update : Update , context : CallbackContext):
chat_id = update.message.chat_id
first_name = update.message.chat.first_name
last_name = update.message.chat.last_name
context.bot.send_chat_action(chat_id=chat_id , action = ChatAction)
context.bot.send_message(chat_id=chat_id , text=messages_and_commands["start"].format(first_name , last_name))
#bot to can start in the telegram
updater = Updater(token=token , use_context=True)
#set command handler
start_robot = CommandHandler('start' , start_bot)
#add dispatcher
updater.dispatcher.add_handler(start_robot)
#start polling to while start
updater.start_polling()
#when i use ctrl+c the bot is finish action in telegram
updater.idle()
And this is my error in when i start bot:
No error handlers are registered, logging exception.
Traceback (most recent call last):
File "/home/hsahfodsauhfda/env/lib/python3.8/site-packages/telegram/ext/dispatcher.py", `line 432, in process_update`
handler.handle_update(update, self, check, context)
File "/home/hsahfodsauhfda/env/lib/python3.8/site-packages/telegram/ext/handler.py", line `156, in handle_update`
return self.callback(update, context)
File "telegram_bot.py", line 16, in start_bot
context.bot.send_chat_action(chat_id=chat_id , action = ChatAction)
File "<decorator-gen-20>", line 2, in send_chat_action
File "/home/hsahfodsauhfda/env/lib/python3.8/site-packages/telegram/bot.py", line 135, in `decorator`
result = func(*args, **kwargs)
File "/home/hsahfodsauhfda/env/lib/python3.8/site-packages/telegram/bot.py", line 1880, in `send_chat_action`
result = self._post('sendChatAction', data, timeout=timeout, api_kwargs=api_kwargs)
File "/home/hsahfodsauhfda/env/lib/python3.8/site-packages/telegram/bot.py", line 245, in `_post`
return self.request.post(f'{self.base_url}/{endpoint}', data=data, timeout=timeout)
File "/home/hsahfodsauhfda/env/lib/python3.8/site-packages/telegram/utils/request.py", `line 352, in post`
body=json.dumps(data).encode('utf-8'),
File "/usr/lib/python3.8/json/__init__.py", line 231, in dumps
return _default_encoder.encode(obj)
File "/usr/lib/python3.8/json/encoder.py", line 199, in encode
chunks = self.iterencode(o, _one_shot=True)
File "/usr/lib/python3.8/json/encoder.py", line 257, in iterencode
return _iterencode(o, 0)
File "/usr/lib/python3.8/json/encoder.py", line 179, in default
raise TypeError(f'Object of type {o.__class__.__name__} '
TypeError: Object of type type is not JSON serializable
I've tried out the code you pasted here locally. Indeed, once I launch the bot and call the "start" handler I get the same error.
If we have a closer look at the error message we can see this line from your code:
context.bot.send_chat_action(chat_id=chat_id , action = ChatAction)
According to the docs, telegram.ChatAction is a "class to provide constants for different chat actions.", hence if you wish to reference a ChatAction you need to explicitly mention one, like ChatAction.TYPING.
So in your case, if you use the send_chat_action function like this:
context.bot.send_chat_action(chat_id=chat_id, action=ChatAction.TYPING)
You should not get the error.
Let me know if it helped!
I am currently trying to use CosmosDB as state storage but encountering some issues when the bot attempts to save the state in CosmosDB.
Below is the code that I am using CosmosDB as the middleware
LOOP = asyncio.get_event_loop()
APP = Flask(__name__)
APP.config.update(VaultConfig.get_config())
APP.wsgi_app = BotTelemetryMiddleware(APP.wsgi_app)
PORT = APP.config["Settings"]["Port"]
INSTRUMENTATION_KEY = APP.config['Settings']["appinsight_instrumentation_key"]
TELEMETRY_CLIENT = ApplicationInsightsTelemetryClient(INSTRUMENTATION_KEY)
SETTINGS = BotFrameworkAdapterSettings(
APP.config["Settings"]["AppId"], APP.config["Settings"]["AppPassword"]
)
cosmos_config = APP.config['COSMOS']
# Create CosmosStorage and ConversationState
cosmos = CosmosDbStorage(CosmosDbConfig(endpoint=cosmos_config['endpoint'], masterkey=cosmos_config['masterKey'],
database=cosmos_config['database'], container=cosmos_config['container'], partition_key='/id'))
# Create MemoryStorage, UserState and ConversationState
USER_STATE = UserState(cosmos)
CONVERSATION_STATE = ConversationState(cosmos)
ADAPTER = BotFrameworkAdapter(SETTINGS)
ADAPTER.on_turn_error = on_error
The error that I am receiving:
Traceback (most recent call last):
File "/bot/venv/lib/python3.7/site-packages/botbuilder/core/bot_adapter.py", line 95, in run_pipeline
context, callback
File "/bot/venv/lib/python3.7/site-packages/botbuilder/core/middleware_set.py", line 69, in receive_activity_with_status
return await self.receive_activity_internal(context, callback)
File "/bot/venv/lib/python3.7/site-packages/botbuilder/core/middleware_set.py", line 79, in receive_activity_internal
return await callback(context)
File "/bot/main.py", line 146, in aux_func
await BOT.on_turn(turn_context)
File "/bot/bots/dialog_bot.py", line 46, in on_turn
await self.conversation_state.save_changes(turn_context, False)
File "/bot/venv/lib/python3.7/site-packages/botbuilder/core/bot_state.py", line 88, in save_changes
await self._storage.write(changes)
File "/bot/venv/lib/python3.7/site-packages/botbuilder/azure/cosmosdb_storage.py", line 196, in write
raise error
File "/bot/venv/lib/python3.7/site-packages/botbuilder/azure/cosmosdb_storage.py", line 168, in write
e_tag = change.e_tag
AttributeError: 'dict' object has no attribute 'e_tag'
Attempting to modify this file /bot/venv/lib/python3.7/site-packages/botbuilder/azure/cosmosdb_storage.py for a temporary patch seems to lead me down a rabbit hole that makes it seems like CosmosDB is not fully implemented/tested to be used yet. Am I doing this right?
There were no current samples to work with.
CosmosDB has been fixed with the following commit: https://github.com/microsoft/botbuilder-python/commit/843edfc1f4c563d58ba639b23f2bb019bdbc381b
I'm getting the following error in one of my Celery workers:
2015-07-21T15:02:04.010066+00:00 app[worker.1]: Traceback (most recent call last):
2015-07-21T15:02:04.010069+00:00 app[worker.1]: File "/app/.heroku/python/lib/python2.7/site-packages/celery/app/trace.py", line 296, in trace_task
2015-07-21T15:02:04.010070+00:00 app[worker.1]: on_chord_part_return(task, state, R)
2015-07-21T15:02:04.010073+00:00 app[worker.1]: deps.delete()
2015-07-21T15:02:04.010074+00:00 app[worker.1]: File "/app/.heroku/python/lib/python2.7/site-packages/celery/result.py", line 773, in delete
2015-07-21T15:02:04.010071+00:00 app[worker.1]: File "/app/.heroku/python/lib/python2.7/site-packages/celery/backends/base.py", line 587, in on_chord_part_return
2015-07-21T15:02:04.010078+00:00 app[worker.1]: File "/app/.heroku/python/lib/python2.7/site-packages/celery/backends/base.py", line 329, in delete_group
2015-07-21T15:02:04.010076+00:00 app[worker.1]: (backend or self.app.backend).delete_group(self.id)
2015-07-21T15:02:04.010079+00:00 app[worker.1]: return self._delete_group(group_id)
2015-07-21T15:02:04.010081+00:00 app[worker.1]: File "/app/.heroku/python/lib/python2.7/site-packages/celery/backends/base.py", line 499, in _delete_group
2015-07-21T15:02:04.010082+00:00 app[worker.1]: self.delete(self.get_key_for_group(group_id))
2015-07-21T15:02:04.010083+00:00 app[worker.1]: File "/app/.heroku/python/lib/python2.7/site-packages/celery/backends/redis.py", line 172, in delete
2015-07-21T15:02:04.010084+00:00 app[worker.1]: self.client.delete(key)
2015-07-21T15:02:04.010085+00:00 app[worker.1]: File "/app/.heroku/python/lib/python2.7/site-packages/redis/client.py", line 824, in delete
2015-07-21T15:02:04.010087+00:00 app[worker.1]: return self.execute_command('DEL', *names)
2015-07-21T15:02:04.010088+00:00 app[worker.1]: File "/app/.heroku/python/lib/python2.7/site-packages/redis/client.py", line 565, in execute_command
2015-07-21T15:02:04.010089+00:00 app[worker.1]: return self.parse_response(connection, command_name, **options)
2015-07-21T15:02:04.010090+00:00 app[worker.1]: File "/app/.heroku/python/lib/python2.7/site-packages/redis/client.py", line 579, in parse_response
2015-07-21T15:02:04.010091+00:00 app[worker.1]: return self.response_callbacks[command_name](response, **options)
2015-07-21T15:02:04.010093+00:00 app[worker.1]: ValueError: invalid literal for int() with base 10: 'QUEUED'
What I find weird is that I see no call to int in the last line of the stack trace. QUEUED probably came in as a worker's status. I'm using it as a custom worker status like this:
#before_task_publish.connect
def update_sent_state(sender=None, body=None, **kwargs):
# the task may not exist if sent using `send_task` which
# sends tasks by name, so fall back to the default result backend
# if that is the case.
task = current_app.tasks.get(sender)
backend = task.backend if task else current_app.backend
logging.debug("Setting status for %s" % body["id"])
backend.store_result(body['id'], None, "QUEUED")
What could be the issue here?
In case it's relevant, here's the code for my task. I only call fetch directly is fetch.
#app.task
def fetch(url_or_urls, subscribe=None):
"""This fetches a (list of) podcast(s) and stores it in the db. It assumes that it only gets called
by Podcast.get_by_url, or some other method that knows whether a given podcast has
already been fetched.
If *subscribe* is given, it should be a User instance to be subscribed to the given podcasts."""
if isinstance(url_or_urls, basestring):
url_or_urls = [url_or_urls]
body = _store_podcasts.s()
if subscribe:
body.link(_subscribe_user.s(user=subscribe))
return chord([_fetch_podcast_data.s(url) for url in url_or_urls])(body)
#app.task
def _fetch_podcast_data(url):
return do_fetch(url) # This function returns a dict of podcast data.
#app.task
def _store_podcasts(podcasts_data):
"""Given a list of dictionaries representing podcasts, store them all in the database."""
podcasts = [Podcast(**pdata) for pdata in podcasts_data]
return Podcast.objects.insert(podcasts)
#app.task
def _subscribe_user(podcasts, user):
"""Subscribe the given users to all the podcasts in the list."""
return user.subscribe_multi(podcasts)
Is there anything else that could be relevant here?
Library versions as shown by pip freeze:
redis==2.10.3
celery==3.1.18
It is hard to debug such a bug without working code. Here is what i think it could be.
Lets start here:
http://celery.readthedocs.org/en/latest/_modules/celery/backends/base.html#BaseBackend.store_result
def store_result(self, task_id, result, status,
traceback=None, request=None, **kwargs):
"""Update task state and result."""
result = self.encode_result(result, status)
self._store_result(task_id, result, status, traceback,
request=request, **kwargs)
return result
It calls ecnode_result. Lets check that out
def encode_result(self, result, status):
if status in self.EXCEPTION_STATES and isinstance(result, Exception):
return self.prepare_exception(result)
else:
return self.prepare_value(result)
It looks like "status" is expected to be something from predefined STATE constants.
Its code is here
http://celery.readthedocs.org/en/latest/_modules/celery/states.html#state
And docs here
http://celery.readthedocs.org/en/latest/reference/celery.states.html
That does not look like they expect to see something like "QUEUED" there. Try one of the predefined.
The redis python packages expects the response from the DEL action to always be an integer, which I assume is the count of deleted rows.
The call to int happens in the last line (return self.response_callbacks[command_name](response, **options)) where self.response_callbacks['DEL'] is equal to int.
As a workaround, you could subclass the redis.client.StrictRedis and set the DEL response callback to something other than int, just make sure you're familiar with the implications.
I got the same error these days. And founded my QUEUED response comes from redis MULTI commands. See https://redis.io/topics/transactions#usage.
It maybe that your are reading response from wrong connection. Maybe in multi-processing / multi-threading / eventlet, etc. Not sure.