How to import instances of a Class in Python? - python

class Tweeter:
def __init__(self, api_key, api_secret_key, bearer_token, access_token, access_token_secret ):
self.api_key = api_key
self.api_secret_key = api_secret_key
self.bearer_token = bearer_token
self.access_token = access_token
self.access_token_secret = access_token_secret
auth = tweepy.OAuthHandler(self.api_key, self.api_secret_key)
auth.set_access_token(self.access_token, self.access_token_secret)
self.api = tweepy.API(auth)
How can I import an instance of a class from the file in which the instance was created to another .py file.
For example: instance1 = Tweeter(xargument,yargument, zargument)
How do import and/or call the instance that I created in another file without having to import the detail that clutter up the code.

Ideally, you'd use parameters to pass around your API client instance, rather than global application imports
You shouldn't need multiple (numbered) instances of it, either.
from classes import Tweeter # for example
if __name__ == "__main__":
t = Tweeter(...)
some_function(t, some, other, args)

from name_of_your_file_that_Tweeter_is_in import Tweeter
from file_x import Tweeter
instance1 = Tweeter(xargument,yargument, zargument)

As long as you initialize your class instance of Tweeter outside of a function or method, then you should be able to import that instance. Keep in mind that all the code that is not within a function or class is ran whenever you import from that file. For example:
# tweeter.py
Class Tweeter:
...
# This code is ran whenever this file is imported from another file
tweeter = Tweeter(<arguments to pass to the __init__ function>)
# my_file.py
from .tweeter import tweeter # Assuming both files are in the same directory
# now you have the same class instance from the tweeter.py file
print(tweeter)

Related

How can i re-use an initialized class in Python?

I'm trying to access a initialized class in the main application from other modules but don't know how to do it.
Background: i want to update a dataframe with data during the whole execution in the main application.
I have to following application structure (this is an simplified version of the code in my application):
constraints
- test_function.py (separate module which should be able to update the initialized class in the main app)
functions
- helper.py (the class which contains the dataframe logic)
main.py (my main application code)
main.py:
import functions.helper
gotstats = functions.helper.GotStats()
gotstats.add(solver_stat='This is a test')
gotstats.add(type='This is a test Type!')
print(gotstats.result())
import constraints.test_function
constraints.test_function.test_function()
helper.py:
class GotStats(object):
def __init__(self):
print('init() called')
import pandas as pd
self.df_got_statistieken = pd.DataFrame(columns=['SOLVER_STAT','TYPE','WAARDE','WAARDE_TEKST','LOWER_BOUND','UPPER_BOUND','OPTIMALISATIE_ID','GUROBI_ID'])
def add(self,solver_stat=None,type=None,waarde=None,waarde_tekst=None,lower_bound=None,upper_bound=None,optimalisatie_id=None,gurobi_id=None):
print('add() called')
self.df_got_statistieken = self.df_got_statistieken.append({'SOLVER_STAT': solver_stat,'TYPE': type, 'WAARDE': waarde, 'OPTIMALISATIE_ID': optimalisatie_id, 'GUROBI_ID': gurobi_id}, ignore_index=True)
def result(self):
print('result() called')
df_got_statistieken = self.df_got_statistieken
return df_got_statistieken
test_function.py:
import sys, os
sys.path.append(os.getcwd())
def test_function():
import functions.helper
gotstats = functions.helper.GotStats()
gotstats.add(solver_stat='This is a test from the seperate module')
gotstats.add(type='This is a test type from the seperate module!')
print(gotstats.result())
if __name__ == "__main__":
test_function()
In main i initialize the class with "gotstats = functions.helper.GotStats()". After that i can correctly use its functions and add dataframe rows by using the add function.
I would like that test_function() is able to add dataframe rows to that same object but i don't know how to do this (in current code the test_function.py just creates a new class in it's local namespace which i don't want). Do i need to extend the class object with an function to get the active one (like logging.getLogger(name))?
Any help in the right direction would be appreciated.
Make your test_function accept the instance as a parameter and pass it to the function when you call it:
main.py:
import functions.helper
from constraints.test_function import test_function
gotstats = functions.helper.GotStats()
gotstats.add(solver_stat='This is a test')
gotstats.add(type='This is a test Type!')
print(gotstats.result())
test_function(gotstats)
test_function.py:
import sys, os
import functions.helper
sys.path.append(os.getcwd())
def test_function(gotstats=None):
if gotstats is None:
gotstats = functions.helper.GotStats()
gotstats.add(solver_stat='This is a test from the seperate module')
gotstats.add(type='This is a test type from the seperate module!')
print(gotstats.result())

Can't pass variable value from one function to another

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, "")

Best practices using python mock for testing functions within sub modules

