Using example for strategies that return class instances - python-hypothesis

I have
class A(st.SearchStrategy):
def do_draw(self, data):
return object_a(b=st.integers(), c=st.boolean()...)
class B(st.SearchStrategy):
def do_draw(self, data):
return object_a(d=st.boolean(), e=st.boolean()...)
#given(a=A(), b=B())
def test_A_and_B(a, b):
...
How I make sure that a test case of
a = A(b=5, c=True)
# b can be anything
and a test case of
a = A(b=10, c=True)
b = B(c=True, d=<can be either T or F>)
get generate?
I know about #example. Would this be correct?
#given(a=A(), b=B())
#example(a=A(b=10, c=True), b=B(c=True, d=False)
# not sure how to set d to be either true or false
def test_A_and_B(a, b):
...

DO NOT INHERIT FROM SEARCHSTRATEGY.
It is private, internal code that we might change at any time. You're using it wrong anyway!
Instead, you should compose your strategy from the documented functions in hypothesis.strategies. For example, you can define a strategy for making instances of object_a using builds() like so:
builds(object_a, b=st.integers(), c=st.booleans(), ...)
An #example is a single exact input, so you'd use it twice to check d both True and False:
#example(a=object_a(b=10, c=True), b=object_b(c=True, d=True)
#example(a=object_a(b=10, c=True), b=object_b(c=True, d=False)
If you don't care about the value of b at all, just define an example with the default value for that argument.
All together, that would look like:
#given(
a=builds(object_a, b=st.integers(), c=st.booleans()),
b=builds(object_b, d=st.booleans(), e=st.booleans()
)
#example(a=object_a(b=5, c=True), b=None) # assuming b=None is valid
#example(a=object_a(b=10, c=True), b=object_b(d=True, e=True))
#example(a=object_a(b=10, c=True), b=object_b(d=True, e=False))
def test_A_and_B(a, b):
...
Hope that helps :-)

Related

Setting instance variables explicitly or via function

If we have a instance variable which can be set either randomly or via a list input is it better to set the instance variable explicitly (via a function return) or as a side-effect of a function? E.i., which of the versions below is better?
class A():
def __init__(self, *input):
if input:
self.property = self.create_property_from_input(input)
else:
self.property = self.create_property_randomly()
#staticmethod
def create_property_from_input(input)
# Do something useful with the input.
return result
#staticmethod
def create_property_randomly():
# Do something useful
return result
or
class A():
def __init__(self, *input):
if parents:
self.create_property_from_input(input)
else:
self.create_property_randomly()
def create_property_from_input(self, input)
# Do something useful with the input.
self.property = result
# return None
def create_property_randomly(self):
# Do something useful
self.property = result
# return None
I think that in the first version, it is not strictly needed to set the two create_property-functions as static methods. However, since they do not need to know anything about the instance I thought it was more clear to do it that way. Personally, I tend to think that the first version is more explicit, but the use of static methods tend to make it look more advanced than it is.
Which version would you think is closer to best practices?

Check if method is from class without known string

Trying to check if a method is from a class. It's as simple as:
class Foo:
def bar(self):
return
f = Foo()
ismethod(f.bar, Foo) # Should evaluate to true
Syntax like hasattr(Foo(), 'bar') works if you know the method name, and the same with 'bar' in dir(Foo()); howeveer, I need to be able to pass the method object itself as the argument, not like a string as shown here. In my scenario, I need to tell if a method—passed as an argument—is of a specific class.
In other words: How do I tell if an object is a method of a class, without knowing the name of the object?
You need inspect.ismethod:
import inspect
def just_func(a, b):
return a + b
class SomeClass:
def just_method(self, a, b, c):
return a * b + c
obj = SomeClass()
print(inspect.ismethod(just_func)) # False
print(inspect.ismethod(obj.just_method)) # True
UPD:
Oh sorry, you need to check if it belongs to a particular class, then use:
print('SomeClass' in obj.just_method.__qualname__) # True
print('SomeClass' in just_func.__qualname__) # False
Here's what the function you want might look like:
def ismethod(func, cls):
return cls.__name__ in func.__qualname__ and '.' in func.__qualname__
It actually looks like a duplicate of this.

How to switch between two sets of attribute values, depending on an internal state?

