Can't pass variable value from one function to another - python

I'm new to Python and tried similar suggestions from here and failed.
I'm writing a script that consists of few functions, the first function will create some of the variables that will be used in other functions (it can't global variables).
When I've tried my script I kept getting NameError for undefined vars.
import boto3
import json
from awsretry import AWSRetry
from botocore.exceptions import ClientError
#AWSRetry.backoff(tries=5)
def instance_details(event, context):    
client = boto3.client('ec2')]
ec2_resource = boto3.resource('ec2')`
alert = event['Records'][0]['Sns']['Message']
instance_id = alert['Trigger']['Dimensions'][0]['value']
instance = ec2_resource.Instance(instance_id)
    return client
#AWSRetry.backoff(tries=5)
def tagging():
instance_type = instance['Reservations'][0]['Instances'][0]['InstanceType']
Why I can't pass the values of instance and client to other functions?
Thanks in advance and sorry for duplicates.

intance_details i believe is lambda handler method. Since you are returing client I believe you should be able to see client value in the variable in which you will be capturing return of this method.
Apart from that, you can try to use Class here and declare these variables in __init__ method. Then create instance of that class in the lambda handler and access these variables. Then you would be able to use these variables in the whole class.
import boto3
class Answer:
def __init__(self):
self.instance = None
self.client = boto3.client('ec2')]
self.ec2_resource = boto3.resource('ec2')
def meth1(self):
# suppose here we want to use the value of instance
# using self.instance you can use the value of instance here
# you can pass the alert from lambda_handler to this method
# as well and do all the computation here too.
print(self.client) # example how to use class variables.
def lambda_handler(event, context):
ans = Answer()
alert = event['Records'][0]['Sns']['Message']
instance_id = alert['Trigger']['Dimensions'][0]['value']
ans.instance = ans.ec2_resource.Instance(instance_id)
# if you want to pass instance id, you can pass in the arguments and
# change the definition of meth1 accordingly.
# Apart form that you can pass the alert in the meth1 too and do all the computation there.
ans.meth1()
if __name__ == "__main__":
lambda_handler(event, "")

Related

How to work around a global variable that invokes some I/O operation?

Suppose I have a module data_provider.py that keeps some code responsible for connecting to external API. In order to establish a connection, an API token needs to be retrieved from the database.
API_TOKEN = get_token_from_database()
class DataProvider:
def __init__(self):
self.api_token = API_TOKEN
def make_query(self):
'''make some request using self.api_token'''
Assuming the code needs to stay in such shape more or less (API_TOKEN being a global variable), what would be a good pattern for retrieving the API_TOKEN from the database?
Obiously now it is not ideal because the module cannot be imported without the database being turned on. Also, I would like to retrieve it only once, not per DataProvider creation.
Should I for example make API_TOKEN load lazily or turn it into a function?
If you have one single DataProvider object in your application, you could simply remove the global variable and load the token in the __init__ method:
class DataProvider:
def __init__(self):
self.api_token = get_token_from_database()
Another possible lazy loading would be to initialize the global token to None and then set it at first instanciation of a DataProvider object
API_TOKEN = None
class DataProvider:
def __init__(self):
global API_TOKEN
if API_TOKEN is None:
API_TOKEN = get_token_from_database()
self.api_token = API_TOKEN
Error processing still omitted for brievety...
I'd probably go with a simple singleton pattern
class DataProvider:
def __init__(self):
self.__api_token = None
def get_token(self):
if self.__api_token is None:
self.__api_token = .....
return self.__api_token
You might want to make get_token(self) into a property token instead. That's a matter of taste.

Is it possible to make a class variable my input outside the class?

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

How to monkey patch an instance method of an external library that uses other instance methods internally?

I need to patch a logic in an instance method of a library I am using.
Sample code for brevity. The process method is using the connect method of the Client library as is but I want to modify it to use a different logic instead of parsing_logic_1. What is the best approach to do this? How do I access the class variables like url if I add a new _patched_connect method in the Usage class?
class Client:
def __init__(self, url)
self.url = url
def connect (self):
if self.url == 'a':
self._parsing_logic_1()
if self.url == 'b':
self._parsing_logic_2()
else:
pass
def _parsing_logic_1(self):
pass
def _parsing_logic_2(self):
pass
def send(self):
pass
# ----separate file --------
class Usage:
def __init__(self, client: Client):
self.client = client
def process(input):
self.client.connect() # the connect method should use a different parsing logic for one case
self.client.send()
You need to import your class and just replace the method with a modified method.
In python you can replace a method dynamically as you wish.
Example:
from x.y.z import Client
def mynewconnect(self):
# your code here
self.url = "..."
pass
Client.connect = mynewconnect

python test delete from mongo

I have a problem with mongo. When I ended my automation tests, I need trash all data and object which I created. I create a script. In this script I delete a rows from a few table. But when I start this, This class doesn't start, where is my problem?
In consol I haven't any message, zero value.
from pymongo import MongoClient
class deleteMongo():
def deleteFirst(self):
client = MongoClient('databaseaddress')
db = client.TableData
db.Employe.delete_one({"name": "EmployeOne"})
def deleteSecond(self):
client = MongoClient('databaseaddress')
db = client.PersonData
db.Person.delete_one({"name": "PersonOne"})
def deleteThird(self):
client = MongoClient('databaseaddress')
db = client.AutoData
db.Auto.delete_one({"name": "AutoThird"})
If I am understanding your question correctly, you are trying to run the script above and it's not doing anything?
If this is your complete module, you are not calling the class at all, but defining the class object.
also the parenthesis in class deleteMongo(): are redundant in a class, since it always inherits the object. On the current setup of this class object, you should use def instead, or setup your class to initialize shared objects of the class.
Based on your current code, try this:
from pymongo import MongoClient
class deleteMongo:
def __init__(self, databaseAddress):
# if the databseAddress is always the same, you can remove it from the arguments
# and hardcode it here
self.client = MongoClient(databaseAddress)
def deleteFirst(self):
db = self.client.TableData
db.Employe.delete_one({"name": "EmployeOne"})
def deleteSecond(self):
db = self.client.PersonData
db.Person.delete_one({"name": "PersonOne"})
def deleteThird(self):
db = self.client.AutoData
db.Auto.delete_one({"name": "AutoThird"})
and then when you need to call one of the class functions, call it like this:
deleteMongo(databaseAddress='someaddress').deleteFirst()

Single instance of class from another module

I come from Java background and most of my thinking comes from there. Recently started learning Python. I have a case where I want to just create one connection to Redis and use it everywhere in the project. Here is how my structure and code looks.
module: state.domain_objects.py
class MyRedis():
global redis_instance
def __init__(self):
redis_instance = redis.Redis(host='localhost', port=6379, db=0)
print("Redus instance created", redis_instance)
#staticmethod
def get_instance():
return redis_instance
def save_to_redis(self, key, object_to_cache):
pickleObj = pickle.dumps(object_to_cache)
redis_instance.set(key, pickleObj)
def get_from_redis(self, key):
pickled_obj = redis_instance.get(key)
return pickle.loads(pickled_obj)
class ABC():
....
Now I want to use this from other modules.
module service.some_module.py
from state.domain_objects import MyRedis
from flask import Flask, request
#app.route('/chat/v1/', methods=['GET'])
def chat_service():
userid = request.args.get('id')
message_string = request.args.get('message')
message = Message(message_string, datetime.datetime.now())
r = MyRedis.get_instance()
user = r.get(userid)
if __name__ == '__main__':
global redis_instance
MyRedis()
app.run()
When I start the server, MyRedis() __init__ method gets called and the instance gets created which I have declared as global. Still when the service tries to access it when the service is called, it says NameError: name 'redis_instance' is not defined I am sure this is because I am trying to java-fy the approach but not sure how exactly to achieve it. I read about globals and my understanding of it is, it acts like single variable to the module and thus the way I have tried doing it. Please help me clear my confusion. Thanks!

Categories

Resources