From 1915795ddfd109b3489056758965d1dcdae8a47e Mon Sep 17 00:00:00 2001 From: Artur Barseghyan Date: Fri, 27 Sep 2024 01:30:39 +0200 Subject: [PATCH] Docs/fixes (#188) * More --- CHANGELOG.rst | 10 ++++ Makefile | 2 +- docs/creating_archives.rst | 2 +- docs/creating_docx.rst | 4 +- docs/creating_odt.rst | 4 +- fake.py | 118 +++++++++++++++++++------------------ pyproject.toml | 2 +- 7 files changed, 77 insertions(+), 65 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index a615280..04cc2b7 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -16,6 +16,16 @@ are used for versioning (schema follows below): 0.3.4 to 0.4). - All backwards incompatible changes are mentioned in this document. +0.10 +---- +2024-09-27 + +- For both ``StringTemplate`` and ``LazyStringTemplate`` the ``faker`` + argument had become optional and positionally moved from first to the last + place. +- Improve string templates. +- Minor documentation improvements. + 0.9.9 ----- 2024-09-27 diff --git a/Makefile b/Makefile index 229bb16..082f8ef 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,5 @@ # Update version ONLY here -VERSION := 0.9.9 +VERSION := 0.10 SHELL := /bin/bash # Makefile for project VENV := ~/.virtualenvs/fake.py/bin/activate diff --git a/docs/creating_archives.rst b/docs/creating_archives.rst index bf1e934..1255cc0 100644 --- a/docs/creating_archives.rst +++ b/docs/creating_archives.rst @@ -325,4 +325,4 @@ Using text templates: {domain_name} """ # EML file - eml_file = FAKER.eml_file(content=StringTemplate(FAKER, template)) + eml_file = FAKER.eml_file(content=StringTemplate(template)) diff --git a/docs/creating_docx.rst b/docs/creating_docx.rst index 49b2300..78d7292 100644 --- a/docs/creating_docx.rst +++ b/docs/creating_docx.rst @@ -120,9 +120,9 @@ Using text templates: """ # DOCX file of 1 page docx_file_1 = FAKER.docx_file( - texts=[StringTemplate(FAKER, template)], + texts=[StringTemplate(template)], ) # DOCX file of 10 pages docx_file_10 = FAKER.odt_file( - texts=[StringTemplate(FAKER, template) for _ in range(10)], + texts=[StringTemplate(template) for _ in range(10)], ) diff --git a/docs/creating_odt.rst b/docs/creating_odt.rst index a5c42e3..1e2d55f 100644 --- a/docs/creating_odt.rst +++ b/docs/creating_odt.rst @@ -120,9 +120,9 @@ Using text templates: """ # ODT file of 1 page odt_file_1 = FAKER.odt_file( - texts=[StringTemplate(FAKER, template)], + texts=[StringTemplate(template)], ) # ODT file of 10 pages odt_file_10 = FAKER.odt_file( - texts=[StringTemplate(FAKER, template) for _ in range(10)], + texts=[StringTemplate(template) for _ in range(10)], ) diff --git a/fake.py b/fake.py index 74b2a67..bdbdf80 100644 --- a/fake.py +++ b/fake.py @@ -65,7 +65,7 @@ from uuid import UUID __title__ = "fake.py" -__version__ = "0.9.9" +__version__ = "0.10" __author__ = "Artur Barseghyan " __copyright__ = "2023-2024 Artur Barseghyan" __license__ = "MIT" @@ -387,9 +387,9 @@ def wrap_text(text: str, wrap_chars_after: int) -> str: class StringTemplateMixin: - faker: "Faker" template: str wrap_chars_after: Optional[int] + faker: Optional["Faker"] # Regular expression to match placeholders with optional arguments placeholder_pattern = re.compile(r"\{(\w+)(?:\((.*?)\))?}") @@ -483,7 +483,7 @@ class StringTemplate(str, StringTemplateMixin): "Best regards,\n" "{name}" ) - string_template = StringTemplate(FAKER, template) + string_template = StringTemplate(template) print(string_template) Integration with providers: @@ -499,27 +499,27 @@ class StringTemplate(str, StringTemplateMixin): "Best regards,\n" "{name}" ) - string_template = StringTemplate(FAKER, template) + string_template = StringTemplate(template) FAKER.docx_file( - texts=[StringTemplate(FAKER, template) for _ in range(10)] + texts=[StringTemplate(template) for _ in range(10)] ) FAKER.eml_file(content=string_template) FAKER.txt_file(text=string_template) FAKER.text_pdf_file( - texts=[StringTemplate(FAKER, template) for _ in range(10)] + texts=[StringTemplate(template) for _ in range(10)] ) """ def __new__( cls, - faker: "Faker", template: str, wrap_chars_after: Optional[int] = None, + faker: Optional["Faker"] = None, ) -> "StringTemplate": # Create a temporary instance to use render instance = super().__new__(cls, "") - instance.faker = faker + instance.faker = faker or FAKER instance.template = template instance.wrap_chars_after = wrap_chars_after # Render the content @@ -544,7 +544,7 @@ class LazyStringTemplate(StringTemplateMixin): "Best regards,\n" "{name}" ) - string_template = LazyStringTemplate(FAKER, template) + string_template = LazyStringTemplate(template) print(string_template.render()) Integration with providers: @@ -560,7 +560,7 @@ class LazyStringTemplate(StringTemplateMixin): "Best regards,\n" "{name}" ) - string_template = LazyStringTemplate(FAKER, template) + string_template = LazyStringTemplate(template) FAKER.docx_file(texts=[str(string_template)]) FAKER.eml_file(content=str(string_template)) @@ -570,11 +570,11 @@ class LazyStringTemplate(StringTemplateMixin): def __init__( self, - faker: "Faker", template: str, wrap_chars_after: Optional[int] = None, + faker: Optional["Faker"] = None, ) -> None: - self.faker = faker + self.faker = faker or FAKER self.template = template self.wrap_chars_after = wrap_chars_after @@ -7575,7 +7575,7 @@ def setUp(self): def test_simple_placeholder_replacement(self): template = "Hello, {name()}!" - string_template = LazyStringTemplate(self.mock_faker, template) + string_template = LazyStringTemplate(template, faker=self.mock_faker) expected = "Hello, John Doe!" result = string_template.render() self.assertEqual(result, expected) @@ -7583,7 +7583,7 @@ def test_simple_placeholder_replacement(self): def test_placeholder_with_arguments(self): template = "Sentence: {sentence(nb_words=5)}" - string_template = LazyStringTemplate(self.mock_faker, template) + string_template = LazyStringTemplate(template, faker=self.mock_faker) expected = "Sentence: This is a test sentence." result = string_template.render() self.assertEqual(result, expected) @@ -7596,7 +7596,7 @@ def test_multiple_placeholders(self): "Date: {date(start_date='-7d')}\n" "Custom: {custom_method(param='value')}" ) - string_template = LazyStringTemplate(self.mock_faker, template) + string_template = LazyStringTemplate(template, faker=self.mock_faker) expected = ( "Name: John Doe\n" "Sentence: This is a test sentence.\n" @@ -7613,7 +7613,7 @@ def test_multiple_placeholders(self): def test_wrapping_functionality(self): template = "This is a long sentence that needs to be wrapped." string_template = LazyStringTemplate( - self.mock_faker, template, wrap_chars_after=10 + template, wrap_chars_after=10, faker=self.mock_faker ) expected = "This is a\nlong\nsentence\nthat needs\nto be\nwrapped." result = string_template.render() @@ -7621,14 +7621,14 @@ def test_wrapping_functionality(self): def test_no_wrapping_when_not_specified(self): template = "This is a long sentence that does not need to be wrapped." - string_template = LazyStringTemplate(self.mock_faker, template) + string_template = LazyStringTemplate(template, faker=self.mock_faker) expected = "This is a long sentence that does not need to be wrapped." result = string_template.render() self.assertEqual(result, expected) def test_missing_method_raises_attribute_error(self): template = "Hello, {nonexistent_method()}!" - string_template = LazyStringTemplate(self.faker, template) + string_template = LazyStringTemplate(template, faker=self.faker) with self.assertRaises(AttributeError) as context: string_template.render() self.assertIn( @@ -7637,7 +7637,7 @@ def test_missing_method_raises_attribute_error(self): def test_argument_parsing_error_raises_value_error(self): template = "Date: {date(start_date='-7d' missing_comma)}" - string_template = LazyStringTemplate(self.mock_faker, template) + string_template = LazyStringTemplate(template, faker=self.mock_faker) with self.assertRaises(ValueError) as context: string_template.render() self.assertIn( @@ -7649,7 +7649,7 @@ def test_method_call_error_raises_value_error(self): # Configure the mock to raise an exception when called self.mock_faker.name.side_effect = Exception("Method error") template = "Hello, {name()}!" - string_template = LazyStringTemplate(self.mock_faker, template) + string_template = LazyStringTemplate(template, faker=self.mock_faker) with self.assertRaises(ValueError) as context: string_template.render() self.assertIn("Error calling method 'name'", str(context.exception)) @@ -7657,7 +7657,7 @@ def test_method_call_error_raises_value_error(self): def test_no_placeholders(self): template = "This string has no placeholders." - string_template = LazyStringTemplate(self.mock_faker, template) + string_template = LazyStringTemplate(template, faker=self.mock_faker) expected = "This string has no placeholders." result = string_template.render() self.assertEqual(result, expected) @@ -7666,14 +7666,14 @@ def test_no_placeholders(self): def test_str_method(self): template = "Hello, {name()}!" - string_template = LazyStringTemplate(self.mock_faker, template) + string_template = LazyStringTemplate(template, faker=self.mock_faker) expected = "Hello, John Doe!" result = str(string_template) self.assertEqual(result, expected) def test_repr_method(self): template = "Hello, {name()}!" - string_template = LazyStringTemplate(self.mock_faker, template) + string_template = LazyStringTemplate(template, faker=self.mock_faker) expected = "Hello, John Doe!" result = repr(string_template) self.assertEqual(result, expected) @@ -7681,7 +7681,7 @@ def test_repr_method(self): def test_complex_argument_parsing(self): # Test with multiple arguments and different types template = "Custom: {custom_method(param1='value1', param2=123)}" - string_template = LazyStringTemplate(self.mock_faker, template) + string_template = LazyStringTemplate(template, faker=self.mock_faker) expected = "Custom: Custom value" result = string_template.render() self.assertEqual(result, expected) @@ -7693,7 +7693,7 @@ def test_nested_placeholders(self): # Although nested placeholders are not supported, ensure they are # handled gracefully. template = "Nested: {{name()}}" - string_template = LazyStringTemplate(self.mock_faker, template) + string_template = LazyStringTemplate(template, faker=self.mock_faker) # The regex should match {name()}, so {{name()}} becomes {John Doe} expected = "Nested: {John Doe}" result = string_template.render() @@ -7703,7 +7703,7 @@ def test_nested_placeholders(self): def test_escape_braces(self): # Test that escaped braces are handled correctly template = "Escaped braces: \\{name()\\}" - string_template = LazyStringTemplate(self.faker, template) + string_template = LazyStringTemplate(template, faker=self.faker) expected = "Escaped braces: \\{name()\\}" result = string_template.render() self.assertEqual(result, expected) @@ -7713,7 +7713,7 @@ def test_placeholder_with_no_parentheses(self): # Test that placeholders without parentheses are handled (assuming # they require parentheses). template = "Hello, {name}!" - string_template = LazyStringTemplate(self.mock_faker, template) + string_template = LazyStringTemplate(template, faker=self.mock_faker) # The regex expects parentheses, so {name} should remain unchanged expected = "Hello, John Doe!" result = string_template.render() @@ -7723,7 +7723,7 @@ def test_placeholder_with_no_parentheses(self): def test_placeholder_with_empty_arguments(self): # Test placeholders with empty parentheses template = "Hello, {name()} and {sentence()}!" - string_template = LazyStringTemplate(self.mock_faker, template) + string_template = LazyStringTemplate(template, faker=self.mock_faker) expected = "Hello, John Doe and This is a test sentence.!" result = string_template.render() self.assertEqual(result, expected) @@ -7735,7 +7735,7 @@ def test_placeholder_with_spaces_in_arguments(self): template = ( "Date: {date(start_date = '2020-01-01', end_date = '2020-12-31')}" ) - string_template = LazyStringTemplate(self.mock_faker, template) + string_template = LazyStringTemplate(template, faker=self.mock_faker) expected = "Date: 2023-01-01" result = string_template.render() self.assertEqual(result, expected) @@ -7747,7 +7747,7 @@ def test_placeholder_with_numeric_method_name(self): # Assuming method names are purely alphabetic, but testing with # numeric characters. template = "Numeric method: {method123()}!" - string_template = LazyStringTemplate(self.mock_faker, template) + string_template = LazyStringTemplate(template, faker=self.mock_faker) self.mock_faker.method123.return_value = "Numeric method" expected = "Numeric method: Numeric method!" result = string_template.render() @@ -7757,7 +7757,7 @@ def test_placeholder_with_numeric_method_name(self): def test_placeholder_with_underscores_in_method_name(self): # Test method names with underscores template = "Underscore method: {custom_method()}!" - string_template = LazyStringTemplate(self.mock_faker, template) + string_template = LazyStringTemplate(template, faker=self.mock_faker) expected = "Underscore method: Custom value!" result = string_template.render() self.assertEqual(result, expected) @@ -7767,7 +7767,7 @@ def test_placeholder_with_boolean_arguments(self): # Test placeholders with boolean arguments self.mock_faker.boolean_method.return_value = "Boolean result" template = "Boolean: {boolean_method(flag=True)}" - string_template = LazyStringTemplate(self.mock_faker, template) + string_template = LazyStringTemplate(template, faker=self.mock_faker) expected = "Boolean: Boolean result" result = string_template.render() self.assertEqual(result, expected) @@ -7788,21 +7788,21 @@ def setUp(self): def test_instance_is_str(self): template = "Hello, {name()}!" - string_template = StringTemplate(self.mock_faker, template) + string_template = StringTemplate(template, faker=self.mock_faker) self.assertIsInstance(string_template, str) self.assertIsInstance(string_template, StringTemplate) self.assertEqual(string_template, "Hello, John Doe!") def test_simple_placeholder_replacement(self): template = "Hello, {name()}!" - string_template = StringTemplate(self.mock_faker, template) + string_template = StringTemplate(template, faker=self.mock_faker) expected = "Hello, John Doe!" self.assertEqual(string_template, expected) self.mock_faker.name.assert_called_once() def test_placeholder_with_arguments(self): template = "Sentence: {sentence(nb_words=5)}" - string_template = StringTemplate(self.mock_faker, template) + string_template = StringTemplate(template, faker=self.mock_faker) expected = "Sentence: This is a test sentence." self.assertEqual(string_template, expected) self.mock_faker.sentence.assert_called_once_with(nb_words=5) @@ -7814,7 +7814,7 @@ def test_multiple_placeholders(self): "Date: {date(start_date='-7d')}\n" "Custom: {custom_method(param='value')}" ) - string_template = StringTemplate(self.mock_faker, template) + string_template = StringTemplate(template, faker=self.mock_faker) expected = ( "Name: John Doe\n" "Sentence: This is a test sentence.\n" @@ -7830,14 +7830,16 @@ def test_multiple_placeholders(self): def test_wrapping_functionality(self): template = "This is a long sentence that needs to be wrapped." string_template = StringTemplate( - self.mock_faker, template, wrap_chars_after=10 + template, + wrap_chars_after=10, + faker=self.mock_faker, ) expected = "This is a\nlong\nsentence\nthat needs\nto be\nwrapped." self.assertEqual(string_template, expected) def test_no_wrapping_when_not_specified(self): template = "This is a long sentence that does not need to be wrapped." - string_template = StringTemplate(self.mock_faker, template) + string_template = StringTemplate(template, faker=self.mock_faker) expected = "This is a long sentence that does not need to be wrapped." self.assertEqual(string_template, expected) # No faker methods should be called @@ -7846,7 +7848,7 @@ def test_no_wrapping_when_not_specified(self): def test_missing_method_raises_attribute_error(self): template = "Hello, {nonexistent_method()}!" with self.assertRaises(AttributeError) as context: - StringTemplate(self.faker, template) + StringTemplate(template, faker=self.faker) self.assertIn( "Method 'nonexistent_method' not found", str(context.exception), @@ -7855,7 +7857,7 @@ def test_missing_method_raises_attribute_error(self): def test_argument_parsing_error_raises_value_error(self): template = "Date: {date(start_date='-7d' missing_comma)}" with self.assertRaises(ValueError) as context: - StringTemplate(self.mock_faker, template) + StringTemplate(template, faker=self.mock_faker) self.assertIn( "Error parsing arguments for 'date'", str(context.exception), @@ -7867,13 +7869,13 @@ def test_method_call_error_raises_value_error(self): self.mock_faker.name.side_effect = Exception("Method error") template = "Hello, {name()}!" with self.assertRaises(ValueError) as context: - StringTemplate(self.mock_faker, template) + StringTemplate(template, faker=self.mock_faker) self.assertIn("Error calling method 'name'", str(context.exception)) self.mock_faker.name.assert_called_once() def test_no_placeholders(self): template = "This string has no placeholders." - string_template = StringTemplate(self.mock_faker, template) + string_template = StringTemplate(template, faker=self.mock_faker) expected = "This string has no placeholders." self.assertEqual(string_template, expected) # No faker methods should be called @@ -7881,14 +7883,14 @@ def test_no_placeholders(self): def test_str_method(self): template = "Hello, {name()}!" - string_template = StringTemplate(self.mock_faker, template) + string_template = StringTemplate(template, faker=self.mock_faker) expected = "Hello, John Doe!" result = str(string_template) self.assertEqual(result, expected) def test_repr_method(self): template = "Hello, {name()}!" - string_template = StringTemplate(self.mock_faker, template) + string_template = StringTemplate(template, faker=self.mock_faker) expected = "'Hello, John Doe!'" result = repr(string_template) self.assertEqual(result, expected) @@ -7896,7 +7898,7 @@ def test_repr_method(self): def test_complex_argument_parsing(self): # Test with multiple arguments and different types template = "Custom: {custom_method(param1='value1', param2=123)}" - string_template = StringTemplate(self.mock_faker, template) + string_template = StringTemplate(template, faker=self.mock_faker) expected = "Custom: Custom value" self.assertEqual(string_template, expected) self.mock_faker.custom_method.assert_called_once_with( @@ -7907,7 +7909,7 @@ def test_nested_placeholders(self): # Although nested placeholders are not supported, ensure they are # handled gracefully. template = "Nested: {{name()}}" - string_template = StringTemplate(self.mock_faker, template) + string_template = StringTemplate(template, faker=self.mock_faker) # The regex should match {name()}, so {{name()}} becomes {John Doe} expected = "Nested: {John Doe}" self.assertEqual(string_template, expected) @@ -7916,7 +7918,7 @@ def test_nested_placeholders(self): def test_escape_braces(self): # Test that escaped braces are handled correctly template = "Escaped braces: \\{name()\\}" - string_template = StringTemplate(self.mock_faker, template) + string_template = StringTemplate(template, faker=self.mock_faker) expected = "Escaped braces: \\{name()\\}" self.assertEqual(string_template, expected) self.mock_faker.name.assert_not_called() @@ -7925,7 +7927,7 @@ def test_placeholder_with_no_parentheses(self): # Test that placeholders without parentheses are handled (assuming # they require parentheses). template = "Hello, {name}!" - string_template = StringTemplate(self.mock_faker, template) + string_template = StringTemplate(template, faker=self.mock_faker) # The regex expects parentheses, so {name} should remain unchanged expected = "Hello, John Doe!" self.assertEqual(string_template, expected) @@ -7934,7 +7936,7 @@ def test_placeholder_with_no_parentheses(self): def test_placeholder_with_empty_arguments(self): # Test placeholders with empty parentheses template = "Hello, {name()} and {sentence()}!" - string_template = StringTemplate(self.mock_faker, template) + string_template = StringTemplate(template, faker=self.mock_faker) expected = "Hello, John Doe and This is a test sentence.!" self.assertEqual(string_template, expected) self.mock_faker.name.assert_called_once() @@ -7945,7 +7947,7 @@ def test_placeholder_with_spaces_in_arguments(self): template = ( "Date: {date(start_date = '2020-01-01', end_date = '2020-12-31')}" ) - string_template = StringTemplate(self.mock_faker, template) + string_template = StringTemplate(template, faker=self.mock_faker) expected = "Date: 2023-01-01" self.assertEqual(string_template, expected) self.mock_faker.date.assert_called_once_with( @@ -7956,7 +7958,7 @@ def test_placeholder_with_numeric_method_name(self): # Assuming method names are purely alphabetic, but testing with # numeric characters. template = "Numeric method: {method123()}!" - string_template = StringTemplate(self.mock_faker, template) + string_template = StringTemplate(template, faker=self.mock_faker) expected = "Numeric method: Numeric method!" self.assertEqual(string_template, expected) self.mock_faker.method123.assert_called_once() @@ -7964,7 +7966,7 @@ def test_placeholder_with_numeric_method_name(self): def test_placeholder_with_underscores_in_method_name(self): # Test method names with underscores template = "Underscore method: {custom_method()}!" - string_template = StringTemplate(self.mock_faker, template) + string_template = StringTemplate(template, faker=self.mock_faker) expected = "Underscore method: Custom value!" self.assertEqual(string_template, expected) self.mock_faker.custom_method.assert_called_once() @@ -7972,7 +7974,7 @@ def test_placeholder_with_underscores_in_method_name(self): def test_placeholder_with_boolean_arguments(self): # Test placeholders with boolean arguments template = "Boolean: {boolean_method(flag=True)}" - string_template = StringTemplate(self.mock_faker, template) + string_template = StringTemplate(template, faker=self.mock_faker) expected = "Boolean: Boolean result" self.assertEqual(string_template, expected) self.mock_faker.boolean_method.assert_called_once_with(flag=True) @@ -7980,9 +7982,9 @@ def test_placeholder_with_boolean_arguments(self): def test_join_with_string_template(self): # Test that StringTemplate can be used directly with join templates = [ - StringTemplate(self.mock_faker, "Hello, {name()}!"), - StringTemplate(self.mock_faker, "Welcome, {name()}!"), - StringTemplate(self.mock_faker, "Goodbye, {name()}!"), + StringTemplate("Hello, {name()}!", faker=self.mock_faker), + StringTemplate("Welcome, {name()}!", faker=self.mock_faker), + StringTemplate("Goodbye, {name()}!", faker=self.mock_faker), ] expected = ( "Hello, John Doe!\n---\nWelcome, John Doe!\n---\nGoodbye, John Doe!" @@ -7996,7 +7998,7 @@ def test_large_number_of_placeholders(self): # Test performance and correctness with a large number of placeholders template = "User {name()} has email {email()}." * 1000 self.mock_faker.email.return_value = "john.doe@example.com" - string_template = StringTemplate(self.mock_faker, template) + string_template = StringTemplate(template, faker=self.mock_faker) expected = "User John Doe has email john.doe@example.com." * 1000 self.assertEqual(string_template, expected) self.assertEqual(self.mock_faker.name.call_count, 1000) @@ -8012,7 +8014,7 @@ def test_join_with_no_templates(self): def test_join_with_single_template(self): # Test joining a single template template = "Hello, {name()}!" - string_template = StringTemplate(self.mock_faker, template) + string_template = StringTemplate(template, faker=self.mock_faker) expected = "Hello, John Doe!" joined_string = "\n---\n".join([string_template]) self.assertEqual(joined_string, expected) diff --git a/pyproject.toml b/pyproject.toml index 83b6fe5..35181c9 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.9.9" +version = "0.10" dependencies = [] authors = [ {name = "Artur Barseghyan", email = "artur.barseghyan@gmail.com"},