pkg-about 2.0.4__tar.gz → 2.0.7__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 (28) hide show
  1. {pkg_about-2.0.4 → pkg_about-2.0.7}/CHANGES.rst +4 -1
  2. {pkg_about-2.0.4 → pkg_about-2.0.7}/PKG-INFO +7 -4
  3. {pkg_about-2.0.4 → pkg_about-2.0.7}/pyproject.toml +4 -4
  4. {pkg_about-2.0.4 → pkg_about-2.0.7}/src/pkg_about/_about.py +34 -11
  5. {pkg_about-2.0.4 → pkg_about-2.0.7}/src/pkg_about.egg-info/PKG-INFO +7 -4
  6. {pkg_about-2.0.4 → pkg_about-2.0.7}/src/pkg_about.egg-info/requires.txt +2 -2
  7. {pkg_about-2.0.4 → pkg_about-2.0.7}/tests/test_main.py +75 -0
  8. {pkg_about-2.0.4 → pkg_about-2.0.7}/.readthedocs.yml +0 -0
  9. {pkg_about-2.0.4 → pkg_about-2.0.7}/LICENSE +0 -0
  10. {pkg_about-2.0.4 → pkg_about-2.0.7}/MANIFEST.in +0 -0
  11. {pkg_about-2.0.4 → pkg_about-2.0.7}/README.rst +0 -0
  12. {pkg_about-2.0.4 → pkg_about-2.0.7}/docs/CHANGES.rst +0 -0
  13. {pkg_about-2.0.4 → pkg_about-2.0.7}/docs/README.rst +0 -0
  14. {pkg_about-2.0.4 → pkg_about-2.0.7}/docs/_static/.keep +0 -0
  15. {pkg_about-2.0.4 → pkg_about-2.0.7}/docs/_templates/.keep +0 -0
  16. {pkg_about-2.0.4 → pkg_about-2.0.7}/docs/conf.py +0 -0
  17. {pkg_about-2.0.4 → pkg_about-2.0.7}/docs/index.rst +0 -0
  18. {pkg_about-2.0.4 → pkg_about-2.0.7}/setup.cfg +0 -0
  19. {pkg_about-2.0.4 → pkg_about-2.0.7}/src/pkg_about/__about__.py +0 -0
  20. {pkg_about-2.0.4 → pkg_about-2.0.7}/src/pkg_about/__init__.py +0 -0
  21. {pkg_about-2.0.4 → pkg_about-2.0.7}/src/pkg_about/py.typed +0 -0
  22. {pkg_about-2.0.4 → pkg_about-2.0.7}/src/pkg_about.egg-info/SOURCES.txt +0 -0
  23. {pkg_about-2.0.4 → pkg_about-2.0.7}/src/pkg_about.egg-info/dependency_links.txt +0 -0
  24. {pkg_about-2.0.4 → pkg_about-2.0.7}/src/pkg_about.egg-info/top_level.txt +0 -0
  25. {pkg_about-2.0.4 → pkg_about-2.0.7}/src/pkg_about.egg-info/zip-safe +0 -0
  26. {pkg_about-2.0.4 → pkg_about-2.0.7}/tests/__init__.py +0 -0
  27. {pkg_about-2.0.4 → pkg_about-2.0.7}/tests/__main__.py +0 -0
  28. {pkg_about-2.0.4 → pkg_about-2.0.7}/tests/data/setup.cfg +0 -0
@@ -1,7 +1,7 @@
1
1
  Changelog
2
2
  =========
3
3
 
4
- 2.0.4 (2025-11-08)
4
+ 2.0.7 (2025-11-27)
5
5
  ------------------
6
6
  - | Now about() and about_from_setup() return an instance of the adict
7
7
  | dictionary with about info (but backward compatibility is preserved).
@@ -10,6 +10,9 @@ Changelog
10
10
  - | Workaround for the tox error when pyproject.toml and setup.cfg
11
11
  | files coexist.
12
12
  - Better parsing of newer metadata versions.