I have a class holding some scientific data. Depending on an internal state, the values of this class can appear as normalized (i.e. unitless), or non-normalized. The values are always stored as normalized, but if the object is set in non-normalized status, the user-accessible properties (and methods) will give the non-normalized values. This way the class appears as non-normalized, while there's no need to duplicate the stored values.
Right now I implemented this using getters. While it works, it gives a lot of repeating structure, and I wonder if there's a more Pythonic way of managing this without overcomplicating things.
Am I doing this right? Is there a more elegant way to switch between two sets of data in a similar fashion?
class CoolPhysicsData(object):
def __init__(self, lambda0, *args, normed=False):
self.lambda0 = lambda0 # some normalization factor (wavelength of some wave)
self.normalized = normed # user can change this state as he pleases
self._normed_tmin, self._normed_tmax, self._normed_r = self.calculate_stuffs(*args)
...
#property
def tmin(self):
if self.normalized:
return self._normed_tmin
else:
return denormalize(self.lambda0, self._normed_tmin, unit_type="time")
#property
def tmax(self):
if self.normalized:
return self._normed_tmax
else:
return denormalize(self.lambda0, self._normed_tmax, unit_type="time")
#property
def r(self):
if self.normalized:
return self._normed_r
else:
return denormalize(self.lambda0, self._normed_r, unit_type="len")
... # about 15 getters alike these
One way is to avoid using properties, and implement __getattr__, __setattr__ and __delattr__. Since you need to know which quantity you're denormalizing, there's really no way to escape definitions: these must be handcoded somewhere. I'd do this way:
class CoolPhysicsData:
def _get_normalization_params(self, value):
# set up how individual properties should be denormalized..
params = {
# 'property_name' : (norm_factor, norm_value, 'unit_type')
'tmin': (self.lambda0, self._normed_tmin, 'time'),
'tmax': (self.lambda0, self._normed_tmax, 'time'),
'r': (self.lambda0, self._normed_r, 'len'),
}
return params[value]
and I would implement __getattr__ something like this:
...
def __getattr__(self, value):
# extract the parameters needed
norm_factor, normed_value, unit_type = self._get_normalization_params(f'{value}')
if self.normed:
return normed_value
else:
return self.denormalize(norm_factor, normed_value, unit_type)
...
Note that you might want to write __setattr__ and __delattr__ too.
One little addition: dataclasses might be useful to you. I'm not sure if *args in your __init__ function is the exact signature, or you just simplified for the sake of the example. If you have known arguments (no varargs), this can be easily turned into a dataclass.
from dataclasses import dataclass, field
#dataclass
class CoolPhysicsData:
lambda0: float
normed: bool = field(default=False)
def __post_init__(self):
# set up some test values for simplicity
# of course you can run custom calculations here..
self._normed_tmin = 1
self._normed_tmax = 2
self._normed_r = 3
def __getattr__(self, value):
norm_factor, normed_value, unit_type = self._get_normalization_params(f'{value}')
if self.normed:
return normed_value
else:
return self.denormalize(norm_factor, normed_value, unit_type)
# you may want to implement the following methods too:
# def __setattr__(self, name, value):
# # your custom logic here
# ...
# def __delattr__(self, name):
# # your custom logic here
# ...
def denormalize(self, v1, v2, v3):
# just for simplicity
return 5
def _get_normalization_params(self, value):
# setup how individual properties should be denormalized..
params = {
# 'property_name' : (norm_factor, norm_value, 'unit_type')
'tmin': (self.lambda0, self._normed_tmin, 'time'),
'tmax': (self.lambda0, self._normed_tmax, 'time'),
'r': (self.lambda0, self._normed_r, 'len'),
}
return params[value]
Is it more pythonic? It's up to you to decide. It surely takes away some repetition, but you introduce a little more complexity, and - in my opinion - it's more prone to bugs.

How to check which function has been returned in python?

I have two methods which take different number of arguments. Here are the two functions:
def jumpMX(self,IAS,list):
pass
def addMX(self,IAS):
pass
I am using a function which will return one of these functions to main.I have stored this returned function in a variable named operation.
Since the number of parameters are different for both,how do I identify which function has been returned?
if(operation == jumpMX):
operation(IAS,list)
elif(operation == addMX):
operation(IAS)
What is the syntax for this?Thanks in advance!
You can identify a function through its __name__ attribute:
def foo():
pass
print(foo.__name__)
>>> foo
...or in your case:
operation.__name__ #will return either "jumpMX" or "addMX" depending on what function is stored in operation
Here's a demo you can modify to your needs:
import random #used only for demo purposes
def jumpMX(self,IAS,list):
pass
def addMX(self,IAS):
pass
def FunctionThatWillReturnOneOrTheOtherOfTheTwoFunctionsAbove():
# This will randomly return either jumpMX()
# or addMX to simulate different scenarios
funcs = [jumpMX, addMX]
randomFunc = random.choice(funcs)
return randomFunc
operation = FunctionThatWillReturnOneOrTheOtherOfTheTwoFunctionsAbove()
name = operation.__name__
if(name == "jumpMX"):
operation(IAS,list)
elif(name == "addMX"):
operation(IAS)
You can import those functions and test for equality like with most objects in python.
classes.py
class MyClass:
#staticmethod
def jump(self, ias, _list):
pass
#staticmethod
def add(self, ias):
pass
main.py
from classes import MyClass
myclass_instance = MyClass()
operation = get_op() # your function that returns MyClass.jump or MyClass.add
if operation == MyClass.jump:
operation(myclass_instance, ias, _list)
elif operation == MyClass.add:
operation(myclass_instance, ias)
However, I must emphasize that I don't know what you're trying to accomplish and this seems like a terribly contrived way of doing something like this.
Also, your python code examples are not properly formatted. See the PEP-8 which proposes a standard style-guide for python.

pytest - default fixture parameter value

I wrote a fixture in pytest which was not parametrized but is used by a lot of tests. Later I needed to parametrize this fixture.
In order to not to have to mark.parametrize all the old tests I did the following:
def ldap_con(request):
try:
server_name = request.param
except AttributeError:
server_name = "ldaps://my_default_server"
c = Connection(server_name, use_ssl=True)
yield c
c.unbind()
Now I can have both:
def test_old(ldap_con):
run_test_to_default_connection(ldap_con)
#pytest.mark.parametrize('ldap_con', ['mynewserver'], indirect=True)
def test_new(ldap_con):
run_test_to_new_connection(ldap_con)
The solution has several drawbacks:
I am catching an arbitrary Attribute Error (there might be another)
It does not take into account named parameters
It is not clear to a reader that there is a default value
Is there a standard way to define a default value for a fixture parameter?
Indirect parametrization is messy. To avoid that, I usually write fixture so that it returns a function. I will end up writing it this way:
def ldap_con():
def _ldap_con(server_name="ldaps://my_default_server"):
c = Connection(server_name, use_ssl=True)
yield c
c.unbind()
return _ldap_con
def test_old(ldap_con):
run_test_to_default_connection(ldap_con())
#pytest.mark.parametrize('server', ['mynewserver'])
def test_new(server):
run_test_to_new_connection(ldap_con(server))

Resources