python-utils 4.1.0__tar.gz → 4.1.1__tar.gz

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.
Files changed (42) hide show
  1. {python_utils-4.1.0 → python_utils-4.1.1}/PKG-INFO +1 -1
  2. {python_utils-4.1.0 → python_utils-4.1.1}/_python_utils_tests/test_formatters.py +38 -0
  3. {python_utils-4.1.0 → python_utils-4.1.1}/pyproject.toml +1 -1
  4. {python_utils-4.1.0 → python_utils-4.1.1}/pyproject.toml.orig +1 -1
  5. {python_utils-4.1.0 → python_utils-4.1.1}/python_utils/formatters.py +12 -7
  6. {python_utils-4.1.0 → python_utils-4.1.1}/LICENSE +0 -0
  7. {python_utils-4.1.0 → python_utils-4.1.1}/README.md +0 -0
  8. {python_utils-4.1.0 → python_utils-4.1.1}/_python_utils_tests/__init__.py +0 -0
  9. {python_utils-4.1.0 → python_utils-4.1.1}/_python_utils_tests/clock.py +0 -0
  10. {python_utils-4.1.0 → python_utils-4.1.1}/_python_utils_tests/requirements.txt +0 -0
  11. {python_utils-4.1.0 → python_utils-4.1.1}/_python_utils_tests/test_aio.py +0 -0
  12. {python_utils-4.1.0 → python_utils-4.1.1}/_python_utils_tests/test_aliases.py +0 -0
  13. {python_utils-4.1.0 → python_utils-4.1.1}/_python_utils_tests/test_containers.py +0 -0
  14. {python_utils-4.1.0 → python_utils-4.1.1}/_python_utils_tests/test_converters.py +0 -0
  15. {python_utils-4.1.0 → python_utils-4.1.1}/_python_utils_tests/test_decorators.py +0 -0
  16. {python_utils-4.1.0 → python_utils-4.1.1}/_python_utils_tests/test_generators.py +0 -0
  17. {python_utils-4.1.0 → python_utils-4.1.1}/_python_utils_tests/test_import.py +0 -0
  18. {python_utils-4.1.0 → python_utils-4.1.1}/_python_utils_tests/test_import_footprint.py +0 -0
  19. {python_utils-4.1.0 → python_utils-4.1.1}/_python_utils_tests/test_lazy_imports.py +0 -0
  20. {python_utils-4.1.0 → python_utils-4.1.1}/_python_utils_tests/test_logged.py +0 -0
  21. {python_utils-4.1.0 → python_utils-4.1.1}/_python_utils_tests/test_logger.py +0 -0
  22. {python_utils-4.1.0 → python_utils-4.1.1}/_python_utils_tests/test_python_utils.py +0 -0
  23. {python_utils-4.1.0 → python_utils-4.1.1}/_python_utils_tests/test_time.py +0 -0
  24. {python_utils-4.1.0 → python_utils-4.1.1}/_python_utils_tests/test_types.py +0 -0
  25. {python_utils-4.1.0 → python_utils-4.1.1}/conftest.py +0 -0
  26. {python_utils-4.1.0 → python_utils-4.1.1}/python_utils/__about__.py +0 -0
  27. {python_utils-4.1.0 → python_utils-4.1.1}/python_utils/__init__.py +0 -0
  28. {python_utils-4.1.0 → python_utils-4.1.1}/python_utils/_aliases.py +0 -0
  29. {python_utils-4.1.0 → python_utils-4.1.1}/python_utils/aio.py +0 -0
  30. {python_utils-4.1.0 → python_utils-4.1.1}/python_utils/containers.py +0 -0
  31. {python_utils-4.1.0 → python_utils-4.1.1}/python_utils/converters.py +0 -0
  32. {python_utils-4.1.0 → python_utils-4.1.1}/python_utils/decorators.py +0 -0
  33. {python_utils-4.1.0 → python_utils-4.1.1}/python_utils/exceptions.py +0 -0
  34. {python_utils-4.1.0 → python_utils-4.1.1}/python_utils/generators.py +0 -0
  35. {python_utils-4.1.0 → python_utils-4.1.1}/python_utils/import_.py +0 -0
  36. {python_utils-4.1.0 → python_utils-4.1.1}/python_utils/logger.py +0 -0
  37. {python_utils-4.1.0 → python_utils-4.1.1}/python_utils/loguru.py +0 -0
  38. {python_utils-4.1.0 → python_utils-4.1.1}/python_utils/py.typed +0 -0
  39. {python_utils-4.1.0 → python_utils-4.1.1}/python_utils/terminal.py +0 -0
  40. {python_utils-4.1.0 → python_utils-4.1.1}/python_utils/time.py +0 -0
  41. {python_utils-4.1.0 → python_utils-4.1.1}/python_utils/types.py +0 -0
  42. {python_utils-4.1.0 → python_utils-4.1.1}/tox.ini +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: python-utils
