diff --git a/testdata/base.py b/testdata/base.py index 77c82b0..490a92e 100644 --- a/testdata/base.py +++ b/testdata/base.py @@ -1,6 +1,8 @@ from copy import deepcopy +from .compat import implements_iterator from .errors import MissingElementAmountValue, FactoryStartedAlready, MissingRequiredFields +@implements_iterator class Factory(object): """ The base class of all the factories. @@ -18,7 +20,7 @@ def __iter__(self): return self - def next(self): + def __next__(self): if self.current_index >= self.element_amount: raise StopIteration @@ -123,7 +125,7 @@ def set_element_amount(self, element_amount): self._factory.set_element_amount(element_amount * self._elements_per_list) def __call__(self): - return [self._factory.next() for i in xrange(self._elements_per_list)] + return [next(self._factory) for i in range(self._elements_per_list)] class Callable(Factory): """ @@ -158,12 +160,11 @@ class DependentCallable(DependentField): ... x = testdata.CountingFactory(100) ... y = testdata.CountingFactory(1) ... sum = DependentCallable(sum_fields, ['x', 'y']) + >>> got = [] >>> for i in A().generate(4): - ... print i['x'], i['y'], i['sum'] - 100 1 101 - 101 2 103 - 102 3 105 - 103 4 107 + ... got.append((i['x'], i['y'], i['sum'])) + >>> got == [(100, 1, 101), (101, 2, 103), (102, 3, 105), (103, 4, 107)] + True """ def __init__(self, callable_obj, fields=[]): super(DependentCallable, self).__init__(fields) @@ -189,11 +190,13 @@ class ClonedField(DependentField): >>> [result] = [i for i in Foo().generate(1)] >>> result['id'] == result['cloned_id'] True - >>> class Bar(testdata.DictFactory): - ... id = testdata.CountingFactory(0) - ... cloned_id = ClonedField("_id") - Traceback (most recent call last): - UnmetDependentFields: The fields: set(['cloned_id']) - depend on fields that aren't defined! + >>> try: + ... class Bar(testdata.DictFactory): + ... id = testdata.CountingFactory(0) + ... cloned_id = ClonedField("_id") + ... raise AssertionError('not raise UnmetDependentFields') + ... except testdata.errors.UnmetDependentFields: + ... pass """ def __init__(self, cloned_field_name): super(ClonedField, self).__init__([cloned_field_name]) diff --git a/testdata/childrentree.py b/testdata/childrentree.py index ed3563e..9648028 100644 --- a/testdata/childrentree.py +++ b/testdata/childrentree.py @@ -47,7 +47,7 @@ def __getitem__(self, key): def update(self, factories_dct): dependent_factories = {} - for key, value in factories_dct.iteritems(): + for key, value in factories_dct.items(): if issubclass(type(value), DependentField): dependent_factories[key] = value continue diff --git a/testdata/compat.py b/testdata/compat.py new file mode 100644 index 0000000..f97c153 --- /dev/null +++ b/testdata/compat.py @@ -0,0 +1,30 @@ +import sys + + +PY2 = sys.version_info[0] == 2 + +if PY2: + def implements_iterator(cls): + cls.next = cls.__next__ + del cls.__next__ + return cls +else: + implements_iterator = lambda x: x + + +def with_metaclass(meta, *bases): + """Create a class with a metaclass. + + Source: http://lucumr.pocoo.org/2013/5/21/porting-to-python-3-redux/ + + """ + + class metaclass(meta): + __call__ = type.__call__ + __init__ = type.__init__ + + def __new__(cls, name, this_bases, d): + if this_bases is None: + return type.__new__(cls, name, (), d) + return meta(name, bases, d) + return metaclass('temporary_class', None, {}) diff --git a/testdata/dictionary.py b/testdata/dictionary.py index 6727f95..aa57728 100644 --- a/testdata/dictionary.py +++ b/testdata/dictionary.py @@ -1,8 +1,9 @@ from copy import deepcopy, copy from .base import Factory from .metaclasses import DictFactoryBuilder +from .compat import with_metaclass -class DictFactory(Factory): +class DictFactory(with_metaclass(DictFactoryBuilder, Factory)): """ One of the most useful and basic factories. This factory is meant to be subclassed, and other factories should be defined @@ -17,10 +18,9 @@ class DictFactory(Factory): ... age = testdata.RandomInteger(10, 10) ... gender = testdata.RandomSelection(['male']) >>> [result] = [i for i in Users().generate(1)] - >>> result - {'gender': 'male', 'age': 10, 'id': 10} + >>> result == {'id': 10, 'age': 10, 'gender': 'male'} + True """ - __metaclass__ = DictFactoryBuilder def __init__(self, **factories): super(DictFactory, self).__init__() @@ -43,13 +43,13 @@ def _get_oldest_generation(self): def __call__(self): result = {} - for factory_name, factory in self._child_factories[0].iteritems(): + for factory_name, factory in self._child_factories[0].items(): result[factory_name] = factory() # now we call all Factories subclassing the DependentField - for i in xrange(1, self._oldest_generation + 1): + for i in range(1, self._oldest_generation + 1): generation_result = {} - for factory_name, factory in self._child_factories[i].iteritems(): + for factory_name, factory in self._child_factories[i].items(): factory.update_depending(result) generation_result[factory_name] = factory() @@ -59,12 +59,12 @@ def __call__(self): def increase_index(self): super(DictFactory, self).increase_index() - for i in xrange(self._oldest_generation + 1): + for i in range(self._oldest_generation + 1): for child_factory in self._child_factories[i].values(): child_factory.increase_index() def set_element_amount(self, new_element_amount): super(DictFactory, self).set_element_amount(new_element_amount) - for i in xrange(self._oldest_generation + 1): + for i in range(self._oldest_generation + 1): for child_factory in self._child_factories[i].values(): child_factory.set_element_amount(new_element_amount) diff --git a/testdata/extra/mongodb.py b/testdata/extra/mongodb.py index 322bc9c..ab632d4 100644 --- a/testdata/extra/mongodb.py +++ b/testdata/extra/mongodb.py @@ -1,6 +1,6 @@ try: import pymongo -except ImportError, import_err: +except ImportError as import_err: raise ImportError("{}. in order to use the mongodb extra you must install pymongo (pip install pymongo)".format(str(import_err))) from ..factories.sequences import RandomSelection diff --git a/testdata/factories/generic.py b/testdata/factories/generic.py index 7e3d67c..45936cf 100644 --- a/testdata/factories/generic.py +++ b/testdata/factories/generic.py @@ -31,9 +31,10 @@ class Sum(Factory): :param sum_func: The function that will be used for summing the factories' results. A simple Example, + >>> from __future__ import print_function >>> import testdata >>> for i in testdata.Sum([testdata.CountingFactory(10, 5), testdata.CountingFactory(1, 1)]).generate(5): - ... print i + ... print(i) 11 17 23 @@ -94,7 +95,7 @@ def set_element_amount(self, element_amount): self._factory.set_element_amount(element_amount * self._max_items) def __call__(self): - return [self._factory.next() for i in xrange(random.randint(self._min_items, self._max_items))] + return [next(self._factory) for i in range(random.randint(self._min_items, self._max_items))] class ConditionalValueField(DependentField): """ @@ -109,17 +110,16 @@ class ConditionalValueField(DependentField): >>> class Bar(testdata.DictFactory): ... a = testdata.CountingFactory(0) ... b = ConditionalValueField('a', {0: 'a', 1: 'b', 2: 'c'}, -1) + >>> got = [] >>> for i in Bar().generate(3): - ... print i - {'a': 0, 'b': 'a'} - {'a': 1, 'b': 'b'} - {'a': 2, 'b': 'c'} + ... got.append(i) + >>> got == [{'a': 0, 'b': 'a'}, {'a': 1, 'b': 'b'}, {'a': 2, 'b': 'c'}] + True + >>> got = [] >>> for i in Bar().generate(4): - ... print i - {'a': 0, 'b': 'a'} - {'a': 1, 'b': 'b'} - {'a': 2, 'b': 'c'} - {'a': 3, 'b': -1} + ... got.append(i) + >>> got == [{'a': 0, 'b': 'a'}, {'a': 1, 'b': 'b'}, {'a': 2, 'b': 'c'}, {'a': 3, 'b': -1}] + True """ def __init__(self, other_field, possible_values, default_value): super(ConditionalValueField, self).__init__([other_field]) diff --git a/testdata/factories/numbers.py b/testdata/factories/numbers.py index bac4a95..0ddc73a 100644 --- a/testdata/factories/numbers.py +++ b/testdata/factories/numbers.py @@ -34,8 +34,8 @@ class RelativeNumber(DependentField): >>> class Foo(testdata.DictFactory): ... a = testdata.CountingFactory(1) ... b = RelativeNumber('a', 1) - >>> [i for i in Foo().generate(3)] - [{'a': 1, 'b': 2}, {'a': 2, 'b': 3}, {'a': 3, 'b': 4}] + >>> [i for i in Foo().generate(3)] == [{'a': 1, 'b': 2}, {'a': 2, 'b': 3}, {'a': 3, 'b': 4}] + True """ def __init__(self, other_number_field, delta): super(RelativeNumber, self).__init__([other_number_field]) diff --git a/testdata/factories/sequences.py b/testdata/factories/sequences.py index 4379f21..995cd8c 100644 --- a/testdata/factories/sequences.py +++ b/testdata/factories/sequences.py @@ -8,8 +8,9 @@ class CycleSequenceFactory(Factory): all the items. Example, + >>> from __future__ import print_function >>> for i in CycleSequenceFactory([1, 2, 3]).generate(9): - ... print i + ... print(i) 1 2 3 @@ -33,12 +34,13 @@ class RandomSelection(Factory): Randomly chooses an element for the give sequence. Example, + >>> from __future__ import print_function >>> possible_values = set([1, 2, 3]) >>> while possible_values: ... for i in RandomSelection([1, 2, 3]).generate(100): ... possible_values.discard(i) - >>> print possible_values - set([]) + >>> possible_values == set() + True """ def __init__(self, sequence): super(RandomSelection, self).__init__() diff --git a/testdata/factories/statistical.py b/testdata/factories/statistical.py index 9afe2ee..9da5b92 100644 --- a/testdata/factories/statistical.py +++ b/testdata/factories/statistical.py @@ -18,9 +18,11 @@ class StatisticalPercentageFactory(Factory): 2 >>> f.count('bar') 2 - >>> f = [i for i in StatisticalPercentageFactory([(testdata.Constant('foo'), 50), (testdata.Constant('bar'), 20)]).generate(4)] - Traceback (most recent call last): - InvalidTotalPrecentage: Need a total of a 100 precent. got 70 instead + >>> try: + ... f = [i for i in StatisticalPercentageFactory([(testdata.Constant('foo'), 50), (testdata.Constant('bar'), 20)]).generate(4)] + ... raise AssesionError('InvalidTotalPercentage not raised') + ... except InvalidTotalPrecentage: + ... pass """ def __init__(self, factories): super(StatisticalPercentageFactory, self).__init__() diff --git a/testdata/factories/strings.py b/testdata/factories/strings.py index fc02d9c..a3d223d 100644 --- a/testdata/factories/strings.py +++ b/testdata/factories/strings.py @@ -23,7 +23,7 @@ def __init__(self, min_chars=None, max_chars=None, prefix=None, suffix=None): def __call__(self): length = random.randint(self._min_chars, self._max_chars) - random_string = [random.choice(string.ascii_letters) for i in xrange(length)] + random_string = [random.choice(string.ascii_letters) for i in range(length)] random_string.insert(0, self._prefix) random_string.append(self._suffix) @@ -60,5 +60,5 @@ def __init__(self, hash_class): def __call__(self): length = random.randint(self._MIN_VALUE_LENGTH, self._MAX_VALUE_LENGTH) - random_string = ''.join([random.choice(string.ascii_letters) for i in xrange(length)]) + random_string = ''.join([random.choice(string.ascii_letters) for i in range(length)]) return self._hash_class(random_string).hexdigest() diff --git a/testdata/metaclasses.py b/testdata/metaclasses.py index 666cd7c..35f648c 100644 --- a/testdata/metaclasses.py +++ b/testdata/metaclasses.py @@ -18,6 +18,10 @@ def _clean_factories(dct): """ After we create the children factory, we don't need it anymore """ + keys = [] for key in dct.keys(): if issubclass(type(dct[key]), Factory): - dct.pop(key) + # avoid change dict in loop + keys.append(key) + for key in keys: + dct.pop(key)