13
+ - | Fixed a bug concerning the 'strict' parameter for the methods
14
+ | email.utils.getaddresses() and email.utils.parseaddr().
15
+ | Thank you! https://github.com/hedesandxlii
13
16
  - Mark the package as typed.
14
17
  - Add tox's tool.tox.env.cleanup testenv.
15
18
  - Setup (dependencies) update.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pkg_about
3
- Version: 2.0.4
3
+ Version: 2.0.7
4
4
  Summary: Shares Python package metadata at runtime.
5
5
  Author-email: Adam Karpierz <adam@karpierz.net>
6
6
  Maintainer-email: Adam Karpierz <adam@karpierz.net>
@@ -41,8 +41,8 @@ Requires-Dist: sphinx-toolbox>=4.0.0; extra == "doc"
41
41
  Requires-Dist: sphinx-tabs>=3.4.5; extra == "doc"
42
42
  Requires-Dist: sphinx-copybutton>=0.5.2; extra == "doc"
43
43
  Requires-Dist: sphinxcontrib-spelling>=8.0.1; extra == "doc"
44
- Requires-Dist: sphinx-lint>=1.0.1; extra == "doc"
45
- Requires-Dist: restructuredtext-lint>=1.4.0; extra == "doc"
44
+ Requires-Dist: sphinx-lint>=1.0.2; extra == "doc"
45
+ Requires-Dist: restructuredtext-lint>=2.0.2; extra == "doc"
46
46
  Requires-Dist: nbsphinx>=0.9.7; extra == "doc"
47
47
  Provides-Extra: test
48
48
  Requires-Dist: deepdiff>=8.6.1; extra == "test"
@@ -144,7 +144,7 @@ Authors
144
144
  Changelog
145
145
  =========
146
146
 
147
- 2.0.4 (2025-11-08)
147
+ 2.0.7 (2025-11-27)
148
148
  ------------------
149
149
  - | Now about() and about_from_setup() return an instance of the adict
150
150
  | dictionary with about info (but backward compatibility is preserved).
@@ -153,6 +153,9 @@ Changelog
153
153
  - | Workaround for the tox error when pyproject.toml and setup.cfg
154
154
  | files coexist.
155
155
  - Better parsing of newer metadata versions.
156
+ - | Fixed a bug concerning the 'strict' parameter for the methods
157
+ | email.utils.getaddresses() and email.utils.parseaddr().
158
+ | Thank you! https://github.com/hedesandxlii
156
159
  - Mark the package as typed.
157
160
  - Add tox's tool.tox.env.cleanup testenv.
158
161
  - Setup (dependencies) update.
@@ -7,7 +7,7 @@ requires = ['setuptools>=80.9.0', 'packaging>=25.0.0', 'tox>=4.32.0']
7
7
 
8
8
  [project]
9
9
  name = 'pkg_about'
10
- version = '2.0.4'
10
+ version = '2.0.7'
11
11
  description = 'Shares Python package metadata at runtime.'
