From 12040acf567778a63414dd57d56a43b2a6ed6068 Mon Sep 17 00:00:00 2001 From: Artur Barseghyan Date: Fri, 22 Nov 2024 17:51:41 +0100 Subject: [PATCH 01/11] More linting --- fake.py | 26 +++++++++------------ pyproject.toml | 58 +++++++++++++++------------------------------- tox.ini | 63 ++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 93 insertions(+), 54 deletions(-) create mode 100644 tox.ini diff --git a/fake.py b/fake.py index 7f65556..bebef62 100644 --- a/fake.py +++ b/fake.py @@ -1544,8 +1544,8 @@ def generate( jpeg = original.copy() # Step 1: Update the SOF0 marker with new dimensions - SOF0 = b"\xFF\xC0" - sof0_index = cls.find_marker(jpeg, SOF0) + sof0 = b"\xFF\xC0" + sof0_index = cls.find_marker(jpeg, sof0) # SOF0 structure: # [Marker] @@ -1576,8 +1576,8 @@ def generate( jpeg[sof0_index + 8] = new_width_bytes[1] # Step 2: Locate the Start of Scan (SOS) marker - SOS = b"\xFF\xDA" - sos_index = cls.find_marker(jpeg, SOS) + sos = b"\xFF\xDA" + sos_index = cls.find_marker(jpeg, sos) # SOS structure: # [Marker] @@ -1592,8 +1592,8 @@ def generate( image_data_start = sos_index + 2 + sos_length # Locate the End of Image (EOI) marker - EOI = b"\xFF\xD9" - eoi_index = jpeg.find(EOI, image_data_start) + eoi = b"\xFF\xD9" + eoi_index = jpeg.find(eoi, image_data_start) if eoi_index == -1: eoi_index = 0 # raise ValueError("EOI marker not found.") @@ -1630,7 +1630,7 @@ class ProviderRegistryItem(str): def __new__(cls, value, *args, **kwargs): obj = str.__new__(cls, value) - obj.tags = tuple() + obj.tags = () return obj @@ -5433,7 +5433,7 @@ def __init__(self, faker: Optional[Faker] = None) -> None: else: self.faker = FAKER faker_id = f"{self.faker.__module__}.{self.faker.__class__.__name__}" - self.provider_list = sorted(list(PROVIDER_REGISTRY[faker_id])) + self.provider_list = sorted(PROVIDER_REGISTRY[faker_id]) self.provider_tags = [ (_provider, _provider.tags) for _provider in self.provider_list ] @@ -5529,9 +5529,7 @@ def test_main(self): class TestOrganizeProviders(unittest.TestCase): def setUp(self): - self.provider_list = sorted( - list(PROVIDER_REGISTRY[f"{__name__}.Faker"]) - ) + self.provider_list = sorted(PROVIDER_REGISTRY[f"{__name__}.Faker"]) self.provider_tags = [ (_provider, _provider.tags) for _provider in self.provider_list ] @@ -5605,9 +5603,7 @@ def test_organize_providers_category_sorting(self): class TestCLI(unittest.TestCase): def setUp(self): - self.provider_list = sorted( - list(PROVIDER_REGISTRY[f"{__name__}.Faker"]) - ) + self.provider_list = sorted(PROVIDER_REGISTRY[f"{__name__}.Faker"]) @patch("sys.argv", ["fake-py"]) def test_provider_list(self): @@ -6069,7 +6065,7 @@ def test_password(self): length=4, min_digits=3 ) # 2 required characters + 3 digits > 4 with self.subTest("Test multiple generated passwords are unique."): - passwords = set(self.faker.password() for _ in range(25)) + passwords = {self.faker.password() for _ in range(25)} self.assertEqual(len(passwords), 25, "Passwords should be unique.") def test_pyfloat(self) -> None: diff --git a/pyproject.toml b/pyproject.toml index 7718097..f1f4797 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -80,49 +80,29 @@ include = ["fakepy"] requires = ["setuptools>=41.0", "setuptools-scm", "wheel"] build-backend = "setuptools.build_meta" -#[tool.black] -#line-length = 80 -#target-version = ['py38', 'py39', 'py310', 'py311'] -#include = '\.pyi?$' -#force-exclude = '__copy_fake\.py' -#extend-exclude = ''' -#/( -# # The following are specific to Black, you probably don't want those. -# | blib2to3 -# | tests/data -# | profiling -# | migrations -#)/ -#''' -# -#[tool.isort] -#profile = "black" -#combine_as_imports = true -#multi_line_output = 3 -#force_single_line = false -#include_trailing_comma = true -#force_grid_wrap = 0 -#use_parentheses = true -#ensure_newline_before_comments = true -#line_length = 80 -#honor_noqa = true -#known_first_party = [ -# "address", -# "article", -# "config", -# "data", -# "fake_address", -# "fake_band", -#] -#known_third_party = ["fake"] -#skip = ["wsgi.py", "builddocs/"] - [tool.ruff] line-length = 80 # Enable Pyflakes `E` and `F` codes by default. -lint.select = ["E", "F", "I", "Q"] -lint.ignore = [] +lint.select = [ +# "ANN", # Annotations: missing (return) types +# "B", # Bugbear: common bug patterns or design problems + "C4", # Complexity: McCabe complexity checker + "E", # Pycodesyle: Style guide enforcement + "F", # Pyflakes: Source files errors + "G", # Logging format: Basic logging format errors + "I", # Isort: import sorting + "ISC", # Naming: Variable naming convention + "INP", # Implicit namespace packages: Check if __init__.py is present + "N", # Naming: Variable naming convention + "PERF", # Perflint: Performance linting + "Q", +] +lint.ignore = [ + "G004", # Allow use of f-string in logging + "ISC003", # Allow explicitly concatenated strings + "N805", # Allow first argument of a method be named other than `self` +] # Enable autofix for formatting and import sorting fix = true src = [ diff --git a/tox.ini b/tox.ini new file mode 100644 index 0000000..07e64c0 --- /dev/null +++ b/tox.ini @@ -0,0 +1,63 @@ +[tox] +envlist = py39,py310,py311,py312,py313 +skip_build = True + +[testenv] +commands = + source $(VENV) + pytest -vrx --dagnose + python manage.py test + +[testenv:customization-test] +commands = + cd examples/customization/ + source $(VENV) + python manage.py test + +[testenv:dataclasses-test] +commands = + cd examples/dataclasses/ + source $(VENV) + python manage.py test + +[testenv:django-test] +commands = + cd examples/django/ + source $(VENV) + ./manage.py test + +[testenv:hypothesis-test] +commands = + cd examples/hypothesis/ + source $(VENV) + python manage.py test + +[testenv:lazyfuzzy-test] +commands = + cd examples/lazyfuzzy/ + source $(VENV) + python manage.py test + +[testenv:pydantic-test] +commands = + cd examples/pydantic/ + source $(VENV) + python manage.py test + +[testenv:sqlalchemy-test] +commands = + cd examples/sqlalchemy/ + source $(VENV) + python manage.py test + +[testenv:sqlmodel-test] +commands = + cd examples/sqlmodel/ + source $(VENV) + python manage.py test + +[testenv:tortoise-test] +commands = + cd examples/tortoise/ + source $(VENV) + python manage.py test From 7e7dbef2abb892642b511cf4056db04b481b1069 Mon Sep 17 00:00:00 2001 From: Artur Barseghyan Date: Fri, 22 Nov 2024 18:09:16 +0100 Subject: [PATCH 02/11] More --- conftest.py | 2 +- fake.py | 6 +++--- pyproject.toml | 9 +++++++-- 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/conftest.py b/conftest.py index 73814a2..094d7f5 100644 --- a/conftest.py +++ b/conftest.py @@ -20,7 +20,7 @@ def pytest_collection_modifyitems(session, config, items): """Modify test items during collection.""" for item in items: - try: + try: # noqa from pytest_rst import RSTTestItem if isinstance(item, RSTTestItem): diff --git a/fake.py b/fake.py index bebef62..d47448f 100644 --- a/fake.py +++ b/fake.py @@ -449,7 +449,7 @@ def replacer(self, match: re.Match) -> str: # Example: f('morning', format='%A, %B %d, %Y') parsed_args = ast.parse(f"f({args_str})", mode="eval").body for arg in parsed_args.args: - args.append(ast.literal_eval(arg)) + args.append(ast.literal_eval(arg)) # noqa: PERF401 for kw in parsed_args.keywords: kwargs[kw.arg] = ast.literal_eval(kw.value) except Exception as err: @@ -6984,7 +6984,7 @@ def set_password(self, password: str) -> None: self.password = xor_transform(password) @classproperty - def objects(cls): + def objects(cls): # noqa: N805 """Mimicking Django's Manager behaviour.""" return DjangoManager( instance=fill_dataclass(cls), # type: ignore @@ -7013,7 +7013,7 @@ def save(self, *args, **kwargs): self.save_called = True # noqa @classproperty - def objects(cls): + def objects(cls): # noqa: N805 """Mimicking Django's Manager behaviour.""" return DjangoManager( instance=fill_dataclass(cls), # type: ignore diff --git a/pyproject.toml b/pyproject.toml index f1f4797..d01ed83 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -97,11 +97,12 @@ lint.select = [ "N", # Naming: Variable naming convention "PERF", # Perflint: Performance linting "Q", + "SIM", # Simplify: Helps simplify your code ] lint.ignore = [ "G004", # Allow use of f-string in logging "ISC003", # Allow explicitly concatenated strings - "N805", # Allow first argument of a method be named other than `self` +# "N805", # Allow first argument of a method be named other than `self` ] # Enable autofix for formatting and import sorting fix = true @@ -140,7 +141,6 @@ exclude = [ "venv", "docs", ] -lint.per-file-ignores = {} # Allow unused variables when underscore-prefixed. lint.dummy-variable-rgx = "^(_+|(_+[a-zA-Z0-9_]*[a-zA-Z0-9]+?))$" @@ -148,6 +148,11 @@ lint.dummy-variable-rgx = "^(_+|(_+[a-zA-Z0-9_]*[a-zA-Z0-9]+?))$" # Assume Python 3.9. target-version = "py39" +[tool.ruff.lint.per-file-ignores] +"conftest.py" = [ + "PERF203" # Allow `try`-`except` within a loop incurs performance overhead +] + [tool.ruff.lint.isort] known-first-party = [ "address", From 9f7981117e1cae74e4bd1e17f141320454e3f4da Mon Sep 17 00:00:00 2001 From: Artur Barseghyan Date: Fri, 22 Nov 2024 18:12:38 +0100 Subject: [PATCH 03/11] More --- fake.py | 4 ++-- pyproject.toml | 5 ++++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/fake.py b/fake.py index d47448f..0df26ed 100644 --- a/fake.py +++ b/fake.py @@ -1777,11 +1777,11 @@ def load_data(self): @staticmethod def get_by_uid(uid: str) -> Union["Faker", None]: - return UID_REGISTRY.get(uid, None) + return UID_REGISTRY.get(uid) @staticmethod def get_by_alias(alias: str) -> Union["Faker", None]: - return ALIAS_REGISTRY.get(alias, None) + return ALIAS_REGISTRY.get(alias) def load_words(self) -> None: with contextlib.redirect_stdout(io.StringIO()): diff --git a/pyproject.toml b/pyproject.toml index d01ed83..0be5eb5 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -97,12 +97,15 @@ lint.select = [ "N", # Naming: Variable naming convention "PERF", # Perflint: Performance linting "Q", - "SIM", # Simplify: Helps simplify your code +# "SIM", # Simplify: Helps simplify your code + "TD", # TO DO: Format TO DO comments ] lint.ignore = [ "G004", # Allow use of f-string in logging "ISC003", # Allow explicitly concatenated strings # "N805", # Allow first argument of a method be named other than `self` + "TD002", # Allow to do without author + "TD003", # Allow to do without URL ] # Enable autofix for formatting and import sorting fix = true From c72a42861b0b22e4efdc9bf62236c5e1c8194783 Mon Sep 17 00:00:00 2001 From: Artur Barseghyan Date: Fri, 22 Nov 2024 18:18:27 +0100 Subject: [PATCH 04/11] More --- fake.py | 4 ++-- pyproject.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/fake.py b/fake.py index 0df26ed..494b632 100644 --- a/fake.py +++ b/fake.py @@ -785,7 +785,7 @@ def generate_filename( dir_path.mkdir(parents=True, exist_ok=True) if not extension: - raise Exception("Extension shall be given!") + raise ValueError("Extension shall be given!") if not basename: basename = self.generate_basename(prefix) @@ -6785,7 +6785,7 @@ def test_randomise_string(self): def test_storage(self) -> None: storage = FileSystemStorage() - with self.assertRaises(Exception): + with self.assertRaises(ValueError): storage.generate_filename(extension=None) # type: ignore def test_storage_integration(self) -> None: diff --git a/pyproject.toml b/pyproject.toml index 0be5eb5..9e23699 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -86,7 +86,7 @@ line-length = 80 # Enable Pyflakes `E` and `F` codes by default. lint.select = [ # "ANN", # Annotations: missing (return) types -# "B", # Bugbear: common bug patterns or design problems + "B", # Bugbear: common bug patterns or design problems "C4", # Complexity: McCabe complexity checker "E", # Pycodesyle: Style guide enforcement "F", # Pyflakes: Source files errors From 173f2522402b5760bd68b7a903ea70bfca7f312a Mon Sep 17 00:00:00 2001 From: Artur Barseghyan Date: Fri, 22 Nov 2024 21:40:09 +0100 Subject: [PATCH 05/11] More --- fake.py | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/fake.py b/fake.py index 494b632..c240734 100644 --- a/fake.py +++ b/fake.py @@ -315,6 +315,8 @@ SLUGIFY_RE = re.compile(r"[^a-zA-Z0-9]") +TEMP_DIR = gettempdir() + def slugify(value: str, separator: str = "") -> str: """Slugify.""" @@ -758,7 +760,7 @@ class FileSystemStorage(BaseStorage): def __init__( self: "FileSystemStorage", - root_path: Optional[Union[str, Path]] = gettempdir(), + root_path: Optional[Union[str, Path]] = TEMP_DIR, rel_path: Optional[str] = "tmp", *args, **kwargs, @@ -932,7 +934,7 @@ def create( b"0000000010 00000 n \n0000000057 00000 n \n0000000103 00000 n \n" ) offset = 149 - for i in range(self.nb_pages): + for _ in range(self.nb_pages): pdf_bytes.write(f"{offset:010} 00000 n \n".encode()) offset += 78 pdf_bytes.write(f"{offset:010} 00000 n \n".encode()) @@ -1088,7 +1090,7 @@ def _find_authorship_info(self, file_path: str) -> List[str]: def _extract_authorship_info_from_stdlib(self) -> None: stdlib_path = os.path.dirname(os.__file__) - for root, dirs, files in os.walk(stdlib_path): + for root, _, files in os.walk(stdlib_path): for file in files: if file.endswith(".py"): file_path = os.path.join(root, file) @@ -4575,7 +4577,7 @@ def create(cls, **kwargs): model_data[key] = value # Execute pre-init methods - for key, pre_init_method in pre_init_methods.items(): + for pre_init_method in pre_init_methods.values(): pre_init_method.execute(model_data) # Pre-init hooks @@ -4746,7 +4748,7 @@ def create(cls, **kwargs): model_data[key] = value # Execute pre-init methods - for key, pre_init_method in pre_init_methods.items(): + for pre_init_method in pre_init_methods.values(): pre_init_method.execute(model_data) # Pre-init hooks @@ -4933,7 +4935,7 @@ async def async_filter(): model_data[key] = value # Execute pre-init methods - for key, pre_init_method in pre_init_methods.items(): + for pre_init_method in pre_init_methods.values(): pre_init_method.execute(model_data) # Pre-init hooks @@ -5099,7 +5101,7 @@ def create(cls, **kwargs): model_data[key] = value # Execute pre-init methods - for key, pre_init_method in pre_init_methods.items(): + for pre_init_method in pre_init_methods.values(): pre_init_method.execute(model_data) # Pre-init hooks From 422bf87281ec871dbf076124fd058a0a1e6eb726 Mon Sep 17 00:00:00 2001 From: Artur Barseghyan Date: Fri, 22 Nov 2024 21:59:21 +0100 Subject: [PATCH 06/11] More --- fake.py | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/fake.py b/fake.py index c240734..e351e10 100644 --- a/fake.py +++ b/fake.py @@ -4956,17 +4956,21 @@ async def async_filter(): cls._apply_lazy_attributes(instance, model_data) # Handle nested attributes - for attr, value in nested_attrs.items(): - field_name, nested_attr = attr.split("__", 1) - if isinstance(getattr(cls, field_name, None), SubFactory): - - async def async_related_instance(): - return getattr(cls, field_name).factory_class.create( - **{nested_attr: value} + for _attr, _value in nested_attrs.items(): + _field_name, _nested_attr = _attr.split("__", 1) + if isinstance(getattr(cls, _field_name, None), SubFactory): + + async def async_related_instance( + field_name_=_field_name, + nested_attr_=_nested_attr, + value_=_value, + ): + return getattr(cls, field_name_).factory_class.create( + **{nested_attr_: value_} ) related_instance = run_async_in_thread(async_related_instance()) - setattr(instance, field_name, related_instance) + setattr(instance, _field_name, related_instance) # Execute PreSave methods for __pre_save_method in pre_save_methods.values(): @@ -5247,8 +5251,8 @@ def fill(cls, dataclass_type: Type) -> Any: if not provider_func: if is_dataclass(_field.type): # Recursive call for nested dataclass - def provider_func(): - return cls.fill(_field.type) + def provider_func(field_=_field): + return cls.fill(field_.type) else: provider_func = cls.get_provider_for_type(_field.type) From e15649cb4faabd587b80bf64301dfeeb3ecdf0d7 Mon Sep 17 00:00:00 2001 From: Artur Barseghyan Date: Fri, 22 Nov 2024 23:01:29 +0100 Subject: [PATCH 07/11] More --- fake.py | 15 ++++++++------- pyproject.toml | 2 +- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/fake.py b/fake.py index e351e10..f6cc690 100644 --- a/fake.py +++ b/fake.py @@ -187,7 +187,7 @@ ) FILE_TYPES = mimetypes.types_map -FILE_EXTENSIONS = [__v[1:] for __v in FILE_TYPES.keys()] +FILE_EXTENSIONS = [__v[1:] for __v in FILE_TYPES.keys()] # noqa: SIM118 MIME_TYPES = list(FILE_TYPES.values()) UNWANTED_GEO_PATTERN = re.compile( @@ -386,11 +386,13 @@ def returns_list(func: Callable) -> bool: if element_type in {StringValue, BytesValue}: return True element_origin = getattr(element_type, "__origin__", None) - if element_origin is Union: - if set(getattr(element_type, "__args__", [])) == { + if ( + element_origin is Union + and set(getattr(element_type, "__args__", [])) == { BytesValue, StringValue, - }: + } + ): return True return False @@ -1816,9 +1818,8 @@ def load_geo_locations(self) -> None: parts = tz.split("/") _parts = [] for part in parts: - if part: - if not UNWANTED_GEO_PATTERN.match(part): - _parts.append(part.replace("_", " ")) + if part and not UNWANTED_GEO_PATTERN.match(part): + _parts.append(part.replace("_", " ")) if _parts: add_geo_location("/".join(_parts)) diff --git a/pyproject.toml b/pyproject.toml index 9e23699..a32d8ed 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -97,7 +97,7 @@ lint.select = [ "N", # Naming: Variable naming convention "PERF", # Perflint: Performance linting "Q", -# "SIM", # Simplify: Helps simplify your code + "SIM", # Simplify: Helps simplify your code "TD", # TO DO: Format TO DO comments ] lint.ignore = [ From 490cbb1a631d575457fb5930147d51de25a65814 Mon Sep 17 00:00:00 2001 From: Artur Barseghyan Date: Fri, 22 Nov 2024 23:18:09 +0100 Subject: [PATCH 08/11] More --- fake.py | 121 ++++++++++++++++++++++++++------------------------------ 1 file changed, 56 insertions(+), 65 deletions(-) diff --git a/fake.py b/fake.py index f6cc690..7c3a245 100644 --- a/fake.py +++ b/fake.py @@ -1816,10 +1816,11 @@ def load_geo_locations(self) -> None: for tz in zoneinfo.available_timezones(): parts = tz.split("/") - _parts = [] - for part in parts: - if part and not UNWANTED_GEO_PATTERN.match(part): - _parts.append(part.replace("_", " ")) + _parts = [ + part.replace("_", " ") + for part in parts + if part and not UNWANTED_GEO_PATTERN.match(part) + ] if _parts: add_geo_location("/".join(_parts)) @@ -1829,10 +1830,12 @@ def load_geo_locations(self) -> None: country = parts[0].replace("_", "") add_country(country) # Extract cities for Asia and Europe - elif parts[0] in ["Asia", "Europe"]: - if len(parts) > 1: # Check to ensure there is a second part - city = parts[1].replace("_", " ") - add_city(city) + elif ( + parts[0] in ["Asia", "Europe"] + and len(parts) > 1 # Check to ensure there is a second part + ): + city = parts[1].replace("_", " ") + add_city(city) self._cities = list(cities) self._countries = list(countries) @@ -4544,26 +4547,23 @@ def create(cls, **kwargs): pre_save_methods[_field] = value elif isinstance(value, PostSave): post_save_methods[_field] = value - elif not _field.startswith( - ( - "_", - "Meta", - ) - ): - if ( + elif ( + not _field.startswith(("_", "Meta",)) + and ( not getattr(value, "is_trait", False) and not getattr(value, "is_pre_init", False) and not getattr(value, "is_pre_save", False) and not getattr(value, "is_post_save", False) - ): - model_data[_field] = ( - value() - if isinstance( - value, - (FactoryMethod, SubFactory, LazyFunction), - ) - else value + ) + ): + model_data[_field] = ( + value() + if isinstance( + value, + (FactoryMethod, SubFactory, LazyFunction), ) + else value + ) # Update model_data with non-trait kwargs and collect PreSave from # kwargs. @@ -4690,25 +4690,22 @@ def create(cls, **kwargs): pre_save_methods[_field] = value elif isinstance(value, PostSave): post_save_methods[_field] = value - elif not _field.startswith( - ( - "_", - "Meta", - ) - ): - if ( + elif ( + not _field.startswith(("_", "Meta",)) + and ( not getattr(value, "is_trait", False) and not getattr(value, "is_pre_init", False) and not getattr(value, "is_pre_save", False) and not getattr(value, "is_post_save", False) - ): - model_data[_field] = ( - value() - if isinstance( - value, (FactoryMethod, SubFactory, LazyFunction) - ) - else value + ) + ): + model_data[_field] = ( + value() + if isinstance( + value, (FactoryMethod, SubFactory, LazyFunction) ) + else value + ) # TODO: Check if this block is really needed now, that # nested_attrs and direct_attrs are already handled separately @@ -4880,25 +4877,22 @@ async def async_filter(): pre_save_methods[_field] = value elif isinstance(value, PostSave): post_save_methods[_field] = value - elif not _field.startswith( - ( - "_", - "Meta", - ) - ): - if ( + elif ( + not _field.startswith(("_", "Meta",)) + and ( not getattr(value, "is_trait", False) and not getattr(value, "is_pre_init", False) and not getattr(value, "is_pre_save", False) and not getattr(value, "is_post_save", False) - ): - model_data[_field] = ( - value() - if isinstance( - value, (FactoryMethod, SubFactory, LazyFunction) - ) - else value + ) + ): + model_data[_field] = ( + value() + if isinstance( + value, (FactoryMethod, SubFactory, LazyFunction) ) + else value + ) # TODO: Check is this block is needed now that kwargs are split # into nested_attrs and direct_attrs later on. @@ -5050,25 +5044,22 @@ def create(cls, **kwargs): pre_save_methods[_field] = value elif isinstance(value, PostSave): post_save_methods[_field] = value - elif not _field.startswith( - ( - "_", - "Meta", - ) - ): - if ( + elif ( + not _field.startswith(("_", "Meta",)) + and ( not getattr(value, "is_trait", False) and not getattr(value, "is_pre_init", False) and not getattr(value, "is_pre_save", False) and not getattr(value, "is_post_save", False) - ): - model_data[_field] = ( - value() - if isinstance( - value, (FactoryMethod, SubFactory, LazyFunction) - ) - else value + ) + ): + model_data[_field] = ( + value() + if isinstance( + value, (FactoryMethod, SubFactory, LazyFunction) ) + else value + ) # TODO: Check if this is really needed now that kwargs are # handled in direct_attrs later on. From d1091f130fcd06fbf513fbb96d7dc85738809911 Mon Sep 17 00:00:00 2001 From: Artur Barseghyan Date: Fri, 22 Nov 2024 23:23:09 +0100 Subject: [PATCH 09/11] More --- fake.py | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/fake.py b/fake.py index 7c3a245..9a278f5 100644 --- a/fake.py +++ b/fake.py @@ -6057,11 +6057,13 @@ def test_password(self): min_digits, f"Password must contain at least {min_digits} digits.", ) - with self.subTest("Test raises ValueError when length too short."): - with self.assertRaises(ValueError): - self.faker.password( - length=4, min_digits=3 - ) # 2 required characters + 3 digits > 4 + with ( + self.subTest("Test raises ValueError when length too short."), + self.assertRaises(ValueError), + ): + self.faker.password( + length=4, min_digits=3 + ) # 2 required characters + 3 digits > 4 with self.subTest("Test multiple generated passwords are unique."): passwords = {self.faker.password() for _ in range(25)} self.assertEqual(len(passwords), 25, "Passwords should be unique.") @@ -6141,13 +6143,17 @@ def test_pydecimal(self): ) self.assertTrue(-1 < decimal_number_neg <= 0) - with self.subTest("Fail on `left_digits` < 0"): - with self.assertRaises(ValueError): - self.faker.pydecimal(left_digits=-1) + with ( + self.subTest("Fail on `left_digits` < 0"), + self.assertRaises(ValueError), + ): + self.faker.pydecimal(left_digits=-1) - with self.subTest("Fail on `right_digits` < 0"): - with self.assertRaises(ValueError): - self.faker.pydecimal(right_digits=-1) + with ( + self.subTest("Fail on `right_digits` < 0"), + self.assertRaises(ValueError), + ): + self.faker.pydecimal(right_digits=-1) def test_ipv4(self) -> None: # Test a large number of IPs to ensure randomness and correctness From fd64dbe9071fc2167e16dd538f1457405b998790 Mon Sep 17 00:00:00 2001 From: Artur Barseghyan Date: Fri, 22 Nov 2024 23:28:33 +0100 Subject: [PATCH 10/11] More --- fake.py | 48 +++++++++++++++++++++++++++++------------------- 1 file changed, 29 insertions(+), 19 deletions(-) diff --git a/fake.py b/fake.py index 9a278f5..64c7f16 100644 --- a/fake.py +++ b/fake.py @@ -6246,13 +6246,15 @@ def test_date_time(self) -> None: ) def test_text_pdf(self) -> None: - with self.subTest("All params None, should fail"): - with self.assertRaises(ValueError): - self.faker.pdf( - nb_pages=None, - texts=None, - generator=TextPdfGenerator, - ) + with ( + self.subTest("All params None, should fail"), + self.assertRaises(ValueError), + ): + self.faker.pdf( + nb_pages=None, + texts=None, + generator=TextPdfGenerator, + ) with self.subTest("Without params"): pdf = self.faker.pdf(generator=TextPdfGenerator) @@ -6331,9 +6333,11 @@ def test_image(self): self.assertTrue(image) self.assertIsInstance(image, bytes) for image_format in {"bin"}: - with self.subTest(image_format=image_format): - with self.assertRaises(ValueError): - self.faker.image(image_format=image_format) + with ( + self.subTest(image_format=image_format), + self.assertRaises(ValueError), + ): + self.faker.image(image_format=image_format) def test_wav(self) -> None: wav = self.faker.wav() @@ -6341,9 +6345,11 @@ def test_wav(self) -> None: self.assertIsInstance(wav, bytes) def test_docx(self) -> None: - with self.subTest("All params None, should fail"): - with self.assertRaises(ValueError): - self.faker.docx(nb_pages=None, texts=None), # noqa + with ( + self.subTest("All params None, should fail"), + self.assertRaises(ValueError), + ): + self.faker.docx(nb_pages=None, texts=None), # noqa with self.subTest("Without params"): docx = self.faker.docx() @@ -6357,9 +6363,11 @@ def test_docx(self) -> None: self.assertIsInstance(docx, bytes) def test_odt(self) -> None: - with self.subTest("All params None, should fail"): - with self.assertRaises(ValueError): - self.faker.odt(nb_pages=None, texts=None), # noqa + with ( + self.subTest("All params None, should fail"), + self.assertRaises(ValueError), + ): + self.faker.odt(nb_pages=None, texts=None), # noqa with self.subTest("Without params"): odt = self.faker.odt() @@ -7023,9 +7031,11 @@ def objects(cls): # noqa: N805 instance=fill_dataclass(cls), # type: ignore ) - with self.subTest("fill_pydantic_model on dataclass"): - with self.assertRaises(ValueError): - _article = fill_pydantic_model(Article) + with ( + self.subTest("fill_pydantic_model on dataclass"), + self.assertRaises(ValueError), + ): + _article = fill_pydantic_model(Article) with self.subTest("fill_pydantic_model"): _obj = fill_pydantic_model(MockPydanticModel) From b0610cbf2457b90796328eb34827f9a6e359e667 Mon Sep 17 00:00:00 2001 From: Artur Barseghyan Date: Fri, 22 Nov 2024 23:30:04 +0100 Subject: [PATCH 11/11] More --- CHANGELOG.rst | 1 + Makefile | 2 +- fake.py | 2 +- pyproject.toml | 2 +- 4 files changed, 4 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 025f9e0..12601de 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -24,6 +24,7 @@ are used for versioning (schema follows below): - Improve docs. Add a dedicated section on files creation. - Minor clean-up. - Test against Django 5.1. +- Clean-up. 0.10.4 ------ diff --git a/Makefile b/Makefile index 77683b8..b59eb59 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,5 @@ # Update version ONLY here -VERSION := 0.10.4 +VERSION := 0.10.5 SHELL := /bin/bash # Makefile for project VENV := ~/.virtualenvs/fake.py/bin/activate diff --git a/fake.py b/fake.py index 64c7f16..31333c8 100644 --- a/fake.py +++ b/fake.py @@ -67,7 +67,7 @@ from uuid import UUID __title__ = "fake.py" -__version__ = "0.10.4" +__version__ = "0.10.5" __author__ = "Artur Barseghyan " __copyright__ = "2023-2024 Artur Barseghyan" __license__ = "MIT" diff --git a/pyproject.toml b/pyproject.toml index a32d8ed..b09f33f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -2,7 +2,7 @@ name = "fake.py" description = "Minimalistic, standalone alternative fake data generator with no dependencies." readme = "README.rst" -version = "0.10.4" +version = "0.10.5" dependencies = [] authors = [ {name = "Artur Barseghyan", email = "artur.barseghyan@gmail.com"},