From 96011238b33012c98dbd9fe28f8792a5dfabe560 Mon Sep 17 00:00:00 2001 From: Fabio Caccamo Date: Thu, 8 Jun 2023 11:12:30 +0200 Subject: [PATCH 1/5] Remove `requests` from requirements. --- pyproject.toml | 1 - requirements.txt | 1 - 2 files changed, 2 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 5fe52e0..bec1aa3 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -93,7 +93,6 @@ dependencies = [ "python-dateutil >= 2.8.0, < 3.0.0", "python-fsutil >= 0.9.3, < 1.0.0", "python-slugify >= 7.0.0, < 9.0.0", - "requests >= 2.26.0, < 3.0.0", ] dynamic = ["version"] maintainers = [ diff --git a/requirements.txt b/requirements.txt index f11d3b9..16788d8 100644 --- a/requirements.txt +++ b/requirements.txt @@ -7,7 +7,6 @@ python-dateutil == 2.8.2 python-fsutil == 0.10.0 python-slugify == 8.0.1 pyyaml == 6.0 -requests == 2.31.0 toml == 0.10.2 xlrd == 2.0.1 xmltodict == 0.13.0 From 85de7c1f394d18076eccb2002fda6b3269667af9 Mon Sep 17 00:00:00 2001 From: Fabio Caccamo Date: Sat, 17 Jun 2023 22:06:37 +0200 Subject: [PATCH 2/5] Rename internal method. --- benedict/extras.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/benedict/extras.py b/benedict/extras.py index 592f85b..6aedd4c 100644 --- a/benedict/extras.py +++ b/benedict/extras.py @@ -9,26 +9,26 @@ __all__ = [ ] -def _require_optional_module(*, target, installed): +def _require_optional_dependencies(*, target, installed): if not installed: raise ExtrasRequireModuleNotFoundError(target=target) def require_s3(*, installed): - _require_optional_module(target="s3", installed=installed) + _require_optional_dependencies(target="s3", installed=installed) def require_toml(*, installed): - _require_optional_module(target="toml", installed=installed) + _require_optional_dependencies(target="toml", installed=installed) def require_xls(*, installed): - _require_optional_module(target="xls", installed=installed) + _require_optional_dependencies(target="xls", installed=installed) def require_xml(*, installed): - _require_optional_module(target="xml", installed=installed) + _require_optional_dependencies(target="xml", installed=installed) def require_yaml(*, installed): - _require_optional_module(target="yaml", installed=installed) + _require_optional_dependencies(target="yaml", installed=installed) From 521e49a0faf1cc97ebe6744446e2be57fd18de6a Mon Sep 17 00:00:00 2001 From: Fabio Caccamo Date: Sat, 17 Jun 2023 22:07:00 +0200 Subject: [PATCH 3/5] Re-add requests requirement. --- pyproject.toml | 1 + requirements.txt | 1 + 2 files changed, 2 insertions(+) diff --git a/pyproject.toml b/pyproject.toml index bec1aa3..5fe52e0 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -93,6 +93,7 @@ dependencies = [ "python-dateutil >= 2.8.0, < 3.0.0", "python-fsutil >= 0.9.3, < 1.0.0", "python-slugify >= 7.0.0, < 9.0.0", + "requests >= 2.26.0, < 3.0.0", ] dynamic = ["version"] maintainers = [ diff --git a/requirements.txt b/requirements.txt index a8694f5..e484767 100644 --- a/requirements.txt +++ b/requirements.txt @@ -7,6 +7,7 @@ python-dateutil == 2.8.2 python-fsutil == 0.10.0 python-slugify == 8.0.1 pyyaml == 6.0 +requests == 2.31.0 toml == 0.10.2 xlrd == 2.0.1 xmltodict == 0.13.0 From 9f1d5b128e7cf58d1998f63beec0a5be267fc01d Mon Sep 17 00:00:00 2001 From: Fabio Caccamo Date: Sat, 17 Jun 2023 22:26:36 +0200 Subject: [PATCH 4/5] Add `parse` extra (optional dependencies). --- README.md | 1 + benedict/dicts/parse/parse_util.py | 22 ++++++++++++---- benedict/extras.py | 5 ++++ pyproject.toml | 12 +++++---- tests/dicts/parse/test_parse_dict.py | 39 ++++++++++++++++++++++++++++ tests/dicts/parse/test_parse_util.py | 16 ++++++++++++ 6 files changed, 85 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index afbccb3..e57f20e 100644 --- a/README.md +++ b/README.md @@ -61,6 +61,7 @@ Here the hierarchy of possible installation targets available when running `pip - `[xls]` - `[xml]` - `[yaml]` + - `[parse]` - `[s3]` ## Usage diff --git a/benedict/dicts/parse/parse_util.py b/benedict/dicts/parse/parse_util.py index 7146069..dc68c5a 100644 --- a/benedict/dicts/parse/parse_util.py +++ b/benedict/dicts/parse/parse_util.py @@ -2,13 +2,21 @@ import re from datetime import datetime from decimal import Decimal, DecimalException -import ftfy -import phonenumbers -from dateutil import parser as date_parser -from MailChecker import MailChecker -from phonenumbers import PhoneNumberFormat, phonenumberutil +try: + import ftfy + import phonenumbers + from dateutil import parser as date_parser + from MailChecker import MailChecker + from phonenumbers import PhoneNumberFormat, phonenumberutil + + parse_installed = True +except ModuleNotFoundError: + parse_installed = False + + from slugify import slugify +from benedict.extras import require_parse from benedict.serializers import JSONSerializer from benedict.utils import type_util @@ -66,6 +74,7 @@ def _parse_datetime_from_timestamp(val): def parse_datetime(val, format=None): + require_parse(installed=parse_installed) if type_util.is_datetime(val): return val s = str(val) @@ -124,6 +133,7 @@ def _parse_email(val, check_blacklist=True): def parse_email(val, check_blacklist=True): + require_parse(installed=parse_installed) return _parse_with(val, None, _parse_email, check_blacklist=check_blacklist) @@ -183,6 +193,7 @@ def _parse_phonenumber(val, country_code=None): def parse_phonenumber(val, country_code=None): + require_parse(installed=parse_installed) s = parse_str(val) if not s: return None @@ -205,6 +216,7 @@ def parse_slug(val): def parse_str(val): + require_parse(installed=parse_installed) if type_util.is_string(val): val = ftfy.fix_text(val) else: diff --git a/benedict/extras.py b/benedict/extras.py index 6aedd4c..476e49f 100644 --- a/benedict/extras.py +++ b/benedict/extras.py @@ -1,6 +1,7 @@ from benedict.exceptions import ExtrasRequireModuleNotFoundError __all__ = [ + "require_parse", "require_s3", "require_toml", "require_xls", @@ -14,6 +15,10 @@ def _require_optional_dependencies(*, target, installed): raise ExtrasRequireModuleNotFoundError(target=target) +def require_parse(*, installed): + _require_optional_dependencies(target="parse", installed=installed) + + def require_s3(*, installed): _require_optional_dependencies(target="s3", installed=installed) diff --git a/pyproject.toml b/pyproject.toml index 5fe52e0..9d2204c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -87,10 +87,6 @@ classifiers = [ "Topic :: Utilities", ] dependencies = [ - "ftfy >= 6.0.0, < 7.0.0", - "mailchecker >= 4.1.0, < 6.0.0", - "phonenumbers >= 8.12.0, < 9.0.0", - "python-dateutil >= 2.8.0, < 3.0.0", "python-fsutil >= 0.9.3, < 1.0.0", "python-slugify >= 7.0.0, < 9.0.0", "requests >= 2.26.0, < 3.0.0", @@ -118,11 +114,17 @@ Twitter = "https://twitter.com/fabiocaccamo" [project.optional-dependencies] all = [ - "python-benedict[io,s3]", + "python-benedict[io,parse,s3]", ] io = [ "python-benedict[toml,xls,xml,yaml]", ] +parse = [ + "ftfy >= 6.0.0, < 7.0.0", + "mailchecker >= 4.1.0, < 6.0.0", + "phonenumbers >= 8.12.0, < 9.0.0", + "python-dateutil >= 2.8.0, < 3.0.0", +] s3 = [ "boto3 >= 1.24.89, < 2.0.0", ] diff --git a/tests/dicts/parse/test_parse_dict.py b/tests/dicts/parse/test_parse_dict.py index bf7e225..3157bb3 100644 --- a/tests/dicts/parse/test_parse_dict.py +++ b/tests/dicts/parse/test_parse_dict.py @@ -1,8 +1,10 @@ import unittest from datetime import datetime from decimal import Decimal +from unittest.mock import patch from benedict.dicts.parse import ParseDict +from benedict.exceptions import ExtrasRequireModuleNotFoundError class parse_dict_test_case(unittest.TestCase): @@ -185,6 +187,16 @@ class parse_dict_test_case(unittest.TestCase): r = datetime(2019, 5, 1, 0, 0) self.assertEqual(b.get_datetime("a"), r) + @patch("benedict.dicts.parse.parse_util.parse_installed", False) + def test_get_datetime_with_with_extra_not_installed(self): + with self.assertRaises(ExtrasRequireModuleNotFoundError): + d = { + "a": "2019-05-01", + } + b = ParseDict(d) + r = datetime(2019, 5, 1, 0, 0) + self.assertEqual(b.get_datetime("a", format="%Y-%m-%d"), r) + def test_get_datetime_list(self): d = { "a": ["2019-05-01", "2018-12-31", "Hello World"], @@ -335,6 +347,15 @@ class parse_dict_test_case(unittest.TestCase): # invalid key self.assertEqual(b.get_email("e"), "") + @patch("benedict.dicts.parse.parse_util.parse_installed", False) + def test_get_email_with_extra_not_installed(self): + with self.assertRaises(ExtrasRequireModuleNotFoundError): + d = { + "a": "fabio@caccamo.com", + } + b = ParseDict(d) + b.get_email("a") + def test_get_int(self): d = { "a": 1, @@ -504,6 +525,15 @@ class parse_dict_test_case(unittest.TestCase): p = b.get_phonenumber("z") self.assertEqual(p, {}) + @patch("benedict.dicts.parse.parse_util.parse_installed", False) + def test_get_phonenumber_with_extra_not_installed(self): + with self.assertRaises(ExtrasRequireModuleNotFoundError): + d = { + "a": "3334445566", + } + b = ParseDict(d) + b.get_phonenumber("a") + def test_get_slug(self): d = { "a": " Hello World ", @@ -550,6 +580,15 @@ class parse_dict_test_case(unittest.TestCase): self.assertEqual(b.get_str("b"), "Hello World") self.assertEqual(b.get_str("c"), "1") + @patch("benedict.dicts.parse.parse_util.parse_installed", False) + def test_get_str_with_extra_not_installed(self): + with self.assertRaises(ExtrasRequireModuleNotFoundError): + d = { + "a": "Hello World", + } + b = ParseDict(d) + b.get_str("a") + def test_get_str_fix_encoding(self): d = { "a": "Sexâ\x80\x99n Drug", diff --git a/tests/dicts/parse/test_parse_util.py b/tests/dicts/parse/test_parse_util.py index ec3a644..49eac9d 100644 --- a/tests/dicts/parse/test_parse_util.py +++ b/tests/dicts/parse/test_parse_util.py @@ -34,6 +34,10 @@ class parse_util_test_case(unittest.TestCase): # TODO pass + def test_parse_datetime_with_extra_not_installed(self): + # TODO + pass + def test_parse_decimal(self): # TODO pass @@ -50,6 +54,10 @@ class parse_util_test_case(unittest.TestCase): # TODO pass + def test_parse_email_with_extra_not_installed(self): + # TODO + pass + def test_parse_int(self): # TODO pass @@ -90,6 +98,10 @@ class parse_util_test_case(unittest.TestCase): # TODO pass + def test_parse_phonenumber_with_extra_not_installed(self): + # TODO + pass + def test_parse_slug(self): # TODO pass @@ -98,6 +110,10 @@ class parse_util_test_case(unittest.TestCase): # TODO pass + def test_parse_str_with_extra_not_installed(self): + # TODO + pass + def test_parse_uuid(self): # TODO pass From d5caecb67ac3c05605eec7b757c90fd0e9596578 Mon Sep 17 00:00:00 2001 From: Fabio Caccamo Date: Sat, 17 Jun 2023 22:37:15 +0200 Subject: [PATCH 5/5] Update `CHANGELOG` and version. --- CHANGELOG.md | 4 ++++ benedict/metadata.py | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3211d1f..74b18e5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,10 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [0.31.0](https://github.com/fabiocaccamo/python-benedict/releases/tag/0.31.0) - 2023-06-17 +- Add `parse` extra ([optional dependencies](https://github.com/fabiocaccamo/python-benedict#optional-requirements)). #300 (#303) +- Bump requirements. + ## [0.30.2](https://github.com/fabiocaccamo/python-benedict/releases/tag/0.30.2) - 2023-06-02 - Allow `ini` format to support nested structures (encode to json only dicts). #284 - Prevent clearing dict instance when assigning value to itself. #294 diff --git a/benedict/metadata.py b/benedict/metadata.py index 80fe89f..6e2c5d3 100644 --- a/benedict/metadata.py +++ b/benedict/metadata.py @@ -8,4 +8,4 @@ __description__ = ( __email__ = "fabio.caccamo@gmail.com" __license__ = "MIT" __title__ = "benedict" -__version__ = "0.30.2" +__version__ = "0.31.0"