12
12
  authors = [
13
13
  { name = 'Adam Karpierz', email = 'adam@karpierz.net' },
@@ -57,8 +57,8 @@ optional-dependencies.'doc' = [
57
57
  'sphinx-tabs>=3.4.5', # don't touch! sphinx-toolbox requires <3.4.7
58
58
  'sphinx-copybutton>=0.5.2',
59
59
  'sphinxcontrib-spelling>=8.0.1',
60
- 'sphinx-lint>=1.0.1',
61
- 'restructuredtext-lint>=1.4.0',
60
+ 'sphinx-lint>=1.0.2',
61
+ 'restructuredtext-lint>=2.0.2',
62
62
  'nbsphinx>=0.9.7',
63
63
  ]
64
64
  optional-dependencies.'test' = [
@@ -252,7 +252,7 @@ commands = [
252
252
  ]
253
253
  deps = [
254
254
  {replace='ref',of=['tool','tox','env_run_base','deps'],extend=true},
255
- 'coverage>=7.11.1',
255
+ 'coverage>=7.12.0',
256
256
  'covdefaults>=2.3.0',
257
257
  'diff-cover>=9.7.1',
258
258
  ]
@@ -10,37 +10,56 @@ from collections import namedtuple
10
10
  from functools import partial
11
11
  from email.utils import getaddresses, parseaddr
12
12
 
13
- if sys.version_info >= (3, 12):
13
+ if sys.version_info >= (3, 12, 6):
14
14
  getaddresses = partial(getaddresses, strict=False)
15
15
  parseaddr = partial(parseaddr, strict=False)
16
16
  else: pass # pragma: no cover
17
17
 
18
18
  version_info = namedtuple("version_info",
19
19
  ["major", "minor", "micro", "releaselevel", "serial"],
20
- module="pkg_about")
20
+ module=__package__)
21
21
 
22
22
 
23
- class __adict(dict[str, Any]):
24
- __getattr__ = dict.__getitem__
25
- __setattr__ = dict.__setitem__
26
- __delattr__ = dict.__delitem__
23
+ class adict(dict[str, Any]):
24
+
25
+ __module__ = __package__
26
+
27
+ def __getattr__(self, name: str) -> Any:
28
+ try:
29
+ return self.__getitem__(name)
30
+ except KeyError as exc:
31
+ raise AttributeError(*exc.args) from None
32
+
33
+ def __setattr__(self, name: str, value: Any) -> None:
34
+ try:
35
+ self.__setitem__(name, value)
36
+ except KeyError as exc: # pragma: no cover
37
+ raise AttributeError(*exc.args) from None
38
+
39
+ def __delattr__(self, name: str) -> None:
40
+ try:
41
+ self.__delitem__(name)
42
+ except KeyError as exc:
43
+ raise AttributeError(*exc.args) from None
44
+
27
45
  copy = __copy__ = lambda self: self.__class__(self)
28
46
 
29
47
 
30
- def about(package: str | None = None) -> __adict:
48
+ def about(package: str | None = None) -> adict:
31
49
  import sys
32
50
  from packaging.version import parse as parse_version
33
51
  from importlib.metadata import metadata as get_metadata
52
+ from importlib.metadata import version as get_version
34
53
  pkg_globals = sys._getframe(1).f_globals
35
54
  pkg_globals.pop("__builtins__", None)
36
55
  pkg_globals.pop("__cached__", None)
37
56
  if package is None: package = pkg_globals["__package__"]
38
57
  metadata = get_metadata(package)
39
- version = parse_version(metadata["Version"])
58
+ version = parse_version(get_version(package))
40
59
  project_urls = {item.partition(",")[0].strip():
41
60
  item.partition(",")[2].lstrip()
42
61
  for item in metadata.get_all("Project-URL") or []}
43
- adict, release_levels = __adict, __release_levels
62
+ release_levels = __release_levels
44
63
  metadata_get = metadata.get # type: ignore[attr-defined]
45
64
 
46
65
  pkg_metadata = adict(
@@ -65,11 +84,13 @@ def about(package: str | None = None) -> __adict:
65
84
  or project_urls.get("Homepage")
66
85
  or project_urls.get("Home")),
67
86
  __author__ = metadata_get("Author"),
87
+ __email__ = None,
68
88
  __author_email__ = metadata_get("Author-email"),
69
89
  __maintainer__ = metadata_get("Maintainer"),
70
90
  __maintainer_email__ = metadata_get("Maintainer-email"),
71
91
  __license__ = (metadata_get("License-Expression")
72
92
  or metadata_get("License")),
93
+ __copyright__ = None,
73
94
  )
74
95
  email = pkg_metadata["__author_email__"] or ""
75
96
  names = ", ".join(name for name, _ in getaddresses([email]) if name)
@@ -94,7 +115,7 @@ def about(package: str | None = None) -> __adict:
94
115
  return pkg_metadata
95
116
 
96
117
 
97
- def about_from_setup(package_path: Path | str | None = None) -> __adict:
118
+ def about_from_setup(package_path: Path | str | None = None) -> adict:
98
119
  import sys
