telebot: How to take a massage in input here? - python

I don't know how to take a message in input here?
#bot.message_handler(commands=['tts'])
def send_text_request(message):
bot.reply_to(message, "Write a phrase")
#input...

You can manage it in two different ways:
Using custom_state, a new feature from recent releases.
After tts command you can set the state of user at 1, with:
bot.set_state(message.from_user.id, '1')
and create a new handler:
#bot.message_handler(state = '1'):
def new_function(message):
....
At the end of the code, add:
from telebot import custom_filters
bot.add_custom_filter(custom_filters.StateFilter(bot))
Source: https://github.com/eternnoir/pyTelegramBotAPI/blob/master/examples/custom_states.py
Another way could be using register_next_step_handler, but honestly I used it only once and then I defined my personal states, because it's a mess. But I itroduce you to it anyway.
Define a new function that will handle the input from the user, so:
def function(message):
....
Change the code you already wrote with the following:
#bot.message_handler(commands=['tts'])
def send_text_request(message):
msg = bot.reply_to(message, "Write a phrase")
bot.register_next_step_handler(msg, function)
That's all!

Related

How to get the current test name in cocotb

I am using cocotb version 1.5.2, and I would like to write an utility function to create reports/plots per test.
MWE: Implementing the get_test_name function so that the following test will print my_wonderful_test.
import cocotb
#cocotb.test()
async def my_wonderful_test(dut):
print(get_test_name(dut));
def get_test_name(dut):
pass # how do I get the current test from here?
You can use "name" attribute :
import cocotb
#cocotb.test()
async def my_wonderful_test(dut):
print(my_wonderful_test.name);
But not sure that exactly you want.
Thank you for the commenters, and thank you #FabienM for trying to give an answer. Thank you for #Tzane for trying to find an answer. You were close.
If you want to know a one liner answer
import cocotb;
def get_test_name():
return cocotb.regression_manager._test.name
but the underline prefix in _test maybe it will break in the future, but for since I was only concerned about version 1.5.2 this is OK for me.
Any way I implemented another method that scans the stack one level at a time and check if the frame is in a cocotb.test decorated function. This is also the method that cocotb uses to _discover_tests
It won't work if the test is in a closure, but I never use that, and I don't know if it is even supported.
import cocotb
import inspect;
import sys
#cocotb.test()
async def test_get_testname(dut):
print('Runnign from test ', get_test_name())
def get_test_name():
try:
return cocotb.regression_manager._test.name
except:
pass
cocotbdir = '/'.join(cocotb.__file__.split('/')[:-1])
frame = sys._getframe();
prev_frame = None
while frame is not None:
try:
# the [documentation](https://docs.python.org/2/library/inspect.html#inspect.getmodule)
# says
# Try to guess which module an object was defined in.
# Implying it may fail, wrapp in a try block and everything is fine
module = inspect.getmodule(frame.f_code)
func_name = inspect.getframeinfo(frame).function
if hasattr(module, func_name):
ff = getattr(module, func_name)
if isinstance(ff, cocotb.test):
return func_name
except:
pass
prev_frame = frame;
frame = frame.f_back;
# return None if fail to determine the test name
I don't know why my questions are so badly received
It was something simple that I preferred to engage more people

Use variables of imported files

