autofaker 0.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- autofaker/__init__.py +14 -0
- autofaker/attributes.py +19 -0
- autofaker/autodata.py +71 -0
- autofaker/base.py +7 -0
- autofaker/builtins.py +105 -0
- autofaker/dataframe.py +38 -0
- autofaker/dates.py +51 -0
- autofaker/decorators.py +209 -0
- autofaker/enums.py +16 -0
- autofaker/fakes.py +30 -0
- autofaker/generator.py +352 -0
- autofaker/literals.py +23 -0
- autofaker/registry.py +185 -0
- autofaker-0.1.0.dist-info/METADATA +487 -0
- autofaker-0.1.0.dist-info/RECORD +18 -0
- autofaker-0.1.0.dist-info/WHEEL +5 -0
- autofaker-0.1.0.dist-info/licenses/LICENSE +21 -0
- autofaker-0.1.0.dist-info/top_level.txt +1 -0
autofaker/__init__.py
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Provides modules for creation anonymous variables to help minimize the setup/arrange phase when writing unit tests
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
__version__ = "0.1.0"
|
|
6
|
+
|
|
7
|
+
from autofaker.autodata import *
|
|
8
|
+
from autofaker.decorators import *
|
|
9
|
+
from autofaker.registry import (
|
|
10
|
+
register_predicate,
|
|
11
|
+
register_type,
|
|
12
|
+
registry_context,
|
|
13
|
+
reset_registry,
|
|
14
|
+
)
|
autofaker/attributes.py
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
class Attributes:
|
|
2
|
+
def __init__(self, instance):
|
|
3
|
+
self.instance = instance
|
|
4
|
+
|
|
5
|
+
def get_members(self):
|
|
6
|
+
return [
|
|
7
|
+
attr
|
|
8
|
+
for attr in dir(self.instance)
|
|
9
|
+
if not callable(getattr(self.instance, attr)) and not attr.startswith("__")
|
|
10
|
+
]
|
|
11
|
+
|
|
12
|
+
def get_attribute(self, member):
|
|
13
|
+
return getattr(self.instance, member)
|
|
14
|
+
|
|
15
|
+
def get_typename(self, member):
|
|
16
|
+
return type(self.get_attribute(member)).__name__
|
|
17
|
+
|
|
18
|
+
def set_value(self, member, value):
|
|
19
|
+
setattr(self.instance, member, value)
|
autofaker/autodata.py
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Provides classes for anonymous object creation to help minimize
|
|
3
|
+
the setup/arrange phase when writing unit tests
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
import typing
|
|
7
|
+
from typing import List
|
|
8
|
+
|
|
9
|
+
from autofaker.dataframe import PandasDataFrameGenerator
|
|
10
|
+
from autofaker.generator import TypeDataGenerator
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class Autodata:
|
|
14
|
+
"""
|
|
15
|
+
Provides anonymous object creation functions to help minimize
|
|
16
|
+
the setup/arrange phase when writing unit tests
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
@staticmethod
|
|
20
|
+
def create(t, use_fake_data: bool = False):
|
|
21
|
+
"""
|
|
22
|
+
Creates an anonymous variable of the requested type
|
|
23
|
+
|
|
24
|
+
:param type t: type
|
|
25
|
+
The type to generate data for
|
|
26
|
+
|
|
27
|
+
:param use_fake_data: bool
|
|
28
|
+
Set this to True to use Faker to generate data
|
|
29
|
+
otherwise False to generate anonymous data
|
|
30
|
+
"""
|
|
31
|
+
return TypeDataGenerator.create(t, use_fake_data=use_fake_data).generate()
|
|
32
|
+
|
|
33
|
+
@staticmethod
|
|
34
|
+
def create_many(t, size: int = 3, use_fake_data: bool = False) -> List[typing.Any]:
|
|
35
|
+
"""
|
|
36
|
+
Creates a list of anonymous variables of the requested
|
|
37
|
+
type using the specified length (default 3)
|
|
38
|
+
|
|
39
|
+
:param type t: (type)
|
|
40
|
+
The type to generate data for
|
|
41
|
+
|
|
42
|
+
:param size: (int)
|
|
43
|
+
The number of items to generate (default 3)
|
|
44
|
+
|
|
45
|
+
:param use_fake_data: (bool)
|
|
46
|
+
Set this to True to use Faker to generate data,
|
|
47
|
+
otherwise False to generate anonymous data
|
|
48
|
+
"""
|
|
49
|
+
items = []
|
|
50
|
+
for _ in range(size):
|
|
51
|
+
items.append(Autodata.create(t, use_fake_data=use_fake_data))
|
|
52
|
+
return items
|
|
53
|
+
|
|
54
|
+
@staticmethod
|
|
55
|
+
def create_pandas_dataframe(t, rows: int = 3, use_fake_data: bool = False):
|
|
56
|
+
"""
|
|
57
|
+
Create a Pandas DataFrame containing anonymous data
|
|
58
|
+
with the specified number of rows (default 3)
|
|
59
|
+
|
|
60
|
+
:param type t: object
|
|
61
|
+
The class that represents the DataFrame.
|
|
62
|
+
This can be a plain old class or a @dataclass
|
|
63
|
+
|
|
64
|
+
:param type rows: int
|
|
65
|
+
The number of rows to generate for the DataFrame (default 3)
|
|
66
|
+
|
|
67
|
+
:param use_fake_data: bool
|
|
68
|
+
Set this to True to use Faker to generate data,
|
|
69
|
+
otherwise False to generate anonymous data
|
|
70
|
+
"""
|
|
71
|
+
return PandasDataFrameGenerator(t, rows, use_fake_data=use_fake_data).generate()
|
autofaker/base.py
ADDED
autofaker/builtins.py
ADDED
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import decimal
|
|
2
|
+
import pathlib
|
|
3
|
+
import random
|
|
4
|
+
import uuid
|
|
5
|
+
|
|
6
|
+
from autofaker.base import TypeDataGeneratorBase
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class IntegerGenerator(TypeDataGeneratorBase):
|
|
10
|
+
def generate(self):
|
|
11
|
+
return random.randint(1, 10000)
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class StringGenerator(TypeDataGeneratorBase):
|
|
15
|
+
def generate(self):
|
|
16
|
+
return str(uuid.uuid4())
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class FloatGenerator(TypeDataGeneratorBase):
|
|
20
|
+
def generate(self):
|
|
21
|
+
return random.uniform(0, 10000)
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class BooleanGenerator(TypeDataGeneratorBase):
|
|
25
|
+
def generate(self):
|
|
26
|
+
return bool(random.getrandbits(1))
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
class ComplexGenerator(TypeDataGeneratorBase):
|
|
30
|
+
def generate(self):
|
|
31
|
+
return complex(IntegerGenerator().generate())
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
class RangeGenerator(TypeDataGeneratorBase):
|
|
35
|
+
def generate(self):
|
|
36
|
+
return range(IntegerGenerator().generate())
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
class BytesGenerator(TypeDataGeneratorBase):
|
|
40
|
+
def generate(self):
|
|
41
|
+
return bytes(range(random.randint(1, 256)))
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
class ByteArrayGenerator(TypeDataGeneratorBase):
|
|
45
|
+
def generate(self):
|
|
46
|
+
return bytearray(range(random.randint(1, 256)))
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
class MemoryViewGenerator(TypeDataGeneratorBase):
|
|
50
|
+
def generate(self):
|
|
51
|
+
return memoryview(BytesGenerator().generate())
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
class TupleGenerator(TypeDataGeneratorBase):
|
|
55
|
+
def generate(self):
|
|
56
|
+
return (
|
|
57
|
+
IntegerGenerator().generate(),
|
|
58
|
+
StringGenerator().generate(),
|
|
59
|
+
FloatGenerator().generate(),
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
class SetGenerator(TypeDataGeneratorBase):
|
|
64
|
+
def generate(self):
|
|
65
|
+
return {
|
|
66
|
+
StringGenerator().generate(),
|
|
67
|
+
StringGenerator().generate(),
|
|
68
|
+
StringGenerator().generate(),
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
class FrozenSetGenerator(TypeDataGeneratorBase):
|
|
73
|
+
def generate(self):
|
|
74
|
+
return frozenset({
|
|
75
|
+
StringGenerator().generate(),
|
|
76
|
+
StringGenerator().generate(),
|
|
77
|
+
StringGenerator().generate(),
|
|
78
|
+
})
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
class DictGenerator(TypeDataGeneratorBase):
|
|
82
|
+
def generate(self):
|
|
83
|
+
return {
|
|
84
|
+
StringGenerator().generate(): IntegerGenerator().generate(),
|
|
85
|
+
StringGenerator().generate(): IntegerGenerator().generate(),
|
|
86
|
+
StringGenerator().generate(): IntegerGenerator().generate(),
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
class DecimalGenerator(TypeDataGeneratorBase):
|
|
91
|
+
def generate(self):
|
|
92
|
+
return decimal.Decimal(str(random.uniform(0, 10000)))
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
class UUIDGenerator(TypeDataGeneratorBase):
|
|
96
|
+
def generate(self):
|
|
97
|
+
return uuid.uuid4()
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
class PathGenerator(TypeDataGeneratorBase):
|
|
101
|
+
def generate(self):
|
|
102
|
+
return pathlib.Path(
|
|
103
|
+
StringGenerator().generate(),
|
|
104
|
+
StringGenerator().generate(),
|
|
105
|
+
)
|
autofaker/dataframe.py
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import dataclasses
|
|
2
|
+
|
|
3
|
+
import pandas as pd
|
|
4
|
+
|
|
5
|
+
from autofaker.attributes import Attributes
|
|
6
|
+
from autofaker.generator import TypeDataGenerator
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class PandasDataFrameGenerator:
|
|
10
|
+
def __init__(self, t, rows: int = 3, use_fake_data: bool = False):
|
|
11
|
+
self.t = t
|
|
12
|
+
self.data = []
|
|
13
|
+
for _ in range(rows):
|
|
14
|
+
row = TypeDataGenerator.create(t, use_fake_data=use_fake_data).generate()
|
|
15
|
+
self.data.append(row)
|
|
16
|
+
|
|
17
|
+
def _get_columns(self, instance):
|
|
18
|
+
return [
|
|
19
|
+
attr
|
|
20
|
+
for attr in dir(instance)
|
|
21
|
+
if (dataclasses.is_dataclass(getattr(instance, attr))
|
|
22
|
+
or not callable(getattr(instance, attr)))
|
|
23
|
+
and not attr.startswith("__")
|
|
24
|
+
]
|
|
25
|
+
|
|
26
|
+
def generate(self):
|
|
27
|
+
if not self.data:
|
|
28
|
+
sample = TypeDataGenerator.create(self.t).generate()
|
|
29
|
+
columns = self._get_columns(sample)
|
|
30
|
+
return pd.DataFrame(columns=columns)
|
|
31
|
+
members = self._get_columns(self.data[0])
|
|
32
|
+
rows = []
|
|
33
|
+
for d in self.data:
|
|
34
|
+
row = []
|
|
35
|
+
for member in members:
|
|
36
|
+
row.append(Attributes(d).get_attribute(member))
|
|
37
|
+
rows.append(row)
|
|
38
|
+
return pd.DataFrame(rows, columns=members)
|
autofaker/dates.py
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import datetime
|
|
2
|
+
import random
|
|
3
|
+
|
|
4
|
+
from autofaker.base import TypeDataGeneratorBase
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def is_date_type(type_name) -> bool:
|
|
8
|
+
return type_name in ["datetime", "date", "time", "timedelta"]
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class DatetimeGenerator(TypeDataGeneratorBase):
|
|
12
|
+
def generate(self):
|
|
13
|
+
year = datetime.date.today().year
|
|
14
|
+
return datetime.datetime(
|
|
15
|
+
random.randint(year - 10, year + 10),
|
|
16
|
+
random.randint(1, 12),
|
|
17
|
+
random.randint(1, 28),
|
|
18
|
+
random.randint(0, 23),
|
|
19
|
+
random.randint(0, 59),
|
|
20
|
+
random.randint(0, 59),
|
|
21
|
+
random.randint(0, 999999),
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class DateGenerator(TypeDataGeneratorBase):
|
|
26
|
+
def generate(self):
|
|
27
|
+
year = datetime.date.today().year
|
|
28
|
+
return datetime.date(
|
|
29
|
+
random.randint(year - 10, year + 10),
|
|
30
|
+
random.randint(1, 12),
|
|
31
|
+
random.randint(1, 28),
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
class TimeGenerator(TypeDataGeneratorBase):
|
|
36
|
+
def generate(self):
|
|
37
|
+
return datetime.time(
|
|
38
|
+
random.randint(0, 23),
|
|
39
|
+
random.randint(0, 59),
|
|
40
|
+
random.randint(0, 59),
|
|
41
|
+
random.randint(0, 999999),
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
class TimedeltaGenerator(TypeDataGeneratorBase):
|
|
46
|
+
def generate(self):
|
|
47
|
+
return datetime.timedelta(
|
|
48
|
+
days=random.randint(0, 365),
|
|
49
|
+
seconds=random.randint(0, 86399),
|
|
50
|
+
microseconds=random.randint(0, 999999),
|
|
51
|
+
)
|
autofaker/decorators.py
ADDED
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Provides anonymous object creation functions to help minimize
|
|
3
|
+
the setup/arrange phase when writing unit tests
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
import inspect
|
|
7
|
+
import unittest
|
|
8
|
+
from typing import List
|
|
9
|
+
|
|
10
|
+
from autofaker import Autodata, PandasDataFrameGenerator
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def autodata(*types: object, use_fake_data: bool = False):
|
|
14
|
+
"""
|
|
15
|
+
Creates anonymous variable of the requested types
|
|
16
|
+
and pass them as arguments to a unit test function
|
|
17
|
+
|
|
18
|
+
Example:
|
|
19
|
+
|
|
20
|
+
import unittest
|
|
21
|
+
|
|
22
|
+
from autofaker import autodata
|
|
23
|
+
|
|
24
|
+
class SampleTest(unittest.TestCase):
|
|
25
|
+
@autodata(str, int, float, bool)
|
|
26
|
+
|
|
27
|
+
def test_create_str_argument_using_decorator(self, text, number, decimal, boolean):
|
|
28
|
+
self.assertIsNotNone(text)
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
:param use_fake_data: bool
|
|
32
|
+
Set this to True to use Faker to generate data,
|
|
33
|
+
otherwise False to generate anonymous data
|
|
34
|
+
|
|
35
|
+
:param type types: tuple
|
|
36
|
+
The types to generate data.
|
|
37
|
+
This is optional and will use the arguments
|
|
38
|
+
from the function being decorated if not specified
|
|
39
|
+
"""
|
|
40
|
+
if _is_bare_decoration(types):
|
|
41
|
+
return _make_arg_decorator((), use_fake_data=use_fake_data)(types[0])
|
|
42
|
+
return _make_arg_decorator(types, use_fake_data=use_fake_data)
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def fakedata(*types: object):
|
|
46
|
+
"""
|
|
47
|
+
Creates fake values for the variables of the requested types
|
|
48
|
+
and pass them as arguments to a unit test function
|
|
49
|
+
|
|
50
|
+
Example:
|
|
51
|
+
|
|
52
|
+
import unittest
|
|
53
|
+
|
|
54
|
+
from autofaker import fakedata
|
|
55
|
+
|
|
56
|
+
class SampleTest(unittest.TestCase):
|
|
57
|
+
@fakedata()
|
|
58
|
+
|
|
59
|
+
def test_create_fake_arguments(self, text: str, number: int, decimal: float, boolean: bool):
|
|
60
|
+
self.assertIsNotNone(text)
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
:param types: object
|
|
64
|
+
The types to generate data.
|
|
65
|
+
This is optional and will use the arguments from the function
|
|
66
|
+
being decorated if not specified
|
|
67
|
+
"""
|
|
68
|
+
if _is_bare_decoration(types):
|
|
69
|
+
return _make_arg_decorator((), use_fake_data=True)(types[0])
|
|
70
|
+
return _make_arg_decorator(types, use_fake_data=True)
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
def autopandas(t: object, rows: int = 3, use_fake_data: bool = False):
|
|
74
|
+
"""
|
|
75
|
+
Create a Pandas DataFrame containing anonymous data
|
|
76
|
+
with the specified number of rows (default 3)
|
|
77
|
+
|
|
78
|
+
:param type t: object
|
|
79
|
+
The class that represents the DataFrame.
|
|
80
|
+
This can be a plain old class or a @dataclass
|
|
81
|
+
|
|
82
|
+
:param type rows: int
|
|
83
|
+
The number of rows to generate for the DataFrame (default 3)
|
|
84
|
+
|
|
85
|
+
:param use_fake_data: bool
|
|
86
|
+
Set this to True to use Faker to generate data,
|
|
87
|
+
otherwise False to generate anonymous data
|
|
88
|
+
"""
|
|
89
|
+
|
|
90
|
+
def decorator(function):
|
|
91
|
+
def wrapper(*args):
|
|
92
|
+
pdf = PandasDataFrameGenerator(
|
|
93
|
+
t, rows, use_fake_data=use_fake_data
|
|
94
|
+
).generate()
|
|
95
|
+
return _invoke(function, args, lambda: [pdf])
|
|
96
|
+
|
|
97
|
+
return wrapper
|
|
98
|
+
|
|
99
|
+
return decorator
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
def fakepandas(t, rows: int = 3):
|
|
103
|
+
"""
|
|
104
|
+
Create a Pandas DataFrame containing fake data with
|
|
105
|
+
the specified number of rows (default 3)
|
|
106
|
+
|
|
107
|
+
:param type t: object
|
|
108
|
+
The class that represents the DataFrame.
|
|
109
|
+
This can be a plain old class or a @dataclass
|
|
110
|
+
|
|
111
|
+
:param type rows: int
|
|
112
|
+
The number of rows to generate for the DataFrame (default 3)
|
|
113
|
+
"""
|
|
114
|
+
return autopandas(t, rows, use_fake_data=True)
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
def _is_bare_decoration(types) -> bool:
|
|
118
|
+
"""True when a decorator was applied without parentheses (``@autodata``).
|
|
119
|
+
|
|
120
|
+
In that case the decorated function itself is passed as the single
|
|
121
|
+
positional argument. Distinguished from a callable type argument by the
|
|
122
|
+
presence of ``__code__`` and not being a class.
|
|
123
|
+
"""
|
|
124
|
+
return (
|
|
125
|
+
len(types) == 1
|
|
126
|
+
and callable(types[0])
|
|
127
|
+
and not isinstance(types[0], type)
|
|
128
|
+
and hasattr(types[0], "__code__")
|
|
129
|
+
)
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
def _make_arg_decorator(types, use_fake_data: bool):
|
|
133
|
+
"""Build a decorator that injects generated arguments into a test function.
|
|
134
|
+
|
|
135
|
+
When ``types`` is empty the argument types are taken from the decorated
|
|
136
|
+
function's annotations; otherwise the explicit ``types`` are used.
|
|
137
|
+
"""
|
|
138
|
+
|
|
139
|
+
def decorator(function):
|
|
140
|
+
def wrapper(*args):
|
|
141
|
+
return _invoke(
|
|
142
|
+
function,
|
|
143
|
+
args,
|
|
144
|
+
lambda: __create_function_args(
|
|
145
|
+
function, *tuple(types), use_fake_data=use_fake_data
|
|
146
|
+
),
|
|
147
|
+
)
|
|
148
|
+
|
|
149
|
+
return wrapper
|
|
150
|
+
|
|
151
|
+
return decorator
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
def _invoke(function, call_args, build_args):
|
|
155
|
+
"""Call ``function`` with generated arguments.
|
|
156
|
+
|
|
157
|
+
When the decorated function is a ``unittest.TestCase`` method, its instance
|
|
158
|
+
(``self``) is recovered from the wrapper's call arguments and prepended.
|
|
159
|
+
The test-class check runs before ``build_args`` so an invalid target raises
|
|
160
|
+
``NotImplementedError`` ahead of any argument-shape error. ``build_args`` is
|
|
161
|
+
a thunk to defer that work until the target is known.
|
|
162
|
+
"""
|
|
163
|
+
if __get_class_that_defined_method(function) is None:
|
|
164
|
+
function(*build_args())
|
|
165
|
+
return None
|
|
166
|
+
test_class = __get_test_class(*call_args)
|
|
167
|
+
function(test_class, *build_args())
|
|
168
|
+
return None
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
def __get_test_class(*args):
|
|
172
|
+
test_class = args[0]
|
|
173
|
+
if not issubclass(test_class.__class__, unittest.TestCase):
|
|
174
|
+
raise NotImplementedError(
|
|
175
|
+
"This way of creating anonymous objects are only supported from unit tests"
|
|
176
|
+
)
|
|
177
|
+
return test_class
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
def __get_class_that_defined_method(meth):
|
|
181
|
+
if inspect.isfunction(meth):
|
|
182
|
+
cls = getattr(
|
|
183
|
+
inspect.getmodule(meth),
|
|
184
|
+
meth.__qualname__.split(".<locals>", 1)[0].rsplit(".", 1)[0],
|
|
185
|
+
None,
|
|
186
|
+
)
|
|
187
|
+
if isinstance(cls, type):
|
|
188
|
+
return cls
|
|
189
|
+
return getattr(meth, "__objclass__", None) # handle special descriptor objects
|
|
190
|
+
|
|
191
|
+
|
|
192
|
+
def __create_function_args(function, *types, use_fake_data: bool = False) -> List:
|
|
193
|
+
values = []
|
|
194
|
+
argtypes = inspect.getfullargspec(function)
|
|
195
|
+
annotations = {
|
|
196
|
+
k: v for k, v in argtypes.annotations.items() if k != 'return'
|
|
197
|
+
}
|
|
198
|
+
args = annotations.values() if types is None or len(types) == 0 else types
|
|
199
|
+
for t in args:
|
|
200
|
+
value = Autodata.create(t, use_fake_data)
|
|
201
|
+
values.append(value)
|
|
202
|
+
pos = 1
|
|
203
|
+
if __get_class_that_defined_method(function) is None:
|
|
204
|
+
pos = 0
|
|
205
|
+
if len(argtypes.args) - pos != len(values):
|
|
206
|
+
raise ValueError(
|
|
207
|
+
"Missing argument annotations. Please declare the type of every argument"
|
|
208
|
+
)
|
|
209
|
+
return values
|
autofaker/enums.py
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import random
|
|
2
|
+
from enum import Enum
|
|
3
|
+
|
|
4
|
+
from autofaker.base import TypeDataGeneratorBase
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def is_enum(t) -> bool:
|
|
8
|
+
return isinstance(t, Enum.__class__)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class EnumGenerator(TypeDataGeneratorBase):
|
|
12
|
+
def __init__(self, enum):
|
|
13
|
+
self.enum = enum
|
|
14
|
+
|
|
15
|
+
def generate(self):
|
|
16
|
+
return random.choice(list(self.enum))
|
autofaker/fakes.py
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
from faker import Faker
|
|
2
|
+
|
|
3
|
+
from autofaker.attributes import Attributes
|
|
4
|
+
from autofaker.base import TypeDataGeneratorBase
|
|
5
|
+
from autofaker.builtins import StringGenerator
|
|
6
|
+
|
|
7
|
+
faker = Faker()
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def generate(field_name: str):
|
|
11
|
+
try:
|
|
12
|
+
attributes = Attributes(faker)
|
|
13
|
+
func = attributes.get_attribute(field_name)
|
|
14
|
+
return func()
|
|
15
|
+
except AttributeError:
|
|
16
|
+
return None
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class FakeStringGenerator(TypeDataGeneratorBase):
|
|
20
|
+
def __init__(self, field_name: str):
|
|
21
|
+
self.field_name = field_name
|
|
22
|
+
|
|
23
|
+
def generate(self):
|
|
24
|
+
fake = generate(self.field_name)
|
|
25
|
+
return fake if fake is not None else StringGenerator().generate()
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class FakeIntegerGenerator(TypeDataGeneratorBase):
|
|
29
|
+
def generate(self):
|
|
30
|
+
return faker.random_int(min=1, max=10000)
|