99
120
  from pathlib import Path
100
121
  from packaging.version import parse as parse_version
@@ -129,7 +150,7 @@ def about_from_setup(package_path: Path | str | None = None) -> __adict:
129
150
  with pyproject_path.open("rb") as file:
130
151
  metadata.update(tomllib.load(file).get("project", {}))
131
152
  version = parse_version(metadata["version"])
132
- adict, get, release_levels = __adict, __get, __release_levels
153
+ get, release_levels = __get, __release_levels
133
154
 
134
155
  authors = get(metadata, "authors") or []
135
156
  maintainers = get(metadata, "maintainers") or []
@@ -158,6 +179,7 @@ def about_from_setup(package_path: Path | str | None = None) -> __adict:
158
179
  __author__ = (", ".join(item["name"] for item in authors
159
180
  if item and "name" in item)
160
181
  or get(metadata, "author")),
182
+ __email__ = None,
161
183
  __author_email__ = (", ".join((f"{item['name']} <{item['email']}>"
162
184
  if "name" in item and not parseaddr(
163
185
  item["email"])[0]
@@ -177,6 +199,7 @@ def about_from_setup(package_path: Path | str | None = None) -> __adict:
177
199
  or get(metadata, "maintainer_email")),
178
200
  __license__ = (get(metadata, "license", "text")
179
201
  or get(metadata, "license")),
202
+ __copyright__ = None,
180
203
  )
181
204
  pkg_metadata["__email__"] = pkg_metadata["__author_email__"]
182
205
  pkg_metadata["__copyright__"] = pkg_metadata["__author__"]
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pkg_about
3
- Version: 2.0.4
3
+ Version: 2.0.7
4
4
  Summary: Shares Python package metadata at runtime.
5
5
  Author-email: Adam Karpierz <adam@karpierz.net>
6
6
  Maintainer-email: Adam Karpierz <adam@karpierz.net>
@@ -41,8 +41,8 @@ Requires-Dist: sphinx-toolbox>=4.0.0; extra == "doc"
41
41
  Requires-Dist: sphinx-tabs>=3.4.5; extra == "doc"
42
42
  Requires-Dist: sphinx-copybutton>=0.5.2; extra == "doc"
43
43
  Requires-Dist: sphinxcontrib-spelling>=8.0.1; extra == "doc"
44
- Requires-Dist: sphinx-lint>=1.0.1; extra == "doc"
45
- Requires-Dist: restructuredtext-lint>=1.4.0; extra == "doc"
44
+ Requires-Dist: sphinx-lint>=1.0.2; extra == "doc"
45
+ Requires-Dist: restructuredtext-lint>=2.0.2; extra == "doc"
46
46
  Requires-Dist: nbsphinx>=0.9.7; extra == "doc"
47
47
  Provides-Extra: test
48
48
  Requires-Dist: deepdiff>=8.6.1; extra == "test"
@@ -144,7 +144,7 @@ Authors
144
144
  Changelog
145
145
  =========
146
146
 
147
- 2.0.4 (2025-11-08)
147
+ 2.0.7 (2025-11-27)
148
148
  ------------------
149
149
  - | Now about() and about_from_setup() return an instance of the adict
150
150
  | dictionary with about info (but backward compatibility is preserved).
@@ -153,6 +153,9 @@ Changelog
153
153
  - | Workaround for the tox error when pyproject.toml and setup.cfg
154
154
  | files coexist.
155
155
  - Better parsing of newer metadata versions.
156
+ - | Fixed a bug concerning the 'strict' parameter for the methods
157
+ | email.utils.getaddresses() and email.utils.parseaddr().
158
+ | Thank you! https://github.com/hedesandxlii
156
159
  - Mark the package as typed.
157
160
  - Add tox's tool.tox.env.cleanup testenv.
158
161
  - Setup (dependencies) update.
@@ -11,8 +11,8 @@ sphinx-toolbox>=4.0.0
11
11
  sphinx-tabs>=3.4.5
12
12
  sphinx-copybutton>=0.5.2
13
13
  sphinxcontrib-spelling>=8.0.1
14
- sphinx-lint>=1.0.1
15
- restructuredtext-lint>=1.4.0
14
+ sphinx-lint>=1.0.2
15
+ restructuredtext-lint>=2.0.2
16
16
  nbsphinx>=0.9.7
17
17
 
18
18
  [test]
@@ -4,6 +4,7 @@
4
4
  import unittest
5
5
  import sys
6
6
  import os
7
+ import copy
7
8
  import stat
8
9
  import shutil
9
10
  from pathlib import Path
@@ -11,6 +12,7 @@ from pathlib import Path
11
12
  from . import test_dir
12
13
 
13
14
  import pkg_about
15
+ from pkg_about._about import adict
14
16
 
15
17
 
16
18
  class MainTestCase(unittest.TestCase):
@@ -131,3 +133,76 @@ class MainTestCase(unittest.TestCase):
131
133
  self.assertEqual(about.__license__, "MIT")
132
134
  self.assertIs(__copyright__, about.__copyright__)
133
135
  self.assertEqual(about.__copyright__, __author__)
136
+
137
+
138
+ class TestAdict(unittest.TestCase):
139
+
140
+ def test_item_assignment(self):
141
+ d = adict()
142
+ self.assertNotIn("x", d)
143
+ d["x"] = 10
144
+ self.assertEqual(d.x, 10)
145
+ self.assertEqual(d["x"], 10)
146
+
147
+ def test_attribute_assignment(self):
148
+ d = adict()
149
+ self.assertNotIn("x", d)
150
+ d.x = 20
151
+ self.assertEqual(d["x"], 20)
152
+ self.assertEqual(d.x, 20)
153
+
154
+ def test_missing_item_raises(self):
155
+ d = adict()
156
+ with self.assertRaises(KeyError):
157
+ _ = d["missing"]
158
+
159
+ def test_missing_attribute_raises(self):
160
+ d = adict()
161
+ with self.assertRaises(AttributeError):
162
+ _ = d.missing
163
+
164
+ def test_item_deletion(self):
165
+ d = adict(x=5)
166
+ self.assertIn("x", d)
167
+ del d["x"]
168
+ self.assertNotIn("x", d)
169
+
170
+ def test_attribute_deletion(self):
171
+ d = adict(x=5)
172
+ self.assertIn("x", d)
173
+ del d.x
174
+ self.assertNotIn("x", d)
175
+
176
+ def test_missing_item_deletion_raises(self):
177
+ d = adict()
178
+ with self.assertRaises(KeyError):
179
+ del d["missing"]
180
+
181
+ def test_missing_attribute_deletion_raises(self):
182
+ d = adict()
183
+ with self.assertRaises(AttributeError):
184
+ del d.missing
185
+
186
+ def test_self_copy_returns_new_instance(self):
187
+ d1 = adict(a=1, b=2)
188
+ d2 = d1.copy()
189
+ self.assertIsInstance(d1, adict)
190
+ self.assertIsInstance(d2, adict)
191
+ self.assertEqual(d2, d1)
192
+ self.assertIsNot(d1, d2)
193
+
194
+ def test_copy_returns_new_instance(self):
195
+ d1 = adict(a=1, b=2)
196
+ d2 = copy.copy(d1)
197
+ self.assertIsInstance(d1, adict)
198
+ self.assertIsInstance(d2, adict)
199
+ self.assertEqual(d2, d1)
200
+ self.assertIsNot(d1, d2)
201
+
202
+ def test_fromkeys_creates_instance(self):
203
+ d = adict.fromkeys(["a", "b"], 0)
204
+ self.assertIsInstance(d, adict)
205
+ self.assertEqual(d["a"], 0)
206
+ self.assertEqual(d.a, 0)
207
+ self.assertEqual(d["b"], 0)
208
+ self.assertEqual(d.b, 0)
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes