I'm trying to apply decorator from another class on method in my class...
it is my implementation of this Telegram API wrapper library:
https://github.com/eternnoir/pyTelegramBotAPI
But in my example want to use it not from script - but as method of class like that:
class Bot:
def __init__(self, key):
self.key = key
self.bot=telebot.TeleBot(key)
def start(self):
self.bot.polling()
# Handle '/start' and '/help'
#self.bot.message_handler(commands=['help', 'start'])
def send_welcome(self,message):
self.bot.reply_to(message, """\
Hi there, I am EchoBot. \
I am here to echo your kind words back to you. \
Just say anything nice and I'll say the exact same thing to you!\
""")
# Handle all other messages with content_type 'text' (content_types defaults to ['text'])
#self.bot.message_handler(func=lambda message: True)
def echo_message(message):
self.bot.reply_to(message, message.text)
All self are highlighted ... and certainly not working - will be glad if someone can explain what im doing wrong?
The original example trying to customize is:
import telebot
bot = telebot.TeleBot("TOKEN")
#bot.message_handler(commands=['start', 'help'])
def send_welcome(message):
bot.reply_to(message, "Howdy, how are you doing?")
#bot.message_handler(func=lambda message: True)
def echo_all(message):
bot.reply_to(message, message.text)
bot.polling()
for those who might need it - solution i found - was to put the functions inside Ctor - and not to apply decorators to class methods .... :
class Bot:
def __init__(self, key,greting):
self.key = key
self.bot=telebot.TeleBot(key)
self.greting=greting
# Handle '/start' and '/help'
#self.bot.message_handler(commands=['help', 'start'])
def send_welcome(self, message):
self.bot.reply_to(message,self.greting )
# Handle all other messages with content_type 'text' (content_types defaults to ['text'])
#self.bot.message_handler(func=lambda message: True)
def echo_message(message):
self.bot.reply_to(message, message.text)
def start(self):
x = threading.Thread(name=self.greting, target=self.bot.polling,)
x.start()
self though a keyword is more of a placeholder variable name for the 1st argument for all methods that is always the instance object (except for classmethod where 1st argument is the class itself and staticmethod where there is neither)
For any method, even if you use this instead if self as 1st argument of any method, you can access all the object attributes as this.foo or methods as this.bar().
So technically, you don't have access to the object outside any method. The decorator is at the outer most level where you cannot access object (which is passed only to methods as the 1st argument)
A complex and unnecessary workaround I can think of is to write a static method that will help you catch the self object from argument and then access it's message_handler
I think that proper method is to use lambda functions. You can pass more than one parameter to it and get self from outer scope.
So, i finished with next sample
import telebot
class Telegram:
def __init__(self, token):
self.channel = telebot.TeleBot(token, parse_mode=None)
start_dict = dict(
function=lambda msg, obj=self: obj.start_handler(msg),
filters=dict(
commands=["start"],
)
)
self.channel.add_message_handler(start_dict)
self.channel.polling()
def start_handler(self, message):
print("START command")
test = Telegram("your-token-here")
You can run it from console and it will print START command every time you send /start to it.
You should set object of TeleBot() in method start().
import telebot
from decouple import config as key
class TelegramBot():
def bot(self):
bot = telebot.TeleBot(key('token'))
#bot.message_handler(commands=['start'])
def start(message):
bot.send_message(message.chat.id, "Sup, Sani :)")
bot.polling(none_stop=True)
TelegramBotSpot().bot()
class Variaveis:
def __init__(self):
self.bot = telebot.TeleBot(token='')
#self.bot.message_handler(commands=["start"])
def _process_command_start(message):
self.process_command_start(message)
self.bot.polling(none_stop=True, timeout=123)
#----------------------------------------------------------------------------------------------------------------#
# Começando a programar :
def process_command_start(self, message):
self.bot.send_message(message.chat.id, 'ola mundo')
Variaveis()
Related
I'm attempting to make a small, interchangeable two-button class that I can call in any cog instead of writing out the same code over and over. Everything works fine except for the buttons' labels, which I cannot find out how to assign from the variables. Called as opt1 or self.opt1, it failed since neither are technically "defined" which I do understand, but I can't seem to find any alternatives.
The snippet of the class is as follows:
class twoButton(discord.ui.View):
def __init__(self, author, opt1="Yes", opt2="No", timeout=0):
self.author = author
self.opt1 = opt1
self.opt2 = opt2
super().__init__(timeout=timeout)
#discord.ui.button(label=opt1, style=discord.ButtonStyle.blurple, custom_id="opt1")
async def buttonOne(self, interaction: discord.Interaction, button: discord.ui.Button):
button.style = discord.ButtonStyle.green
self.buttonTwo.style = discord.ButtonStyle.gray
await interaction.response.edit_message(view=self)
#discord.ui.button(label=opt2, style=discord.ButtonStyle.blurple, custom_id="opt2")
async def buttonTwo(self, interaction: discord.Interaction, button: discord.ui.Button):
button.style = discord.ButtonStyle.green
self.buttonOne.style = discord.ButtonStyle.gray
await interaction.response.edit_message(view=self)
async def interaction_check(self, interaction: discord.Interaction):
return interaction.user.id == self.author.id
Is this possible to fix? If so, is there an actual method for getting a variable into a decorator without making a separate class for every use case?
Explanation
You can add the buttons dynamically, using View.add_item. This can be done in __init__, where the definition of the button would have access to the instance attribute.
Important changes:
The button callback only takes interaction as a parameter - you already have access to the button, and the callback is merely a function, not a method (no need for self).
Note the capital 'B' for Button. It's a class's constructor, not a decorator.
Code
class TestView(discord.ui.View):
def __init__(self, example_var):
self.example_var = example_var
super().__init__(timeout=None)
self.add_buttons()
def add_buttons(self):
button_one = discord.ui.Button(label=self.example_var)
async def button_example(interaction: discord.Interaction):
print(self.example_var)
button_one.callback = button_example
self.add_item(button_one)
Reference
discord.ui.View
discord.ui.Button
I'm quite stuck on structuring the code in this scenario. Can anyone help me with this?
| module.py
import asyncio
class Server:
def __init__(self):
self.d = {}
#classmethod
async def create(cls):
self = cls()
await self.func()
return self
async def func(self):
await asyncio.sleep(5) # Some other async code here
self.a = 12
def reg(self, ev):
def decorator(func):
self.d[ev] = func()
retun func
return decorator
def reg2(self, ev, func):
self.d[ev] = func
| main.py
import asyncio
from module import Server
async def main():
ser = await Server.create()
# This would be another way... but i find the other way one neater
serv.reg2('msg', some_handler)
# I want to decorate and register this using
# reg func; but since object is not created yet
# how do i acomplish this?
# #ser.reg('msg')
async def some_handler():
...
if __name__ == "__main__":
asyncio.run(main())
Some key points of my aim:
The function 'some_handler' is never used other than the time for register. That is, the function soley exists to be registered and is not used anywhere else.
Since Server class needs an asynchronous initialisation, it cannot be done globally.
(I dont know whether this point is helpful) Generally only one Server instance is created for a single program. There wont be any other instance even in other modules.
How do I model my code to satisfy this senario? I have mentioned an alternate way to register the function, but I feel I am missing something, as some_handler isn't used anywhere else. I have thought about making Server class into a metaclass to do registering and converting the main() and some_handler() as parts of the metclass's class but I'm seeking for different views and opinions.
I use fbchat module to listen to my message and use my response as an input for a captcha. I have everything figured out except the last line when I want to call my class variable. Any ideas ?
This is my code :
from fbchat import Client
from fbchat.models import *
import fbchat
from fbchat import log, Client
# Subclass fbchat.Client and override required methods
class EchoBot(Client):
def onMessage(self, author_id, message_object, thread_id, thread_type, **kwargs):
self.markAsDelivered(thread_id, message_object.uid)
self.markAsRead(thread_id)
log.info("{} from {} in {}".format(message_object, thread_id, thread_type.name))
# If you're not the author, echo
if author_id != self.uid:
self.send(message_object, thread_id="id", thread_type=ThreadType.USER)
captchaResponse = str(message_object.text) # This is the text it receive
client = EchoBot("mail", "password")
client.listen()
captchaInput = driver.find_element_by_xpath("//input[#id='captchaResponse']")
captchaImage = driver.find_element_by_id("captchaTag")
captchaImage.screenshot("captcha/captcha.png")
captchaImage = cv2.imread('captcha/captcha.png')
captchaInput.send_keys(captchaResponse, Keys.ENTER) # This is where I'm stuck
EDIT:
So the problem was that I needed to add this line at the end of my function before I could do anything else.
Client.stopListening(self)
You're declaring captchaResponse inside onMessage's function scope, meaning it's not available on the outside.
Declare it before the class, then access the outer captchaResponse with the global keyword to override it from inside the function.
captchaResponse = None
class EchoBot(Client):
def onMessage(self, author_id, message_object, thread_id, thread_type, **kwargs):
...
global captchaResponse
captchaResponse = str(message_object.text) # This is the text it receive
Which should then make it available to be used in captchaInput.send_keys.
Related thread on using global variables in a function
This question already has an answer here:
How to access outer attribute class within inner class?
(1 answer)
Closed 3 years ago.
As a title, I have a versatility function in parent class that will share use in child class A.k.A inner class. In below, I need to pass outer_send function from parent class. then, use it with call inner_send function inside Identify class alias child class. The result will output Test.
class Device:
def __init__(self):
self.identify = self.Identify(self.outer_send())
def outer_send(message):
print(message)
def last_error(self):
return self.identify.error_info
class Identify:
def __init__(self, send):
self.inner_send() = send()
def set_error(self, error):
self.error_info = error
device = Device()
device.identify.inner_send('test')
I don't like the pattern and I would recommend designing it differently. However, this does what I think you want to do:
class Device:
def __init__(self):
self.identify = self.Identify(self._send)
def _send(self, message):
print(message)
class Identify:
def __init__(self, _send):
self.send = _send
device = Device()
device.identify.send('test')
A few notes: I renamed outer_send to _send, as I assume you don't want people calling that directly on the Device object - if you do, just rename it send and it still works; the error bit seemed superfluous, so left it out; your outer_send was missing self as a parameter - it doesn't need it, but if you do want to leave it out, annotate the method with #staticmethod to avoid warnings.
everyone. Please see example below. I'd like to supply a string to 'schedule_action' method which specifies, what Bot-class method should be called. In the example below I've represented it as 'bot.action()' but I have no idea how to do it correctly. Please help
class Bot:
def work(self): pass
def fight(self): pass
class Scheduler:
def schedule_action(self,action):
bot = Bot()
bot.action()
scheduler = Scheduler()
scheduler.schedule_action('fight')
Use getattr:
class Bot:
def fight(self):
print "fighting is fun!"
class Scheduler:
def schedule_action(self,action):
bot = Bot()
getattr(bot,action)()
scheduler = Scheduler()
scheduler.schedule_action('fight')
Note that getattr also takes an optional argument that allows you to return a default value in case the requested action doesn't exist.
In short,
getattr(bot, action)()
getattr will look up an attribute on the object by name -- attributes can be data or member methods The extra () at the end calls the method.
You could get the method in a separate step, like this, as well:
method_to_call = getattr(bot, action)
method_to_call()
And you can pass arguments to the method in the usual way:
getattr(bot, action)(argument1, argument2)
or
method_to_call = getattr(bot, action)
method_to_call(argument1, argument2)
I'm not sure if it applies in your situation, but you may consider using a function pointer instead of manipulating the strings.
class Bot:
def work(self):
print 'working'
def fight(self):
print 'fightin'
class Scheduler:
def schedule_action(self,action):
bot = Bot()
action(bot)
scheduler = Scheduler()
scheduler.schedule_action(Bot.fight)
scheduler.schedule_action(Bot.work)
Which prints:
fightin
working
If you can do this, it will give you an error about a misspelled function at compile-time when the code is interpreted instead of during run-time. This could shorten your debug cycle for stupid data-entry errors, especially if the actions are done over a span of time. Nothing sucks more than running something overnight and discovering that you had a syntax error in the morning.
class Scheduler:
def schedule_action(self,action):
bot = Bot()
boundmethod = getattr(bot, action)
boundmethod()
def schedule_action(self,action):
bot = Bot()
bot.__getattribute__(action)()
You can also use a dictionary to map methods to actions. For instance:
ACTIONS = {"fight": Bot.fight,
"walk": Bot.walk,}
class Scheduler:
def schedule_action(self, action):
return ACTIONS[action](Bot())