Importing a class with its dependencies - python

I am trying to import a class I have created from another file, into my current working file. The class is as follows in this example:
ClassFile
class example_class:
def __init__(self, ticker):
self.df = yf.download(ticker, start='2020-12-31')
def do_something(self):
return something
Then when I go to import it into my working file, and run the code:
WorkingFile
import ClassFile
import yfinance as yf
instance = example_class('MSFT')
I get the following error:
name 'yf' is not defined
I understand that yfinance is not being imported somewhere but, after researching, I have not been able to understand how to import it.
Essentially, I am trying to understand how to import a class from another file alongside the dependencies within said class.

You need to import the symbol where you use it; in ClassFile.
import yahoofinance as yf
class example_class:
def __init__(self, ticker):
self.df = yf.download(ticker, start='2020-12-31')
def do_something(self):
return something
When you import something, it is imported into the current scope, i.e. the current file of code.
In theory, if you left import ... yf in WorkingFile.py, you could say
import WorkingFile
...
self.df = WorkingFile.yf.download(ticker, start='2020-12-31')
though of course in this case, that would create a circular import; and anyway, you don't want to do this - it is completely insane. The entire job of import is to bring in something where you actually need it.
The other way around is how you are supposed to use it; the user of ClassFile should not need to know or care that the implementation uses yfinance internally. A proper class should encapsulate its internals from its users, and only expose functionality that they directly need.
In some scenarios, you need to compromise; for example, if ClassFile is a really thin wrapper around yfinance (let's say it inherits from it and adds a new method sell_MSFT but otherwise works identically) then of course the user needs to be familiar with yfinance anyway, and you can defer to its documentation for most of the functionality. But still, in that case, the import yfinance needs to go where it is actually used; in ClassFile.

You either specifically import the class if you want to use its name without the file classifier (ClassFile) or use the Classifier with the function name. You do NOT have to import the depenency modules. ie
import ClassFile
instance = ClassFile.example_class('MSFT')
or:
from ClassFile import example_class
instance = example_class('MSFT')
I assume yf is imported or declared somehwere in ClassFile. That is put you r yf import statement in ClassFile

Related

How to mock external module calls and test code in the class body

I want to store static information in a class, shared by all the instances. The information is something obtained by using another module, I only want to do this once, eg. let's say that this is what I have in mymodule.py:
import os
MyClass:
bus = os.environ.get('DBUS_SESSION_BUS_ADDRESS', None)
def __init__(self):
pass
How can I test this code and mock os.environ.get to make sure that the call is made correctly?
Since the execution happens at the time of the first import, I would need to reload the module in the test, but even so, I can't have os.environ.get mocked at the right time:
import unittest
from unittest import patch, MagicMock
import importlib
import mymodule
class TestMyClass(unittest.TestCase):
#patch('mymodule.os.environ', spec=['get'])
def test_class_init_patch(self, mock_env):
# Too early - the reload overrides the mock
importlib.reload(mymodule)
mock_env.get.assert_called_once_with('DBUS_SESSION_BUS_ADDRESS', None)
def test_class_init_mock(self):
importlib.reload(mymodule)
# Too late - the class body already executed
mymodule.MyClass.os.environ = MagickMock()
I have managed to come up with two alternatives, that make this testable:
Move the class initialization code into a class method and call it from the class body. I can test this class method in my unit test.
Move the class initialization into the __init__ method, guarded by a flag stored in a class variable so that it is only initialized once on the first instantiation.
While both of these should work just fine, it just feels more clean and straightforward to leave this in the class body if possible.
I have managed to figure out how to do this the right way (I hope)!
If you have imported only the module and not the class, function into your code's namespace, eg.:
like this: import os
and not like this: from os import geteuid
You can do this in your test to patch the os module directly:
import os
import unittest
from unittest import patch
import importlib
import mymodule
class TestMyClass(unittest.TestCase):
#patch('os.environ.get')
def test_class_init_patch(self, mock_env_get):
importlib.reload(mymodule)
mock_env_get.assert_called_once_with('DBUS_SESSION_BUS_ADDRESS', None)
This is described in the official documentation as well:
However, consider the alternative scenario where instead of from a import SomeClass module b does import a and some_function uses a.SomeClass. Both of these import forms are common. In this case the class we want to patch is being looked up in the module and so we have to patch a.SomeClass instead:
More details in the official documentation.
This way the module is being patched directly and reloading your own module doesn't affect the patching.
Once the test has run, the patching of the module is undone as usual, however, keep in mind, that the state of your class remains the same way as it was initialized while the external module was patched, so you might need to reload the module again before you run your other tests.
The easiest way to make sure, that you reclaim your "normal" class state, is to reload the module in your TestCase object's setUp method, eg.:
def setUp(self):
importlib.reload(mymodule)

Why Python doesnt see an existing module

I made an app for analysing data, all in one file, but i read that it needs to be made in objective style. Trying to make it objective I get an error that module doesnt have attribute (which it has)
Tried to disable linting and organise code in a different way but end up with this error all the time
file - analyser.py
import argparse
import helper
class analyser:
def __init__(self):
pass
def cli(self):
#some code
if __name__ == '__main__':
analyser.cli
helper.analyse(arguments)
file - helper.py
import csv
class helper:
def __init__(self):
pass
def analyse(self, arguments):
#code
I get
AttributeError: module 'analyser' has no attribute 'analyse'
The module helper does not have an attribute analyse. However, the class helper does have one. You can do one of the following to access the analyse function:
from helper import helper
...
helper.analyse(arguments)
Or
import helper
...
helper.helper.analyse(arguments)
At the moment, the 2 classes helper and analyser are redundant. You may be better off just using functions. Object-oriented programming is useful in certain circumstances to encapsulate data and for abstraction, but functional programming has its own uses and it is good to know when to use either.

Where to position `import` modules inside an class?

I define a class with multiple methods using standard library.
class Dostuff:
def __init__(self):
pass
def read_book(self):
import os
pass
def listen_music(self):
import os.path
pass
def ask_question(self):
import glob
pass
Where is the suitable place inside a class?
The class will be used as a module for repeated application.
It is good custom to place all your imports at the top of your file. There is a style guide on imports in PEP-8.
https://www.python.org/dev/peps/pep-0008/#imports
In your case:
#!/usr/bin/python3
import os
import os.path
import glob
class Dostuff:
def __init__(self):
pass
def read_book(self):
pass
def listen_music(self):
pass
def ask_question(self):
pass
PEP 8 on imports:
Imports are always put at the top of the file, just after any module comments and docstrings, and before module globals and constants.
You misunderstand the scope of import .
Firstly, It's PEP practice to put module on the top,
secondly and most importantly, it's not about best practice,it works that way.
Every time You import any class or function from your file (or module)
import **run ahead always.
Usually the best practice for importing any type of module is to do it at the top of the file you are writing in. So in your case it would look like this:
import os
import glob
class Dostuff:
def __init__(self):
pass
def read_book(self):
pass
def listen_music(self):
pass
def ask_question(self):
pass

Python Multiple file program

For larger programs, in order to be more organized, I have been looking into dividing my code up into different .py files and having the main file that calls upon those files when needed. I have looked around and seen lots of remarks about creating a directory and a SystemPath for Python. Are those reasonable options for a program that could be distributed between a few computers? As a test, I tried to assemble an example:
This is the class named grades in the same directory as main
class student:
def __init__(self):
self.name = ""
self.score = 0
self.grade = 0
def update(self,name,score,grade):
self.score = score
self.name = name
self.grade = grade
print self.score,self.name,self.grade
s = student()
s.update(name,score,grade)
This is my main script currently:
from grades import score
import random
name = 'carl'
score = random.randrange(0,100)
grade = 11
s = student()
s.score(name,score,grade)
There are some questions I have generally about this method:
Is there a way to import all from different files or do I need to specify each individual class?
If I just had a function, is it possible to import it just as a function or can you only import via a class?
Why is it when I call upon a class, in general, I have to make a variable for it as in the example below?
# way that works
s = student()
s.update(name,score,grade)
# incorrect way
student.update(name,score,grade)
Thank you for your time and thought towards my question.
Yes.
You can import instance of student from other script to main script like this:
from grades import s
# if your first script is called grades.py
import random
name = 'carl'
score = random.randrange(0,100)
grade = 11
# you can directly use it without initializing it again.
s.score(name,score,grade)
2.
If you have a function called test() in grades.py, you can import it in this way:
from grades import test
# then invoke it
test()
3.
This variable stands for the instance of class student. You need this instance to invoke the function inside.
Generally, to divide the source code of a program, Python use module to do that, which corresponds to a *.py file. Then for your 3 questions:
You can import a whole "module content" (function, class, global variables, ...) through import module_name.*
for a function, if it is a function in a class(member method, class method or static method) you can not only import the function, you should import class to use the method; if it is a function under module, you can separately import the function through import module_name.function_name
update is a member function of the student class, so you should use it through an instance. if it is a class method or static method, you can use it through the class name you wrote.
1: Is there a way to import all from different file or do i need to
specify each individual class?
You can use the "wildcard import", but you probably shouldn't. See
Should wildcard import be avoided?
If i just had a function, is it possible to import it just as a
function or can you only import via a class?
Functions can be totally independent of classes in Python.
3.Why is it when i call upon a class in general i have to make a variable for it as in the example below?
You should read up on object-oriented programming. In the basic cases, you have to instantiate instances of a class in order to use that class's functionality. In your example, the class student describes what it means to be a student, and the statement
s = student()
creates a student and names it "s".
I think this should be clear after reading a bit about object-oriented programming.
First, you can use from module import * to import everything like:
hello.py:
def hello():
print 'hello'
def bye():
print 'Bye'
main.py:
from hello import *
hello()
bye()
But it's not a good way, if you have two files, two functions have the same name,
so use
from hello import hello, bye
hello()
bye()
is better, it an example for function ,as same as class.
Third before Second, student is a class, so you have to use an instance object to use the function which with self parameter. If you want to use student.function, the function must be a static method like this:
class Person:
def __init__():
pass
#staticmethod
def Count():
return 1
print Person.Count()
Second, you can import the function in a class file which is independent of the class.
Is there a way to import all from different file or do i need to specify each individual class?
the answer is yes , as python import statement use sys.path (A list of strings that specifies the search path for modules ) you need to add the patht of your modules in sys.path , for example if you want to interact between different computers you can put your modules in public folder and add the path of folder to sys.path :
import sys
sys.path.append( path to public )
If i just had a function, is it possible to import it just as a function or can you only import via a class?
you just need to use from ... import function_name.
Why is it when i call upon a class in general i have to make a variable for it as in the example below?
for this question you just need to read the python Class objects documentation :
Class objects support two kinds of operations: attribute references and instantiation.

What do I import: file_name or class in Python?

I have a file named schedule.py:
class SchedGen:
""" Class creates a pseudo random Schedule.
With 3/4 of total credit point required for graduation"""
def __init__(self, nof_courses=40):
random.seed()
self.courses = {}
self.nof_courses = nof_courses
for i in xrange(nof_courses):
self.courses[i] = college.Course(i)
self.set_rand_cred()
self.set_rand_chance()
self.set_rand_preq_courses()
def set_rand_cred(self):
""" Set random credit to courses uniformly between 2 and 6"""
temp_dict = self.courses.copy()
While importing content of schedule do I do import schedule like:
import schedule
If that's correct how can I access the function set_rand_cred(self) from SchedGen class?
You can either do
import schedule
schedgen = schedule.SchedGen()
schedgen.set_rand_red()
or
from schedule import SchedGen
schedgen = SchedGen()
schedgen.set_rand_red()
This link provides some information how Pythons import statement works.
The set_rand_cred() function is an instance function of the class, so you need to first create a class instance. To create a class instance, you need to be able to access the name of the class. You can do that in two ways.
Here's how to solve the problem using each way:
Importing the module:
import schedule
s = schedule.SchedGen()
s.set_rand_cred()
Importing the class from within the module and putting the class into the local namespace:
from schedule import SchedGen
s = SchedGen()
s.set_rand_cred()
You'd have to first make an instance (using the class's qualified name), then access that function as an attribute of the instance:
import schedule
s = schedule.SchedGen()
s.set_rand_cred()
Like that:
import schedule
schedule_generator = schedule.SchedGen()
schedule_generator.set_rand_cred()
For more information read the Python documentation: http://docs.python.org/2/tutorial/classes.html
That's exactly how you import another module, whether it be third-party or one that you created. Now, one great thing about python is the many ways you can go with this. One being, importing the module, retrieving the class from that, or importing the class by itself.
import schedule
foo = schedule.SchedGen()
returned_var = foo.set_rand_cred()
If you import the class by itself, it's almost exactly the same:
from schedule import SchedGen
foo = SchedGen()
returned_var = foo.set_rand_cred()
You can do this:
import schedule
schedule.SchedGen.set_rand_cred()
But it's more common to do this:
from schedule import SchedGen
SchedGen.set_rand_cred()

Categories

Resources