3
- Version: 4.1.0
3
+ Version: 4.1.1
4
4
  Summary: Python Utils is a module with some convenient utilities not included with the standard Python install
5
5
  Keywords: utils,utilities,helpers,typing,typed,async,lazy-imports
6
6
  Author: Rick van Hattem
@@ -73,6 +73,44 @@ def test_camel_to_underscore_keeps_acronyms_whole(
73
73
  assert formatters.camel_to_underscore(name) == expected
74
74
 
75
75
 
76
+ @pytest.mark.parametrize(
77
+ ('name', 'expected'),
78
+ [
79
+ ('ABc', 'a_bc'),
80
+ ('ABCd', 'ab_cd'),
81
+ ('IPad', 'i_pad'),
82
+ ('AName', 'a_name'),
83
+ ('__ABc__', '__a_bc__'),
84
+ ('XMLParser', 'xml_parser'),
85
+ ],
86
+ )
87
+ def test_camel_to_underscore_splits_short_acronym_boundary(
88
+ name: str, expected: str
89
+ ) -> None:
90
+ """Keep the final capital with the word following even a short acronym."""
91
+ assert formatters.camel_to_underscore(name) == expected
92
+
93
+
94
+ @pytest.mark.parametrize(
95
+ ('name', 'expected'),
96
+ [
97
+ ('IDs', 'ids'),
98
+ ('URLs', 'urls'),
99
+ ('UserIDs', 'user_ids'),
100
+ ('GetURLs', 'get_urls'),
101
+ ('IDsAndNames', 'ids_and_names'),
102
+ ('PDFs_v2', 'pdfs_v2'),
103
+ ('ISpam', 'i_spam'),
104
+ ('IPsec', 'i_psec'),
105
+ ],
106
+ )
107
+ def test_camel_to_underscore_keeps_plural_acronyms_whole(
108
+ name: str, expected: str
109
+ ) -> None:
110
+ """Keep a plural ``s`` that ends a word with the acronym before it."""
111
+ assert formatters.camel_to_underscore(name) == expected
112
+
113
+
76
114
  def test_timesince_date_raises_type_error() -> None:
77
115
  """Keep raising ``TypeError`` for a date, which has no time."""
78
116
  today: typing.Any = datetime.date.today()
@@ -125,7 +125,7 @@ source-include = [
125
125
 
126
126
  [project]
127
127
  name = "python-utils"
128
- version = "4.1.0"
128
+ version = "4.1.1"
129
129
  description = "Python Utils is a module with some convenient utilities not included with the standard Python install"
130
130
  readme = "README.md"
131
131
  requires-python = ">=3.10"
@@ -12,7 +12,7 @@ source-include = ['_python_utils_tests/**/*.py', 'conftest.py', 'tox.ini']
12
12
 
13
13
  [project]
14
14
  name = 'python-utils'
15
- version = "4.1.0" # static; the single source of truth. Bump via `uv version`.
15
+ version = "4.1.1" # static; the single source of truth. Bump via `uv version`.
16
16
  description = 'Python Utils is a module with some convenient utilities not included with the standard Python install'
17
17
  readme = 'README.md'
18
18
  requires-python = '>=3.10'
@@ -21,7 +21,8 @@ def camel_to_underscore(name: str) -> str:
21
21
 
22
22
  If there are existing underscores they will be collapsed with the
23
23
  to-be-added underscores. Multiple consecutive capital letters will not be
24
- split except for the last one.
24
+ split except for the last one. A plural ``s`` that ends a word stays with
25
+ the acronym before it.
25
26
 
26
27
  >>> camel_to_underscore('SpamEggsAndBacon')
27
28
  'spam_eggs_and_bacon'
@@ -42,12 +43,16 @@ def camel_to_underscore(name: str) -> str:
42
43
  # Uppercase and the previous character isn't upper/underscore?
43
44
  # Add the underscore
44
45
  output.append('_')
45
- elif i > 3 and c.islower():
46
- # Will return the last 3 letters to check if we are changing
47
- # case. Only a lowercase letter ends an acronym, an underscore
48
- # or a digit after it leaves the acronym whole.
49
- previous = name[i - 3 : i]
50
- if previous.isalpha() and previous.isupper():
46
+ elif i > 1 and c.islower():
47
+ # Two preceding capitals are enough to mark the boundary:
48
+ # the final capital belongs to the following word. Only a
49
+ # lowercase letter ends an acronym; an underscore or digit
50
+ # after it leaves the acronym whole.
51
+ previous = name[i - 2 : i]
52
+ # A lone ``s`` that ends the word makes the acronym plural
53
+ # (``IDs``, ``URLs``) and does not start a new word.
54
+ plural: bool = c == 's' and not name[i + 1 : i + 2].islower()
55
+ if previous.isalpha() and previous.isupper() and not plural:
51
56
  output.insert(len(output) - 1, '_')
52
57
 
53
58
  output.append(c.lower())
File without changes
File without changes
File without changes
File without changes