So I have this file with the following code
async def check_server_restriction(ctx):
restriction = await get_restriction()
global check
if restriction[str(ctx.channel.id)]["Server"] == 1:
await ctx.send("This command is restricted. You can use it in the #bot-commands channel")
check = True
And I have another file that looks like this:
from channel_restrictions_functions import test_187, new_restriction, get_restriction, check_server_restriction, check
class whois(commands.Cog):
def __init__(self, client):
self.client = client
#commands.command()
async def whois(self, ctx, member:discord.Member = None):
await test_187()
await new_restriction(ctx)
await check_server_restriction(ctx)
#print(check)
if check == True:
print("Nicht perint")
return
So basically I import the function and try to import the variable too. The problem is now when the imported function gets activated and turns check (the variable) True (in theory) nothing happens. It should work like this when the thing is in the list it should send "This command is restricted" and set check true so that in my command the if statement works and it will return.
I dont get whats the mistake. I think it says check = False every time but it should be true
I hope you can understand my problem and you know how to fix it
thx for the help
Even global variables are not truly global, they are global only within the scope of their own module. There are ways to get around this restriction and share a variable between modules, if you absolutely have to, see e.g. here. It is recommended to put all global variables into a separate module and import from there, however, see the Python docs for more on this.
That said, why would you want to do this with a global variable? It's simpler and less error prone (in the sense that the restriction status would be shared between commands if global, which might lead to commands being falsely restricted) to just have check_server_restriction return True or False and then check the return value of the function something like this:
async def check_server_restriction(ctx):
restriction = await get_restriction()
if restriction[str(ctx.channel.id)]["Server"] == 1:
await ctx.send("This command is restricted. You can use it in the #bot-commands channel")
return True
return False
In your code, you'd then use this modified function like so:
if await check_server_restriction(ctx): # the == True can be omitted
print("Nicht perint")
return

Python UnitTest - How can I access subTests messages without having to write them manually?

