After submitting queries to a service, I get a dictionary or a list back and I want to make sure it's not empty. I using Python 2.7.
I am surprised of not having any assertEmpty method for the unittest.TestCase class instance.
The existing alternatives just don't look right:
self.assertTrue(bool(d))
self.assertNotEqual(d,{})
self.assertGreater(len(d),0)
Is this kind of a missing method in the Python unittest framework? If yes, what would be the most pythonic way to assert that an iterable is not empty?
Empty lists/dicts evaluate to False, so self.assertTrue(d) gets the job done.
Depends exactly what you are looking for.
If you want to make sure the object is an iterable and it is not empty:
# TypeError: object of type 'NoneType' has no len()
# if my_iterable is None
self.assertTrue(len(my_iterable))
If it is OK for the object being tested to be None:
self.assertTrue(my_maybe_iterable)
"Falsy" values in Python
A falsy (sometimes written falsey) value is a value that is considered false when encountered in a Boolean context.
According to the official doc, the following built-in types evaluate to false:
constants defined to be false: None and False.
zero of any numeric type: 0, 0.0, 0j, Decimal(0), Fraction(0, 1)
empty sequences and collections: '', (), [], {}, set(), range(0)
Therefore, it's possible to check for
non-emptiness with assertTrue() and for
emptiness with assertFalse().
(The official doc has a full list of all available assert methods.)
Clean Code
All those assertTrue() and assertFalse() calls are kind of misleading as we wanted to check for emptiness and one needs to know which types evaluate to false to properly understand what's happening in the test.
So, for the sake of clean code and for better readability, we can simply define our own assertEmpty() and assertNotEmpty() methods like so:
def assertEmpty(self, obj):
self.assertFalse(obj)
def assertNotEmpty(self, obj):
self.assertTrue(obj)
Maybe:
self.assertRaises(StopIteration, next(iterable_object))
All the credit for this goes to winklerrr, I am just extending his idea: have importable mixins for when you need assertEmpty or assertNotEmpty:
class AssertEmptyMixin( object ):
def assertEmpty(self, obj):
self.assertFalse(obj)
class AssertNotEmptyMixin( object ):
def assertNotEmpty(self, obj):
self.assertTrue(obj)
Caveat, mixins should go on the left:
class MyThoroughTests( AssertNotEmptyMixin, TestCase ):
def test_my_code( self ):
...
self.assertNotEmpty( something )
Based on #winklerr's answer and #Merk's comment, I extended the idea for checking whether the given object is a Container in the first place.
from typing import Container
def assertContainerEmpty(self, obj: Container) -> None:
"""Asserts whether the given object is an empty container."""
self.assertIsInstance(obj, Container)
self.assertFalse(obj)
def assertContainerNotEmpty(self, obj: Container) -> None:
"""Asserts whether the given object is a non-empty container."""
self.assertIsInstance(obj, Container)
self.assertTrue(obj)
This means that assertEmpty and assertNotEmpty will always fail if the given object is e.g. a float, or an instance of an user-defined class - no matter if it would properly evaluate to True/False.
A slightly different answer to those already proposed... If specific named assertions are absolutely required, you could subclass TestCase and add methods for new assertions there.
from pathlib import Path
from typing import Container
from unittest import TestCase
class BaseTestCase(TestCase):
def assertIsFile(self, path: str, msg: str=None) -> None:
default_msg = 'File does not exist: {0}'.format(path)
msg = msg if msg is not None else default_msg
if not Path(path).resolve().is_file():
raise AssertionError(msg)
def assertIsEmpty(self, obj: Container, msg: str=None) -> None:
default_msg = '{0} is not empty.'.format(obj)
msg = msg if msg is not None else default_msg
self.assertIsInstance(obj, Container, '{0} is not a container.'.format(obj))
if len(obj) > 0:
raise AssertionError(msg)
def assertIsNotEmpty(self, obj: Container, msg: str=None) -> None:
default_msg = '{0} is empty.'.format(obj)
msg = msg if msg is not None else default_msg
self.assertIsInstance(obj, Container, '{0} is not a container.'.format(obj))
if obj is None or len(obj) == 0:
raise AssertionError(msg)
And then subclass the new BaseTestCase class to use the new assertion methods.
class TestApplicationLoadBalancer(_BaseTestCase):
def setUp(self) -> None:
# These assertions will fail.
self.assertIsFile('does-not-exist.txt')
self.assertIsEmpty(['asdf'])
self.assertIsNotEmpty([])
Just like the built-in unittest assertions, you can pass an error message to these if desired.
class TestApplicationLoadBalancer(_BaseTestCase):
def setUp(self) -> None:
# These assertions will fail.
self.assertIsFile('does-not-exist.txt', 'Foo')
self.assertIsEmpty(['asdf'], 'Bar')
self.assertIsNotEmpty([], 'Baz')
Related
I'm dealing with refactoring code which extensively uses dicts in a circumstance where enums could be used. Unfortunately, to reduce typing the dict keys were abbreviated in a cryptic fashion.
In order to have more meaningful code and fewer string literals as well as a more advanced interface I translated the message dictionary based code into an Enum based code using the same messages.
The message dictionaries looked like the following:
MsgDictionary = {'none': None,
'STJ': 'start_job',
'RPS': 'report_status',
'KLJ': 'kill_job'}
ExecStates = {'none': None,
'JCNS': 'job_could_not_start',
'JSS': 'job_successfully_started',
'JSF': 'job_successfully_finished'}
This, unfortunately lead to cluttered code:
...
self.send_message(id = MsgDictionary["stj"], some_data)
...
msg = self.receive_msg()
if msg.id in (MsgDictionary['STJ'], MsgDictionary['KLJ']):
self.toggle_job()
...
I would merely like to get rid of the string accesses, the cryptic names and the low level interface, like in the following. This send_message should send the str typed value of the Enum not the Enum instance itself.
...
self.send_message(id = MessagesEnum.START_JOB, some_data)
...
msg = self.receive_msg()
if msg.id in (MessagesEnum.START_JOB, MessagesEnum.KILL_JOB):
self.toggle_job()
...
But as in the original case, undefined execution states should still be allowed. This does currently not work. The reason is to not break existing code:
e = ExecStates(None)
-> ValueError: None is not a valid ExecutionStates
And I would like to be able to compare enum instances, e.g.:
e = ExecState[START_JOB]
if e == ExecState[START_JOB]:
pass
if e == ExecState[KILL_JOB]:
pass
Using the following definitions, I believe I'm almost there:
import enum
class _BaseEnum(str, enum.Enum):
#classmethod
def values(cls) -> DictValues:
return cls.__members__.values()
def _generate_next_value_(name: str, *args: object) -> str:
return name.lower()
def __str__(self):
return str(self.value) # Use stringification to cover the None value case
class MessageEnum(_BaseEnum):
NONE = None
START_JOB = enum.auto()
REPORT_STATUS = enum.auto()
KILL_JOB = enum.auto()
class ExecutionState(_BaseEnum):
NONE = None
JOB_COULD_NOT_START = enum.auto()
JOB_SUCCESSFULLY_STARTED = enum.auto()
JOB_SUCCESSFULLY_FINISHED = enum.auto()
However, one problem still remains. How can I deal with None value as well as strings in the enumerations? In my case, all enum items gets mapped to the lowercase of the enum item name. Which is the intended functionality. However, None gets unintendedly mapped to 'None'. This in effect leads to problems at other spots in the existing code which initializes an ExecutionState instance with None. I would like to also cover this case to not break existing code.
When I add a __new__ method to the _BaseEnum,
def __new__(cls, value):
obj = str.__new__(cls)
obj._value_ = value
return obj
I loose the possibility to compare the enumeration instances as all instances compare equal to ``.
My question is, in order to solve my problem, if I can corner case the None either in the _generate_next_value_ or the __new__ method or maybe using a proxy pattern ?
Two things that should help:
in your __new__, the creation line should read obj = str.__new__(cls, value) -- that way each instance will compare equal to its lower-cased name
export your enum members to the global namespace, and use is:
START_JOB, REPORT_STATUS, KILL_JOB = MessageEnum
...
if e is START_JOB: ...
...
if msg.id in (START_JOB, KILL_JOB): ...
I was writing a test case for a function that accepts typing.BinaryIO that comes from fastapi.UploadFile.file.
def upload_binary(data: typing.BinaryIO):
...
I was confused what kind of object do I create that will pass type check. I tried io.StringIO and io.BytesIO, and the only way to check which one will be accepted as typing.BinaryIO was to use IDE's highlighting. It didn't accept StringIO but accepted BytesIO.
So my question - is there a way in Python to manually check if object will be validated with given typing hint.
For example some function like
file1 = StringIO("text")
file2 = BytesIO(b"text")
typing_check(file1, typing.BinaryIO) # >>> False
typing_check(file2, typing.BinaryIO) # >>> True
UPD
Looking at starlette/datastructures.py we have
class UploadFile:
...
file: typing.BinaryIO
def __init__(...):
if self.file is None:
self.file = tempfile.SpooledTemporaryFile(...)
And if you try to test it
s = tempfile.SpooledTemporaryFile()
isinstance(s, typing.BinaryIO) # >>> False
Somehow you can try building basic static type checking decorator using annotations and inspect module.
inspect.signature(fn) can read annotations of function parameters, and you can compare types with isinstance function.
import inspect
def static_type_checker(fn):
spec = inspect.signature(fn)
params = spec.parameters
def inner_fn(*args, **kwargs):
for arg, (name, param) in zip(args, params.items()):
assert isinstance(arg, param.annotation)
for key, value in kwargs.items():
assert isinstance(value, params[key].annotation)
return fn(*args, **kwargs)
return inner_fn
#static_type_checker
def sample(a: int):
print(a)
sample(1) # prints 1
sample("a") # AssertionError
Note that this is not perfect solution. It has many limitations, like when giving various-length arguments. I'm just suggesting basic idea.
In Python 3, I want to limit the permitted values that are passed to this method:
my_request(protocol_type, url)
Using type hinting I can write:
my_request(protocol_type: str, url: str)
so the protocol and url are limited to strings, but how can I validate that protocol_type accepts only limited set of values, e.g. 'http' and 'https'?
One way is to write code in the method to validate that the value passed in is 'http' or 'https', something in the lines of:
if (protocol_type == 'http') or (protocol_type == 'https'):
Do Something
else:
Throw an exception
Which will work fine during runtime, but doesn't provide an indication of a problem while writing the code.
This is why I prefer using Enum and the type-hinting mechanism that Pycharm and mypy implement.
For the code example below you will get a warning in Pycharm from its code-inspection, see attached screenshot.
The screenshot shows that if you enter a value that is not enum you will get the "Expected Type:..." warning.
Code:
"""Test of ENUM"""
from enum import Enum
class ProtocolEnum(Enum):
"""
ENUM to hold the allowed values for protocol
"""
HTTP: str = 'http'
HTTPS: str = 'https'
def try_protocol_enum(protocol: ProtocolEnum) -> None:
"""
Test of ProtocolEnum
:rtype: None
:param protocol: a ProtocolEnum value allows for HTTP or HTTPS only
:return:
"""
print(type(protocol))
print(protocol.value)
print(protocol.name)
try_protocol_enum(ProtocolEnum.HTTP)
try_protocol_enum('https')
Output:
<enum 'ProtocolEnum'>
http
HTTP
I guess you can use decorators, I have a similar situation but I wanted to validate the parameter types:
def accepts(*types):
"""
Enforce parameter types for function
Modified from https://stackoverflow.com/questions/15299878/how-to-use-python-decorators-to-check-function-arguments
:param types: int, (int,float), if False, None or [] will be skipped
"""
def check_accepts(f):
def new_f(*args, **kwds):
for (a, t) in zip(args, types):
if t:
assert isinstance(a, t), \
"arg %r does not match %s" % (a, t)
return f(*args, **kwds)
new_f.func_name = f.__name__
return new_f
return check_accepts
And then use as:
#accepts(Decimal)
def calculate_price(monthly_item_price):
...
You can modify my decorator to achieve what you want.
You can just check if the input is correct in the function:
def my_request(protocol_type: str, url: str):
if protocol_type in ('http', 'https'):
# Do x
else:
return 'Invalid Input' # or raise an error
Why not use a Literal for the method argument?
def my_request(protocol_type: Literal["http","https"], url: str):
Use an if statement that raises an exception if protocol_type isn't in a list of allowed values :
allowed_protocols = ['http', 'https']
if protocol_type not in allowed_protocols:
raise ValueError()
hasattr(obj, attribute) is used to check if an object has the specified attribute but given an attribute is there a way to know where (all) it is defined?
Assume that my code is getting the name of an attribute (or a classmethod) as string and I want to invoke classname.attribute but I don't have the classname.
One solution that comes to my mind is this
def finder(attr):
for obj in globals():
try:
if globals()[obj].__dict__[attr]:
return(globals()[obj])
except:
...
usage:
class Lime(object):
#classmethod
def lfunc(self):
print('Classic')
getattr(finder('lfunc'),'lfunc')() #Runs lfunc method of Lime class
I am quite sure that this is not the best (oe even proper way) to do it. Can someone please provide a better way.
It is always "possible". Wether it is desirable is another history.
A quick and dirty way to do it is to iterate linearly over all classes and check if any define the attribute you have. Of course, that is subject to conflicts, and it will yield the first class that has such a named attribute. If it exists in more than one, it is up to you to decide which you want:
def finder(attr):
for cls in object.__subclasses__():
if hasattr(cls, attr):
return cls
raise ValueError
Instead of searching in "globals" this searches all subclasses of "object" - thus the classes to be found don't need to be in the namespace of the module where the finder function is.
If your methods are unique in teh set of classes you are searching, though, maybe you could just assemble a mapping of all methods and use it to call them instead.
Let's suppose all your classes inehrit from a class named "Base":
mapper = {attr_name:getattr(cls, attr_name) for cls in base.__subclasses__() for attr_name, obj in cls.__dict__.items()
if isinstance(obj, classmethod) }
And you call them with mapper['attrname']()
This avoids a linear search at each method call and thus would be much better.
- EDIT -
__subclassess__ just find the direct subclasses of a class, not the inheritance tree - so it won't be usefull in "real life" - maybe it is in the specifc case the OP has in its hands.
If one needs to find things across a inheritance tree, one needs to recurse over the each subclass as well.
As for old-style classes: of course this won't work - that is one of the motives for which they are broken by default in new code.
As for non-class attributes: they can only be found inspecting instances anyway - so another method has to be thought of - does not seem to be the concern of the O.P. here.
This might help:
import gc
def checker(checkee, maxdepth = 3):
def onlyDict(ls):
return filter(lambda x: isinstance(x, dict), ls)
collection = []
toBeInspected = {}
tBI = toBeInspected
gc.collect()
for dic in onlyDict(gc.get_referrers(checkee)):
for item, value in dic.iteritems():
if value is checkee:
collection.append(item)
elif item != "checker":
tBI[item] = value
def _auxChecker(checkee, path, collection, checked, current, depth):
if current in checked: return
checked.append(current)
gc.collect()
for dic in onlyDict(gc.get_referents(current)):
for item, value in dic.iteritems():
currentPath = path + "." + item
if value is checkee:
collection.append(currentPath)
else:
try:
_auxChecker(checkee, currentPath, collection,
checked, value, depth + 1)
if depth < maxdepth else None
except TypeError:
continue
checked = []
for item, value in tBI.iteritems():
_auxChecker(checkee, item, collection, checked, value, 1)
return collection
How to use:
referrer = []
class Foo:
pass
noo = Foo()
bar = noo
import xml
import libxml2
import sys
import os
op = os.path
xml.foo = bar
foobar = noo
for x in checker(foobar, 5):
try:
y= eval(x)
referrer.append(x)
except:
continue
del x, y
ps: attributes of the checkee will not be further checked, for recursive or nested references to the checkee itself.
This should work in all circumstances, but still needs a lot of testing:
import inspect
import sys
def finder(attr, classes=None):
result = []
if classes is None:
# get all accessible classes
classes = [obj for name, obj in inspect.getmembers(
sys.modules[__name__])]
for a_class in classes:
if inspect.isclass(a_class):
if hasattr(a_class, attr):
result.append(a_class)
else:
# we check for instance attributes
if hasattr(a_class(), attr):
result.append(a_class)
try:
result += finder(attr, a_class.__subclasses__())
except:
# old style classes (that don't inherit from object) do not
# have __subclasses; not the best solution though
pass
return list(set(result)) # workaround duplicates
def main(attr):
print finder(attr)
return 0
if __name__ == "__main__":
sys.exit(main("some_attr"))
I'm a python noob and I'm trying to solve my problems the 'pythonic' way. I have a class, who's __init__ method takes 6 parameters. I need to validate each param and throw/raise an Exception if any fails to validate.
Is this the right way?
class DefinitionRunner:
def __init__(self, canvasSize, flightId, domain, definitionPath, harPath):
self.canvasSize = canvasSize
self.flightId = flightId
self.domain = domain
self.harPath = harPath
self.definitionPath = definitionPath
... bunch of validation checks...
... if fails, raise ValueError ...
If you want the variables to be settable independently of __init__, you could use properties to implement validations in separate methods.
They work only for new style classes though, so you need to define the class as class DefinitionRunner(object)
So for example,
#property
def canvasSize(self):
return self._canvasSize
#canvasSize.setter
def canvasSize(self, value):
# some validation here
self._canvasSize = value
Broadly speaking, that looks like the way you'd do it. Though strictly speaking, you might as well do validation before rather than after assignment, especially if assignment could potentially be time or resource intensive. Also, style convention says not to align assignment blocks like you are.
I would do it like you did it. Except the validating stuff. I would validate in a setter method and use it to set the attributes.
You could do something like this. Make a validator for each type of input. Make a helper function to run validation:
def validate_and_assign(obj, items_d, validators):
#validate all entries
for key, validator in validators.items():
if not validator[key](items_d[key]):
raise ValueError("Validation for %s failed" % (key,))
#set all entries
for key, val in items_d.items():
setattr(obj, key, val)
Which you'd use like this:
class DefinitionRunner:
validators = {
'canvasSize': canvasSize_validator,
'flightId': flightId_validator,
'domain': domain_validator,
'definitionPath': definitionPath_validator,
'harPath': harPath_validator,
}
def __init__(self, canvasSize, flightId, domain, definitionPath, harPath):
validate_and_assign(self, {
'canvasSize': canvasSize,
'flightId': flightId,
'domain': domain,
'definitionPath': definitionPath,
'harPath': harPath,
}, DefinitionRunner.validators)
The validators might be the same function, of course, if the data type is the same.
I'm not sure if this is exactly "Pythonic", but I've defined a function decorator called require_type. (To be honest, I think I found it somewhere online.)
def require_type(my_arg, *valid_types):
'''
A simple decorator that performs type checking.
#param my_arg: string indicating argument name
#param valid_types: list of valid types
'''
def make_wrapper(func):
if hasattr(func, 'wrapped_args'):
wrapped = getattr(func, 'wrapped_args')
else:
body = func.func_code
wrapped = list(body.co_varnames[:body.co_argcount])
try:
idx = wrapped.index(my_arg)
except ValueError:
raise(NameError, my_arg)
def wrapper(*args, **kwargs):
def fail():
all_types = ', '.join(str(typ) for typ in valid_types)
raise(TypeError, '\'%s\' was type %s, expected to be in following list: %s' % (my_arg, all_types, type(arg)))
if len(args) > idx:
arg = args[idx]
if not isinstance(arg, valid_types):
fail()
else:
if my_arg in kwargs:
arg = kwargs[my_arg]
if not isinstance(arg, valid_types):
fail()
return func(*args, **kwargs)
wrapper.wrapped_args = wrapped
return wrapper
return make_wrapper
Then, to use it:
class SomeObject(object):
#require_type("prop1", str)
#require_type("prop2", numpy.complex128)
def __init__(self, prop1, prop2):
pass