So,
consider I have a simple library that I am trying to write unit-tests for. This library talks to a database and then uses that data to call an SOAP API. I have three modules, and a testfile for each module.
dir structure:
./mypkg
../__init__.py
../main.py
../db.py
../api.py
./tests
../test_main
../test_db
../test_api
Code:
#db.py
import mysqlclient
class Db(object):
def __init__(self):
self._client = mysqlclient.Client()
#property
def data(self):
return self._client.some_query()
#api.py
import soapclient
class Api(object):
def __init__(self):
self._client = soapclient.Client()
#property
def call(self):
return self._client.some_external_call()
#main.py
from db import Db
from api import Api
class MyLib(object):
def __init__(self):
self.db = Db()
self.api = Api()
def caller(self):
return self.api.call(self.db.data)
Unit-Tests:
#test_db.py
import mock
from mypkg.db import Db
#mock.patch('mypkg.db.mysqlclient')
def test_db(mysqlclient_mock):
mysqlclient_mock.Client.return_value.some_query = {'data':'data'}
db = Db()
assert db.data == {'data':'data'}
#test_api.py
import mock
from mypkg.api import Api
#mock.patch('mypkg.db.soapclient')
def test_db(soap_mock):
soap_mock.Client.return_value.some_external_call = 'foo'
api = Api()
assert api.call == 'foo'
In the above example, mypkg.main.MyLib calls mypkg.db.Db() (uses third-party mysqlclient) and then mypkg.api.Api() (uses third-party soapclient)
I am using mock.patch to patch the third-party libraries to mock my db and api calls in test_db and test_api separately.
Now my question is, is it recommended to patch these external calls again in test_main OR simply patch db.Db and api.Api? (this example is pretty simple, but in larger libraries, the code becomes cumbersome when patching the external calls again or even using test helper functions that patch internal libraries).
Option1: patch external libraries in main again
#test_main.py
import mock
from mypkg.main import MyLib
#mock.patch('mypkg.db.mysqlclient')
#mock.patch('mypkg.api.soapclient')
def test_main(soap_mock, mysqlcient_mock):
ml = MyLib()
soap_mock.Client.return_value.some_external_call = 'foo'
assert ml.caller() == 'foo'
Option2: patch internal libraries
#test_main.py
import mock
from mypkg.main import MyLib
#mock.patch('mypkg.db.Db')
#mock.patch('mypkg.api.Api')
def test_main(api_mock, db_mock):
ml = MyLib()
api_mock.return_value = 'foo'
assert ml.caller() == 'foo'
mock.patch creates a mock version of something where it's imported, not where it lives. This means the string passed to mock.patch has to be a path to an imported module in the module under test. Here's what the patch decorators should look like in test_main.py:
#mock.patch('mypkg.main.Db')
#mock.patch('mypkg.main.Api')
Also, the handles you have on your patched modules (api_mock and db_mock) refer to the classes, not instances of those classes. When you write api_mock.return_value = 'foo', you're telling api_mock to return 'foo' when it gets called, not when an instance of it has a method called on it. Here are the objects in main.py and how they relate to api_mock and db_mock in your test:
Api is a class : api_mock
Api() is an instance : api_mock.return_value
Api().call is an instance method : api_mock.return_value.call
Api().call() is a return value : api_mock.return_value.call.return_value
Db is a class : db_mock
Db() is an instance : db_mock.return_value
Db().data is an attribute : db_mock.return_value.data
test_main.py should therefore look like this:
import mock
from mypkg.main import MyLib
#mock.patch('mypkg.main.Db')
#mock.patch('mypkg.main.Api')
def test_main(api_mock, db_mock):
ml = MyLib()
api_mock.return_value.call.return_value = 'foo'
db_mock.return_value.data = 'some data' # we need this to test that the call to api_mock had the correct arguments.
assert ml.caller() == 'foo'
api_mock.return_value.call.assert_called_once_with('some data')
The first patch in Option 1 would work great for unit-testing db.py, because it gives the db module a mock version of mysqlclient. Similarly, #mock.patch('mypkg.api.soapclient') belongs in test_api.py.
I can't think of a way Option 2 could help you unit-test anything.
Edited: I was incorrectly referring to classes as modules. db.py and api.py are modules

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!

importing a class from another python file issue

Hi I want to import a class from another file in python, everything works however the class I want to import receives a command line argument. After I import (which is successful) how would I supply that command line argument in the class? (side:note is this a superclass or something? idk what that means)
#class I'm importing
class trend:
def __init__(self):
self.user_name = sys.argv[1] #receives commandline argument
_______________________________________________________________
#class I want to use it in
class game:
def __init__(self):
self.twitter = Twython(APP_KEY, APP_SECRET, OAUTH_TOKEN, OAUTH_TOKEN_SECRET)
def do_something(self):
import filenameforthetrendclass as TC
game = TC.trend() #how do I bring in the commandline argument in here?
It's a bad idea to use sys.argv anywhere but at the top-level (main, if you have one). That's something you should pass in.
First, re-write Trend to take user_name as a parameter to its constructor.
Quick example with just Trend:
class Trend(object):
def __init__(self, user_name):
self.user_name = user_name
trend = Trend(sys.argv[1])
Now integrating the whole concept:
import sys
from filenameforthetrendclass import Trend
class Game(object):
def __init__(self):
self.twitter = Twython(APP_KEY, APP_SECRET, OAUTH_TOKEN, OAUTH_TOKEN_SECRET)
def do_something(self, user_name):
a_trend = Trend(user_name) # was originally 'game = '
def main():
game = Game()
game.do_something(sys.argv[1])
Notes:
I'm using uppercase names for classes
I'm definitely not having a class named game and then using game as a local variable somewhere.

Categories

Resources