I have a python class that requires a command line argument:
class SomeClass:
request = sys.argv[1] + ".json"
def __init__(self_:
self.req = request
i'd run someClass.py on the commandline i.e. python someClass 1234, which would set the json to 1234.json.
I want a second class, testClass.py, to be able to test methods inside of the main class. But first, i just want to make sure its connected by printing variables:
from someClass import SomeClass
i = SomeClass()
print(i.req)
if i run python testClass.py (without any input), i get a missing input error,
error: the following arguments are required: input
so if i run python testClass.py 1234, i get
none
i just want to know how to pull the class in and make sure its provided with an argument so i can test individual components inside of it.
Just overwrite request in every test that needs it:
import unittest
from x import SomeClass
class TestClass(unittest.TestCase):
def setUp(self):
SomeClass.request = ''
In general, don't make classes which set themselves up. Make the class take parameters which are not defaulted.
You can always make higher level code which supplies default values.
Don't make your class depend on sys.argv in the first place.
class SomeClass:
def __init__(self, base):
self.req = base + ".json"
Then
from someClass import SomeClass
i = SomeClass(sys.argv[1]) # or any other value
print(i.req)
Related
I'm supplid with script.py file with Python contents of which this is psuedo code:
import pandas as pd
import numpy as np
params = {...}
class SomeClass:
def __init__(self, ab):
self.ab = ab
self.de = None
def main(self):
self.foo()
#staticmethod
def DoSomethingUsefull(abc, params=params):
abc['x'] = abc['Red Fox'].copy()
return some_list(abc);
def foo(self):
self.de = SomeClass.DoSomethingUsefull(self.ab)
self.de['de'] = "de"
I cannot change the contents of the file, just use it as is. Eventually I need to execute the script from external (C#) code, currently trying to run from cmd (Python is installed). My question is how to execute from command line? If it's not possible to execute from command line and a wrapper script is needed, what will it look like?
Using WinPython 3.9.10
as #DeepSpace said, this file just contains a definition of a class, it won't do anything by itself.
You can create a python file that instantiates the class and calls some of it's methods
something like
import SomeClass
ab = {'Red Fox': 42}
myClass = SomeClass(ab) # instantiate the class
myClass.main() # call the main method.
Bear also in mind that you will need to modify the File at least to correct the typos like self.de - None otherwise you won't be able to import the class.
If you are going to modify the file anyway to create the typos (Yeah, I know you said you can't modify it, but you must), you could just make the file "executable" by putting the code outside the class like this:
if __name__ == "__main__":
ab = {'Red Fox': 42}
myClass = SomeClass(ab) # instantiate the class
myClass.main() # call the main method.
This way you don't need an extra file.
I have scenario where I am passing a file name and checking if it has argument start as constructor if it has then I have to create instance of that class.
Consider the example where I have a file named test.py which have three class namely A,B,C now only class A has start parameter others have other different parameter or extra parameter.
#test.py
class A:
def __init__(self, start=""):
pass
class B:
def __init__(self, randomKeyword, start=""):
pass
class C:
def __init__(self):
pass
Now I want to write a script which takes test.py as an argument and create instance of A. Till now my progress is
detail = importlib.util.spec_from_file_location('test.py', '/path/to/test.py')
module = importlib.util.module_from_spec(detail)
spec.loader.exec_module(mod)
Bacially I need to write a program which finds init argument of all class in file and create an instance of file with start as init argument.
As mentioned by #deceze it's not a good idea to instantiate a class on the basis of it's init parameter as we're not sure what is there. But it's possible to do it. So I am posting this answer just so that you know how it can be done.
#test.py
class A:
def __init__(self, start=""):
pass
class B:
def __init__(self, randomKeyword, start=""):
pass
class C:
def __init__(self):
pass
One of the possibility is
#init.py
import importlib.util
from inspect import getmembers, isclass, signature
detail = importlib.util.spec_from_file_location('test.py', '/path/to/test.py')
module = importlib.util.module_from_spec(detail)
spec.loader.exec_module(module)
for name, data in getmembers(mod, isclass):
cls = getattr(mod, name)
parameter = signature(cls.__init__).parameters.keys()
# parameter start
if len(parameter) == 2 and 'start' in parameter:
object = cls(start="Whatever you want")
Ofcourse it's not the best approach so more answer are welcome and if you are in this scenario consider #deceze comment and define a builder.
I have a script that I am currently working on, named exp1.py and it's located in
/project/exp1.py
In this script, I am trying to call a function named computelikelihood(), which is inside the class Class(), which is in script method.py, in a different directory:
/project/methods/c_CLASS/method.py
So, in my code in exp1.py, I do this:
import sys
sys.path.append('/project/methods/c_CLASS/')
Which gets me to the folder where method.py is located, but when I want to call the Class() from the method.py, so that I get the function computelikelihood(), that I actually want, I get error. I try this:
from method import Class
from Class import computelikelihood
But I get ImportError: No module named Class. Can anyone help?
EDIT
This is how the __init__ of my Class looks like:
class Class:
def __init__(self,e2wl,w2el,label_set):
self.e2wl = e2wl
self.w2el = w2el
self.workers = self.w2el.keys()
self.examples = self.e2wl.keys()
self.label_set = label_set
Since you are trying to use a method from a Class, you should do so via the class. Do not import the function alone as it isn't intended to be used as such:
from method import Class
Class.computelikelihood()
However, this only works if computelikelihood is a static/class method:
class Class:
#classmethod
def computelikelihood(cls):
...
# or
#staticmethod
def computelikelihood():
...
If it's an instance method:
class Class:
def computelikelihood(self):
...
You'll need to first instantiate an object of class Class:
from method import Class
classObject = Class()
classObject.computelikelihood()
I have a python script which currently takes a command line argument 'path to the json file' and carries out some cleaning up on the data.
I am writing some unit tests where I am trying to pass path to the json file as an arg. It currently comes up with an error when no arg is passed but when it is passed i get the error:
AttributeError: 'module' object has no attribute 'data' which is data.json.
I want to have three separate unit tests each having a different json file to be passed as an argument.
My code is as follows:
import unittest
import sys
import argparse
class TestTransform(unittest.TestCase):
def test_transform(self,input_filename):
target = __import__("cleaning.py")
transform = target
transform.ARGS(input_filename)
self.assertTrue('Pass')
if __name__ == '__main__':
unittest.main()
If I understood your problem correctly here is what I normally do in this case. I override the setUpClass method and make all the inputs to this class attributes that can be accessed by the tests:
class TestTransform():
#classmethod
def setUpClass(self, file_name):
self.input_filename = file_name
#Some other initialization code here
def test_transform(self):
target = __import__("cleaning.py")
transform = target
transform.ARGS(self.input_filename)
self.assertTrue('Pass')
If you then want to make different tests with different input values you can create other classes by subclassing the TestTransform class (and of course the unittest.TestCase):
class Test1(TestTransform, unittest.TestCase):
#classmethod
def setUpClass(self):
input_filename = 'MyFileName'
#Here call the setUpClass from the TestTransform class
TestTransform.setUpClass(input_filename)
I'd like to test a method, whether it calls a specific method of a temporary internal object or not. (ConfigParser.read)
So the object is created inside, and it's not accessible from the outside after the method exits.
Using python 2.7
In foobar.py
import ConfigParser
class FooBar:
def method(self, filename):
config=ConfigParser.ConfigParser()
config.read(filename)
do_some_stuff()
I'd like to test whether config.read was called.
As I understand, the patch decorator was made for this, but unfortunately the MagicMock object the testcase receives is not the same that is created inside, and I can't get near the object that lives inside the method.
I tried like this:
class TestFooBar(TestCase):
def setUp(self):
self.myfoobar = FooBar()
#mock.patch('foobar.ConfigParser')
def test_read(self,mock_foobar):
self.myfoobar.method("configuration.ini")
assert mock_foobar.called # THIS IS OKAY
assert mock_foobar.read.called # THIS FAILS
mock_foobar.read.assert_called_with("configuration.ini") # FAILS TOO
The problem is:
- mock_foobar is created before the self.myfoobar.method creates the ConfigReader inside.
- when debugging mock_foobar has internal data about the previous calls, but no "read" property (the inner MagicMock for mocking the read method)
Of course one way out is refactoring and giving the .read() or the init() a ConfigReader object, but it's not always possible to change the code, and I'd like to grasp the internal objects of the method without touching the module under test.
You're so close! The issue is that you are mocking the class, but then your test checks that read() is called on that mock class - but you actually expect read() to be called on the instance that is returned when you call the class. The following works - I find the second test more readable than the first, but they both work:
import ConfigParser
from unittest import TestCase
from mock import create_autospec, patch, Mock
class FooBar(object):
def method(self, filename):
config=ConfigParser.ConfigParser()
config.read(filename)
class TestFooBar(TestCase):
def setUp(self):
self.myfoobar = FooBar()
#patch('ConfigParser.ConfigParser')
def test_method(self, config_parser_class_mock):
config_parser_mock = config_parser_class_mock.return_value
self.myfoobar.method("configuration.ini")
config_parser_class_mock.assert_called_once_with()
config_parser_mock.read.assert_called_once_with("configuration.ini")
def test_method_better(self):
config_parser_mock = create_autospec(ConfigParser.ConfigParser, instance=True)
config_parser_class_mock = Mock(return_value=config_parser_mock)
with patch('ConfigParser.ConfigParser', config_parser_class_mock):
self.myfoobar.method("configuration.ini")
config_parser_class_mock.assert_called_once_with()
config_parser_mock.read.assert_called_once_with("configuration.ini")