A little bit of context: I am using Python and Selenium for QA Web Automation and I am using the Page Object Model pattern.
I am currently in the process of making the logger part of the system, and I want to make the code more efficient, without
having to write a lot of dublicate code. I checked the docs for subTests, but can't find anything in particular and this is the reason I am here. So I am wondering if there is a way to access this part of the code (so I don't have to
write each logger message each time, which is not very practical):
class TestScenario(unittest.TestCase):
.... # set Up class
def logger(self,info):
logger.error(f"Error happened at {info}")
def test_method(self):
with self.subTest("MESSAGE"):---------------------------------------------
|
try: |
... something |
except AssertionError: |
self.logger(#Is there a way to access subTest msg parameter?) <---
raise
.... other subTests which will follow the same pattern
Thank you in advance!
You can do self.logger(self._subtest._message) to get the message.
Beware, you are accessing internals variable of unittest thus this code can be broken in the next release of python without warning.
Possible approach:
class Message:
def __init__(self, message=''):
self.message = message
def __str__(self):
return self.message
# separate message for every subtest or one message continually modified between subtests
msg = Message('qwe')
...
with self.subTest(msg=msg):
msg.message = 'asd' # access or modify
self.assertTrue(True)
...
Or you may create attribute message in the setUp method of the test and use it to pass message into subTest and access/modify when you need.

Callbacks and events in python

I'm making a bot to link IRC and DC (direct connect) together. There is an existing implementation in C++ I've been following, but it doesn't have all the feature's we're after.
I'm using an IRC library for python which is really well coded. I can register some callback handlers for various IRC events (specifically receiving a public message). This callback function is able to reference objects created in the main python execution from the thread within the IRC library.
Here are my callbacks:
def on_connect(connection, event):
connection.join(ircSettings['channel'])
def on_disconnect(connection, event):
sys.exit()
def on_pubmsg(connection, event):
hubClient.sendMessage(event.source.split('!')[0] + ': ' + event.arguments[0])
And here's how I set them up:
# Create the IRC client
ircClient = irc.client.IRC()
try:
ircConnection = ircClient.server().connect(ircSettings['server'], ircSettin$
except irc.client.ServerConnectionError, x:
print x
sys.exit()
# Set the IRC event handlers
ircConnection.add_global_handler("welcome", on_connect)
ircConnection.add_global_handler("pubmsg", on_pubmsg)
ircConnection.add_global_handler("disconnect", on_disconnect)
I really like this solution, as it makes for very tidy code (particularly in this example). However, I have no idea how to modify my DC library to generate these events.
The main point of interest is the callback's ability to reference the hubClient, which is created in the main python program like so:
# Create the DC client
hubClient = DC.DirectConnect(dcSettings)
hubClient.connect(dcSettings['hub'])
Initially, I passed a function pointer to my DC library to run whenever a message is received:
def messageHandler(nick, msg):
if nick is not ircSettings['nick']:
ircConnection.privmsg(ircSettings['channel'], nick + ': ' + msg)
dcSettings = {
'nick': 'dans_bot',
'sharesize': 10*1024**3, # 10GB
'ip': '0.0.0.0', # XXX: This might not matter, but needed for library
'hub': ('192.168.1.129', 411),
'handler': messageHandler
}
But I get the error:
NameError: global name 'ircConnection' is not defined
How can I set up my DC client to create a callback in a way that I can still reference these local (to the main execution) objects?
Edit: I added a declaration for 'ircConnection'.
I suppose ircConnection is a third party module. And a simple import of that module may solve this error of global nameircConnectionis not defined. Try import ircConnection in your main module
The only problem in your code is that the reference to ircConnection is first seen inside the try-except block and if it fails then the var will be None. Just write ircConnection = None before try.
# Create the IRC client
ircClient = irc.client.IRC()
ircConnection = None
try:
ircConnection = ircClient.server().connect(ircSettings['server'], ircSettin$
except irc.client.ServerConnectionError, x:
print x
sys.exit()
# Set the IRC event handlers
ircConnection.add_global_handler("welcome", on_connect)
ircConnection.add_global_handler("pubmsg", on_pubmsg)
ircConnection.add_global_handler("disconnect", on_disconnect)

Why does globalising a boolean not work but globalising a dictionary does

This is just a question wondering why this doesn't work. I have figured out a better way, but I don't know why previously it wasn't working.
global mydict
mydict = {}
This seems to work fine, and has made the mydict dictionary global. I even print mydict and it works. However, doing this:
global bool
bool = False
Does not seem to work. If trying to print bool in my code, I get:
UnboundLocalError: local variable 'bool' referenced before assignment
So why does it work for the dictionary and not the boolean?
Oh, also, if anyone was wondering how I figured out a better way, I initialised a class and made bool global in the class by doing: self.bool = False which worked. I got it from this question: Making all variables global
EDIT: As requested, I'll post the necessary code:
import chatbot
global mydict
mydict = {}
global haveamessage
haveamessage = False
class MyBot(chatbot.ChatBot):
def __init__(self, username, password, site):
chatbot.ChatBot.__init__(self,username,password,site)
def on_message(self, c, e):
print mydict
print haveamessage
if __name__ == '__main__':
bot = MyBot("MyUsername", "MyPassword", "MySite")
bot.start()
I'll try explain this code. Pretty much the chatbot module is to allow users to create bots in wikis on Wikia, a company that allows wikis to be created which anyone can edit. On a wiki there is a chat extension where users can talk to. This script allows a bot to join the chat and do commands. on_message() goes off when someone posts something in the Chat.
So this prints:
{}
Traceback (most recent call last):
File "file.py", line 146, in <module>
bot.start()
File "/Library/Python/2.7/site-packages/chatbot.py", line 371, in start
self.on_message(self.c, e)
File "file.py", line 12, in on_message
print haveamessage
UnboundLocalError: local variable 'haveamessage' referenced before assignment
I'd like to clarify that the reason this isn't producing an error for all of you is because you are not in a Wikia chat. the function on_message() only runs when someone posts something in the Chat. For example, I may have:
def on_message(self, c, e):
if e.text == 'hello': # e.text is what a user posts in the chat. e = event
c.send('Hello!') # c.send simply sends back a message in the chat. c = connection
So when someone posts in chat hello, the Bot posts back Hello!
The code you've posted does not produce the error you claim it does. However using the global keyword outside of a function has no effect, so it's not surprising that it doesn't work like you expect.
I assume that in your real code, you're actually trying to assign to haveamessage inside on_message. If so, you need a global statement inside that method.
Basically the rule is: If you try to assign a global variable from within a function, you need to use the global keyword within that function. Otherwise you don't need the global keyword at all. Whether or not the variable is a boolean makes no difference.
I believe what you want to do is define the global variables, but then in your function reference them so you can use them locally:
import chatbot
mydict = {}
haveamessage = False
class MyBot(chatbot.ChatBot):
def __init__(self, username, password, site):
chatbot.ChatBot.__init__(self,username,password,site)
def on_message(self, c, e):
global mydict
global haveamessage
print mydict
print haveamessage

Categories