knickknacks 0.5.0__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 (167) hide show
  1. knickknacks-0.5.0/LICENSE.txt +21 -0
  2. knickknacks-0.5.0/PKG-INFO +61 -0
  3. knickknacks-0.5.0/README.md +21 -0
  4. knickknacks-0.5.0/pyproject.toml +291 -0
  5. knickknacks-0.5.0/src/knickknacks/__init__.py +37 -0
  6. knickknacks-0.5.0/src/knickknacks/_version.py +1 -0
  7. knickknacks-0.5.0/src/knickknacks/backports.py +91 -0
  8. knickknacks-0.5.0/src/knickknacks/databytes.py +187 -0
  9. knickknacks-0.5.0/src/knickknacks/iterables.py +101 -0
  10. knickknacks-0.5.0/src/knickknacks/numbers.py +80 -0
  11. knickknacks-0.5.0/src/knickknacks/platforms.py +80 -0
  12. knickknacks-0.5.0/src/knickknacks/py.typed +0 -0
  13. knickknacks-0.5.0/src/knickknacks/strings.py +242 -0
  14. knickknacks-0.5.0/src/knickknacks/testing.py +56 -0
  15. knickknacks-0.5.0/src/knickknacks/typedef.py +73 -0
  16. knickknacks-0.5.0/src/knickknacks/utils.py +87 -0
  17. knickknacks-0.5.0/src/knickknacks/xml.py +115 -0
  18. knickknacks-0.5.0/tests/__init__.py +0 -0
  19. knickknacks-0.5.0/tests/knickknacks/.mypy_cache/.gitignore +2 -0
  20. knickknacks-0.5.0/tests/knickknacks/.mypy_cache/3.12/@plugins_snapshot.json +1 -0
  21. knickknacks-0.5.0/tests/knickknacks/.mypy_cache/3.12/__future__.data.json +1 -0
  22. knickknacks-0.5.0/tests/knickknacks/.mypy_cache/3.12/__future__.meta.json +1 -0
  23. knickknacks-0.5.0/tests/knickknacks/.mypy_cache/3.12/_ast.data.json +1 -0
  24. knickknacks-0.5.0/tests/knickknacks/.mypy_cache/3.12/_ast.meta.json +1 -0
  25. knickknacks-0.5.0/tests/knickknacks/.mypy_cache/3.12/_codecs.data.json +1 -0
  26. knickknacks-0.5.0/tests/knickknacks/.mypy_cache/3.12/_codecs.meta.json +1 -0
  27. knickknacks-0.5.0/tests/knickknacks/.mypy_cache/3.12/_collections_abc.data.json +1 -0
  28. knickknacks-0.5.0/tests/knickknacks/.mypy_cache/3.12/_collections_abc.meta.json +1 -0
  29. knickknacks-0.5.0/tests/knickknacks/.mypy_cache/3.12/_thread.data.json +1 -0
  30. knickknacks-0.5.0/tests/knickknacks/.mypy_cache/3.12/_thread.meta.json +1 -0
  31. knickknacks-0.5.0/tests/knickknacks/.mypy_cache/3.12/_typeshed/__init__.data.json +1 -0
  32. knickknacks-0.5.0/tests/knickknacks/.mypy_cache/3.12/_typeshed/__init__.meta.json +1 -0
  33. knickknacks-0.5.0/tests/knickknacks/.mypy_cache/3.12/_warnings.data.json +1 -0
  34. knickknacks-0.5.0/tests/knickknacks/.mypy_cache/3.12/_warnings.meta.json +1 -0
  35. knickknacks-0.5.0/tests/knickknacks/.mypy_cache/3.12/_winapi.data.json +1 -0
  36. knickknacks-0.5.0/tests/knickknacks/.mypy_cache/3.12/_winapi.meta.json +1 -0
  37. knickknacks-0.5.0/tests/knickknacks/.mypy_cache/3.12/abc.data.json +1 -0
  38. knickknacks-0.5.0/tests/knickknacks/.mypy_cache/3.12/abc.meta.json +1 -0
  39. knickknacks-0.5.0/tests/knickknacks/.mypy_cache/3.12/builtins.data.json +1 -0
  40. knickknacks-0.5.0/tests/knickknacks/.mypy_cache/3.12/builtins.meta.json +1 -0
  41. knickknacks-0.5.0/tests/knickknacks/.mypy_cache/3.12/codecs.data.json +1 -0
  42. knickknacks-0.5.0/tests/knickknacks/.mypy_cache/3.12/codecs.meta.json +1 -0
  43. knickknacks-0.5.0/tests/knickknacks/.mypy_cache/3.12/collections/__init__.data.json +1 -0
  44. knickknacks-0.5.0/tests/knickknacks/.mypy_cache/3.12/collections/__init__.meta.json +1 -0
  45. knickknacks-0.5.0/tests/knickknacks/.mypy_cache/3.12/collections/abc.data.json +1 -0
  46. knickknacks-0.5.0/tests/knickknacks/.mypy_cache/3.12/collections/abc.meta.json +1 -0
  47. knickknacks-0.5.0/tests/knickknacks/.mypy_cache/3.12/contextlib.data.json +1 -0
  48. knickknacks-0.5.0/tests/knickknacks/.mypy_cache/3.12/contextlib.meta.json +1 -0
  49. knickknacks-0.5.0/tests/knickknacks/.mypy_cache/3.12/dataclasses.data.json +1 -0
  50. knickknacks-0.5.0/tests/knickknacks/.mypy_cache/3.12/dataclasses.meta.json +1 -0
  51. knickknacks-0.5.0/tests/knickknacks/.mypy_cache/3.12/email/__init__.data.json +1 -0
  52. knickknacks-0.5.0/tests/knickknacks/.mypy_cache/3.12/email/__init__.meta.json +1 -0
  53. knickknacks-0.5.0/tests/knickknacks/.mypy_cache/3.12/email/charset.data.json +1 -0
  54. knickknacks-0.5.0/tests/knickknacks/.mypy_cache/3.12/email/charset.meta.json +1 -0
  55. knickknacks-0.5.0/tests/knickknacks/.mypy_cache/3.12/email/contentmanager.data.json +1 -0
  56. knickknacks-0.5.0/tests/knickknacks/.mypy_cache/3.12/email/contentmanager.meta.json +1 -0
  57. knickknacks-0.5.0/tests/knickknacks/.mypy_cache/3.12/email/errors.data.json +1 -0
  58. knickknacks-0.5.0/tests/knickknacks/.mypy_cache/3.12/email/errors.meta.json +1 -0
  59. knickknacks-0.5.0/tests/knickknacks/.mypy_cache/3.12/email/header.data.json +1 -0
  60. knickknacks-0.5.0/tests/knickknacks/.mypy_cache/3.12/email/header.meta.json +1 -0
  61. knickknacks-0.5.0/tests/knickknacks/.mypy_cache/3.12/email/message.data.json +1 -0
  62. knickknacks-0.5.0/tests/knickknacks/.mypy_cache/3.12/email/message.meta.json +1 -0
  63. knickknacks-0.5.0/tests/knickknacks/.mypy_cache/3.12/email/policy.data.json +1 -0
  64. knickknacks-0.5.0/tests/knickknacks/.mypy_cache/3.12/email/policy.meta.json +1 -0
  65. knickknacks-0.5.0/tests/knickknacks/.mypy_cache/3.12/enum.data.json +1 -0
  66. knickknacks-0.5.0/tests/knickknacks/.mypy_cache/3.12/enum.meta.json +1 -0
  67. knickknacks-0.5.0/tests/knickknacks/.mypy_cache/3.12/genericpath.data.json +1 -0
  68. knickknacks-0.5.0/tests/knickknacks/.mypy_cache/3.12/genericpath.meta.json +1 -0
  69. knickknacks-0.5.0/tests/knickknacks/.mypy_cache/3.12/importlib/__init__.data.json +1 -0
  70. knickknacks-0.5.0/tests/knickknacks/.mypy_cache/3.12/importlib/__init__.meta.json +1 -0
  71. knickknacks-0.5.0/tests/knickknacks/.mypy_cache/3.12/importlib/abc.data.json +1 -0
  72. knickknacks-0.5.0/tests/knickknacks/.mypy_cache/3.12/importlib/abc.meta.json +1 -0
  73. knickknacks-0.5.0/tests/knickknacks/.mypy_cache/3.12/importlib/machinery.data.json +1 -0
  74. knickknacks-0.5.0/tests/knickknacks/.mypy_cache/3.12/importlib/machinery.meta.json +1 -0
  75. knickknacks-0.5.0/tests/knickknacks/.mypy_cache/3.12/importlib/metadata/__init__.data.json +1 -0
  76. knickknacks-0.5.0/tests/knickknacks/.mypy_cache/3.12/importlib/metadata/__init__.meta.json +1 -0
  77. knickknacks-0.5.0/tests/knickknacks/.mypy_cache/3.12/importlib/metadata/_meta.data.json +1 -0
  78. knickknacks-0.5.0/tests/knickknacks/.mypy_cache/3.12/importlib/metadata/_meta.meta.json +1 -0
  79. knickknacks-0.5.0/tests/knickknacks/.mypy_cache/3.12/importlib/readers.data.json +1 -0
  80. knickknacks-0.5.0/tests/knickknacks/.mypy_cache/3.12/importlib/readers.meta.json +1 -0
  81. knickknacks-0.5.0/tests/knickknacks/.mypy_cache/3.12/importlib/resources/__init__.data.json +1 -0
  82. knickknacks-0.5.0/tests/knickknacks/.mypy_cache/3.12/importlib/resources/__init__.meta.json +1 -0
  83. knickknacks-0.5.0/tests/knickknacks/.mypy_cache/3.12/importlib/resources/abc.data.json +1 -0
  84. knickknacks-0.5.0/tests/knickknacks/.mypy_cache/3.12/importlib/resources/abc.meta.json +1 -0
  85. knickknacks-0.5.0/tests/knickknacks/.mypy_cache/3.12/io.data.json +1 -0
  86. knickknacks-0.5.0/tests/knickknacks/.mypy_cache/3.12/io.meta.json +1 -0
  87. knickknacks-0.5.0/tests/knickknacks/.mypy_cache/3.12/logging/__init__.data.json +1 -0
  88. knickknacks-0.5.0/tests/knickknacks/.mypy_cache/3.12/logging/__init__.meta.json +1 -0
  89. knickknacks-0.5.0/tests/knickknacks/.mypy_cache/3.12/ntpath.data.json +1 -0
  90. knickknacks-0.5.0/tests/knickknacks/.mypy_cache/3.12/ntpath.meta.json +1 -0
  91. knickknacks-0.5.0/tests/knickknacks/.mypy_cache/3.12/os/__init__.data.json +1 -0
  92. knickknacks-0.5.0/tests/knickknacks/.mypy_cache/3.12/os/__init__.meta.json +1 -0
  93. knickknacks-0.5.0/tests/knickknacks/.mypy_cache/3.12/os/path.data.json +1 -0
  94. knickknacks-0.5.0/tests/knickknacks/.mypy_cache/3.12/os/path.meta.json +1 -0
  95. knickknacks-0.5.0/tests/knickknacks/.mypy_cache/3.12/pathlib.data.json +1 -0
  96. knickknacks-0.5.0/tests/knickknacks/.mypy_cache/3.12/pathlib.meta.json +1 -0
  97. knickknacks-0.5.0/tests/knickknacks/.mypy_cache/3.12/posixpath.data.json +1 -0
  98. knickknacks-0.5.0/tests/knickknacks/.mypy_cache/3.12/posixpath.meta.json +1 -0
  99. knickknacks-0.5.0/tests/knickknacks/.mypy_cache/3.12/re.data.json +1 -0
  100. knickknacks-0.5.0/tests/knickknacks/.mypy_cache/3.12/re.meta.json +1 -0
  101. knickknacks-0.5.0/tests/knickknacks/.mypy_cache/3.12/sre_compile.data.json +1 -0
  102. knickknacks-0.5.0/tests/knickknacks/.mypy_cache/3.12/sre_compile.meta.json +1 -0
  103. knickknacks-0.5.0/tests/knickknacks/.mypy_cache/3.12/sre_constants.data.json +1 -0
  104. knickknacks-0.5.0/tests/knickknacks/.mypy_cache/3.12/sre_constants.meta.json +1 -0
  105. knickknacks-0.5.0/tests/knickknacks/.mypy_cache/3.12/sre_parse.data.json +1 -0
  106. knickknacks-0.5.0/tests/knickknacks/.mypy_cache/3.12/sre_parse.meta.json +1 -0
  107. knickknacks-0.5.0/tests/knickknacks/.mypy_cache/3.12/string.data.json +1 -0
  108. knickknacks-0.5.0/tests/knickknacks/.mypy_cache/3.12/string.meta.json +1 -0
  109. knickknacks-0.5.0/tests/knickknacks/.mypy_cache/3.12/subprocess.data.json +1 -0
  110. knickknacks-0.5.0/tests/knickknacks/.mypy_cache/3.12/subprocess.meta.json +1 -0
  111. knickknacks-0.5.0/tests/knickknacks/.mypy_cache/3.12/sys/__init__.data.json +1 -0
  112. knickknacks-0.5.0/tests/knickknacks/.mypy_cache/3.12/sys/__init__.meta.json +1 -0
  113. knickknacks-0.5.0/tests/knickknacks/.mypy_cache/3.12/sys/_monitoring.data.json +1 -0
  114. knickknacks-0.5.0/tests/knickknacks/.mypy_cache/3.12/sys/_monitoring.meta.json +1 -0
  115. knickknacks-0.5.0/tests/knickknacks/.mypy_cache/3.12/tests/__init__.data.json +1 -0
  116. knickknacks-0.5.0/tests/knickknacks/.mypy_cache/3.12/tests/__init__.meta.json +1 -0
  117. knickknacks-0.5.0/tests/knickknacks/.mypy_cache/3.12/tests/knickknacks/__init__.data.json +1 -0
  118. knickknacks-0.5.0/tests/knickknacks/.mypy_cache/3.12/tests/knickknacks/__init__.meta.json +1 -0
  119. knickknacks-0.5.0/tests/knickknacks/.mypy_cache/3.12/textwrap.data.json +1 -0
  120. knickknacks-0.5.0/tests/knickknacks/.mypy_cache/3.12/textwrap.meta.json +1 -0
  121. knickknacks-0.5.0/tests/knickknacks/.mypy_cache/3.12/threading.data.json +1 -0
  122. knickknacks-0.5.0/tests/knickknacks/.mypy_cache/3.12/threading.meta.json +1 -0
  123. knickknacks-0.5.0/tests/knickknacks/.mypy_cache/3.12/time.data.json +1 -0
  124. knickknacks-0.5.0/tests/knickknacks/.mypy_cache/3.12/time.meta.json +1 -0
  125. knickknacks-0.5.0/tests/knickknacks/.mypy_cache/3.12/types.data.json +1 -0
  126. knickknacks-0.5.0/tests/knickknacks/.mypy_cache/3.12/types.meta.json +1 -0
  127. knickknacks-0.5.0/tests/knickknacks/.mypy_cache/3.12/typing.data.json +1 -0
  128. knickknacks-0.5.0/tests/knickknacks/.mypy_cache/3.12/typing.meta.json +1 -0
  129. knickknacks-0.5.0/tests/knickknacks/.mypy_cache/3.12/typing_extensions.data.json +1 -0
  130. knickknacks-0.5.0/tests/knickknacks/.mypy_cache/3.12/typing_extensions.meta.json +1 -0
  131. knickknacks-0.5.0/tests/knickknacks/.mypy_cache/3.12/unittest/__init__.data.json +1 -0
  132. knickknacks-0.5.0/tests/knickknacks/.mypy_cache/3.12/unittest/__init__.meta.json +1 -0
  133. knickknacks-0.5.0/tests/knickknacks/.mypy_cache/3.12/unittest/_log.data.json +1 -0
  134. knickknacks-0.5.0/tests/knickknacks/.mypy_cache/3.12/unittest/_log.meta.json +1 -0
  135. knickknacks-0.5.0/tests/knickknacks/.mypy_cache/3.12/unittest/async_case.data.json +1 -0
  136. knickknacks-0.5.0/tests/knickknacks/.mypy_cache/3.12/unittest/async_case.meta.json +1 -0
  137. knickknacks-0.5.0/tests/knickknacks/.mypy_cache/3.12/unittest/case.data.json +1 -0
  138. knickknacks-0.5.0/tests/knickknacks/.mypy_cache/3.12/unittest/case.meta.json +1 -0
  139. knickknacks-0.5.0/tests/knickknacks/.mypy_cache/3.12/unittest/loader.data.json +1 -0
  140. knickknacks-0.5.0/tests/knickknacks/.mypy_cache/3.12/unittest/loader.meta.json +1 -0
  141. knickknacks-0.5.0/tests/knickknacks/.mypy_cache/3.12/unittest/main.data.json +1 -0
  142. knickknacks-0.5.0/tests/knickknacks/.mypy_cache/3.12/unittest/main.meta.json +1 -0
  143. knickknacks-0.5.0/tests/knickknacks/.mypy_cache/3.12/unittest/mock.data.json +1 -0
  144. knickknacks-0.5.0/tests/knickknacks/.mypy_cache/3.12/unittest/mock.meta.json +1 -0
  145. knickknacks-0.5.0/tests/knickknacks/.mypy_cache/3.12/unittest/result.data.json +1 -0
  146. knickknacks-0.5.0/tests/knickknacks/.mypy_cache/3.12/unittest/result.meta.json +1 -0
  147. knickknacks-0.5.0/tests/knickknacks/.mypy_cache/3.12/unittest/runner.data.json +1 -0
  148. knickknacks-0.5.0/tests/knickknacks/.mypy_cache/3.12/unittest/runner.meta.json +1 -0
  149. knickknacks-0.5.0/tests/knickknacks/.mypy_cache/3.12/unittest/signals.data.json +1 -0
  150. knickknacks-0.5.0/tests/knickknacks/.mypy_cache/3.12/unittest/signals.meta.json +1 -0
  151. knickknacks-0.5.0/tests/knickknacks/.mypy_cache/3.12/unittest/suite.data.json +1 -0
  152. knickknacks-0.5.0/tests/knickknacks/.mypy_cache/3.12/unittest/suite.meta.json +1 -0
  153. knickknacks-0.5.0/tests/knickknacks/.mypy_cache/3.12/warnings.data.json +1 -0
  154. knickknacks-0.5.0/tests/knickknacks/.mypy_cache/3.12/warnings.meta.json +1 -0
  155. knickknacks-0.5.0/tests/knickknacks/.mypy_cache/3.12/zipfile.data.json +1 -0
  156. knickknacks-0.5.0/tests/knickknacks/.mypy_cache/3.12/zipfile.meta.json +1 -0
  157. knickknacks-0.5.0/tests/knickknacks/.mypy_cache/CACHEDIR.TAG +3 -0
  158. knickknacks-0.5.0/tests/knickknacks/__init__.py +0 -0
  159. knickknacks-0.5.0/tests/knickknacks/test_databytes.py +49 -0
  160. knickknacks-0.5.0/tests/knickknacks/test_iterables.py +68 -0
  161. knickknacks-0.5.0/tests/knickknacks/test_numbers.py +46 -0
  162. knickknacks-0.5.0/tests/knickknacks/test_platforms.py +74 -0
  163. knickknacks-0.5.0/tests/knickknacks/test_strings.py +124 -0
  164. knickknacks-0.5.0/tests/knickknacks/test_testing.py +55 -0
  165. knickknacks-0.5.0/tests/knickknacks/test_utils.py +70 -0
  166. knickknacks-0.5.0/tests/knickknacks/test_xml.py +46 -0
  167. knickknacks-0.5.0/uv.lock +752 -0
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 Nick Stockton
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,61 @@
1
+ Metadata-Version: 2.1
2
+ Name: knickknacks
3
+ Version: 0.5.0
4
+ Summary: Small, reusable, miscellaneous pieces of code.
5
+ Keywords: utilities,misc,snippets,reusable
6
+ Author-Email: Nick Stockton <nstockton@users.noreply.github.com>
7
+ License: MIT
8
+ Classifier: Development Status :: 5 - Production/Stable
9
+ Classifier: Intended Audience :: Developers
10
+ Classifier: License :: OSI Approved :: MIT License
11
+ Classifier: Programming Language :: Python
12
+ Classifier: Programming Language :: Python :: 3
13
+ Classifier: Programming Language :: Python :: 3 :: Only
14
+ Classifier: Programming Language :: Python :: 3.9
15
+ Classifier: Programming Language :: Python :: 3.10
16
+ Classifier: Programming Language :: Python :: 3.11
17
+ Classifier: Programming Language :: Python :: 3.12
18
+ Classifier: Programming Language :: Python :: 3.13
19
+ Classifier: Programming Language :: Python :: Implementation
20
+ Classifier: Programming Language :: Python :: Implementation :: CPython
21
+ Classifier: Operating System :: MacOS
22
+ Classifier: Operating System :: MacOS :: MacOS X
23
+ Classifier: Operating System :: Microsoft
24
+ Classifier: Operating System :: Microsoft :: Windows
25
+ Classifier: Operating System :: OS Independent
26
+ Classifier: Operating System :: POSIX
27
+ Classifier: Operating System :: POSIX :: BSD
28
+ Classifier: Operating System :: POSIX :: Linux
29
+ Classifier: Operating System :: Unix
30
+ Classifier: Topic :: Software Development
31
+ Classifier: Topic :: Software Development :: Libraries
32
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
33
+ Project-URL: homepage, https://github.com/nstockton/knickknacks
34
+ Project-URL: repository, https://github.com/nstockton/knickknacks
35
+ Project-URL: documentation, https://nstockton.github.io/knickknacks
36
+ Requires-Python: <4.0,>=3.9
37
+ Requires-Dist: backports-strenum<2.0,>=1.3; python_version < "3.11"
38
+ Requires-Dist: typing-extensions<5.0,>=4.8; python_version < "3.12"
39
+ Description-Content-Type: text/markdown
40
+
41
+ # Knickknacks
42
+
43
+ Small, reusable, miscellaneous pieces of code.
44
+
45
+ ## License And Credits
46
+
47
+ Knickknacks is licensed under the terms of the [MIT License.](https://raw.githubusercontent.com/nstockton/knickknacks/master/LICENSE.txt "Knickknacks License")
48
+
49
+ ### Running From Source
50
+
51
+ Install the [Python interpreter,](https://python.org "Python Home Page") and make sure it's in your path before running this package.
52
+
53
+ After Python is installed, execute the following commands from the top level directory of this repository to install the module dependencies.
54
+ ```
55
+ python -m venv .venv
56
+ source .venv/bin/activate
57
+ pip install --upgrade --require-hashes --requirement requirements-uv.txt
58
+ uv sync
59
+ pre-commit install -t pre-commit
60
+ pre-commit install -t pre-push
61
+ ```
@@ -0,0 +1,21 @@
1
+ # Knickknacks
2
+
3
+ Small, reusable, miscellaneous pieces of code.
4
+
5
+ ## License And Credits
6
+
7
+ Knickknacks is licensed under the terms of the [MIT License.](https://raw.githubusercontent.com/nstockton/knickknacks/master/LICENSE.txt "Knickknacks License")
8
+
9
+ ### Running From Source
10
+
11
+ Install the [Python interpreter,](https://python.org "Python Home Page") and make sure it's in your path before running this package.
12
+
13
+ After Python is installed, execute the following commands from the top level directory of this repository to install the module dependencies.
14
+ ```
15
+ python -m venv .venv
16
+ source .venv/bin/activate
17
+ pip install --upgrade --require-hashes --requirement requirements-uv.txt
18
+ uv sync
19
+ pre-commit install -t pre-commit
20
+ pre-commit install -t pre-push
21
+ ```
@@ -0,0 +1,291 @@
1
+ [build-system]
2
+ requires = [
3
+ "pdm-backend",
4
+ ]
5
+ build-backend = "pdm.backend"
6
+
7
+ [project]
8
+ name = "knickknacks"
9
+ authors = [
10
+ { name = "Nick Stockton", email = "nstockton@users.noreply.github.com" },
11
+ ]
12
+ description = "Small, reusable, miscellaneous pieces of code."
13
+ readme = "README.md"
14
+ requires-python = ">=3.9,<4.0"
15
+ dependencies = [
16
+ "backports-strenum>=1.3,<2.0; python_version < \"3.11\"",
17
+ "typing-extensions>=4.8,<5.0; python_version < \"3.12\"",
18
+ ]
19
+ dynamic = []
20
+ keywords = [
21
+ "utilities",
22
+ "misc",
23
+ "snippets",
24
+ "reusable",
25
+ ]
26
+ classifiers = [
27
+ "Development Status :: 5 - Production/Stable",
28
+ "Intended Audience :: Developers",
29
+ "License :: OSI Approved :: MIT License",
30
+ "Programming Language :: Python",
31
+ "Programming Language :: Python :: 3",
32
+ "Programming Language :: Python :: 3 :: Only",
33
+ "Programming Language :: Python :: 3.9",
34
+ "Programming Language :: Python :: 3.10",
35
+ "Programming Language :: Python :: 3.11",
36
+ "Programming Language :: Python :: 3.12",
37
+ "Programming Language :: Python :: 3.13",
38
+ "Programming Language :: Python :: Implementation",
39
+ "Programming Language :: Python :: Implementation :: CPython",
40
+ "Operating System :: MacOS",
41
+ "Operating System :: MacOS :: MacOS X",
42
+ "Operating System :: Microsoft",
43
+ "Operating System :: Microsoft :: Windows",
44
+ "Operating System :: OS Independent",
45
+ "Operating System :: POSIX",
46
+ "Operating System :: POSIX :: BSD",
47
+ "Operating System :: POSIX :: Linux",
48
+ "Operating System :: Unix",
49
+ "Topic :: Software Development",
50
+ "Topic :: Software Development :: Libraries",
51
+ "Topic :: Software Development :: Libraries :: Python Modules",
52
+ ]
53
+ version = "0.5.0"
54
+
55
+ [project.license]
56
+ text = "MIT"
57
+
58
+ [project.urls]
59
+ homepage = "https://github.com/nstockton/knickknacks"
60
+ repository = "https://github.com/nstockton/knickknacks"
61
+ documentation = "https://nstockton.github.io/knickknacks"
62
+
63
+ [dependency-groups]
64
+ dev = [
65
+ "pre-commit>=3.5,<4.0",
66
+ ]
67
+ docs = [
68
+ "jinja2==3.0.3",
69
+ "mkdocs==1.2.3",
70
+ "mkdocs-autorefs==0.3.1",
71
+ "mkdocs-material==8.1.3",
72
+ "mkdocs-material-extensions==1.0.3",
73
+ "mkdocstrings==0.17.0",
74
+ "pytkdocs @ git+https://github.com/nstockton/pytkdocs.git@9991d493b408c403ac5691074e2af2e509f22926",
75
+ ]
76
+ lint = [
77
+ "isort>=5.13,<6.0",
78
+ "mypy>=1.14,<2.0",
79
+ "ruff>=0.9,<1.0",
80
+ ]
81
+ test = [
82
+ "coverage[toml]>=7.6,<8.0",
83
+ ]
84
+
85
+ [tool.pdm.build]
86
+ package-dir = "src"
87
+ includes = [
88
+ "src/knickknacks",
89
+ ]
90
+ excludes = []
91
+ source-includes = [
92
+ "tests",
93
+ "uv.lock",
94
+ ]
95
+
96
+ [tool.pdm.version]
97
+ fallback_version = "0.0.0"
98
+ source = "scm"
99
+ tag_filter = "[vV][0-9]*"
100
+ tag_regex = "^(?:[vV])(?P<version>\\d+\\.\\d+\\.\\d+)(?:.*)$"
101
+ write_to = "knickknacks/_version.py"
102
+ write_template = "__version__: str = \"{}\"\r\n"
103
+
104
+ [tool.uv]
105
+ default-groups = [
106
+ "dev",
107
+ "docs",
108
+ "lint",
109
+ "test",
110
+ ]
111
+ upgrade-package = [
112
+ "knickknacks",
113
+ ]
114
+
115
+ [tool.ruff]
116
+ extend-include = [
117
+ "*.pyw",
118
+ ]
119
+ force-exclude = true
120
+ line-length = 110
121
+
122
+ [tool.ruff.format]
123
+ docstring-code-format = false
124
+ indent-style = "tab"
125
+ line-ending = "cr-lf"
126
+
127
+ [tool.ruff.lint]
128
+ preview = true
129
+ select = [
130
+ "ALL",
131
+ ]
132
+ extend-select = [
133
+ "D213",
134
+ ]
135
+ ignore = [
136
+ "ANN",
137
+ "ARG",
138
+ "B019",
139
+ "COM812",
140
+ "D105",
141
+ "D206",
142
+ "D212",
143
+ "EM",
144
+ "G",
145
+ "I",
146
+ "PT",
147
+ "T20",
148
+ "TCH",
149
+ "TRY003",
150
+ "UP007",
151
+ "UP045",
152
+ "W191",
153
+ ]
154
+ typing-modules = [
155
+ "knickknacks.typedef",
156
+ ]
157
+ unfixable = []
158
+
159
+ [tool.ruff.lint.flake8-builtins]
160
+ builtins-ignorelist = []
161
+
162
+ [tool.ruff.lint.flake8-copyright]
163
+ author = "Nick Stockton"
164
+ min-file-size = 1
165
+
166
+ [tool.ruff.lint.flake8-implicit-str-concat]
167
+ allow-multiline = false
168
+
169
+ [tool.ruff.lint.mccabe]
170
+ max-complexity = 15
171
+
172
+ [tool.ruff.lint.per-file-ignores]
173
+ "**/__init__.py" = [
174
+ "D1",
175
+ ]
176
+ "**/_version.py" = [
177
+ "CPY001",
178
+ ]
179
+ "./tests/**" = [
180
+ "D1",
181
+ "PLR6301",
182
+ ]
183
+ "**/typedef.py" = [
184
+ "F401",
185
+ ]
186
+ "./src/knickknacks/backports.py" = [
187
+ "PLR2004",
188
+ ]
189
+ "./src/knickknacks/numbers.py" = [
190
+ "A005",
191
+ ]
192
+ "./src/knickknacks/testing.py" = [
193
+ "N802",
194
+ "N815",
195
+ ]
196
+ "./src/knickknacks/xml.py" = [
197
+ "A005",
198
+ ]
199
+
200
+ [tool.ruff.lint.pydocstyle]
201
+ convention = "google"
202
+ ignore-decorators = [
203
+ "typing.overload",
204
+ ]
205
+
206
+ [tool.ruff.lint.ruff]
207
+ parenthesize-tuple-in-subscript = true
208
+
209
+ [tool.coverage.report]
210
+ precision = 0
211
+ fail_under = 100.0
212
+ show_missing = true
213
+ skip_covered = true
214
+ sort = "Cover"
215
+ exclude_lines = [
216
+ "\\#\\s*pragma: no cover",
217
+ "^\\s*raise AssertionError\\b",
218
+ "^\\s*raise NotImplementedError\\b",
219
+ "^\\s*def __repr__",
220
+ "^\\s*def __str__",
221
+ "^\\s*if __name__ == .__main__.:",
222
+ ]
223
+
224
+ [tool.coverage.run]
225
+ source = [
226
+ "knickknacks",
227
+ ]
228
+ omit = [
229
+ "src/knickknacks/backports.py",
230
+ "src/knickknacks/typedef.py",
231
+ ]
232
+
233
+ [tool.isort]
234
+ line_length = 110
235
+ color_output = false
236
+ supported_extensions = [
237
+ "py",
238
+ "pyi",
239
+ "pys",
240
+ "pyw",
241
+ ]
242
+ extend_skip = []
243
+ indent = "tab"
244
+ atomic = true
245
+ dedup_headings = true
246
+ multi_line_output = 3
247
+ include_trailing_comma = true
248
+ force_grid_wrap = 0
249
+ use_parentheses = true
250
+ ensure_newline_before_comments = true
251
+ indented_import_headings = false
252
+ float_to_top = true
253
+ lines_after_imports = 2
254
+ force_adds = false
255
+ from_first = false
256
+ combine_as_imports = false
257
+ order_by_type = true
258
+ reverse_relative = true
259
+ add_imports = [
260
+ "from __future__ import annotations",
261
+ ]
262
+ default_section = "STDLIB"
263
+ import_heading_future = "Future Modules:"
264
+ import_heading_stdlib = "Built-in Modules:"
265
+ import_heading_thirdparty = "Third-party Modules:"
266
+ known_third_party = [
267
+ "backports.strenum",
268
+ "typing_extensions",
269
+ ]
270
+ import_heading_firstparty = "Knickknacks Modules:"
271
+ known_first_party = [
272
+ "knickknacks",
273
+ ]
274
+ import_heading_localfolder = "Local Modules:"
275
+
276
+ [tool.mypy]
277
+ files = [
278
+ "src/knickknacks",
279
+ "tests",
280
+ ]
281
+ exclude = "^$"
282
+ local_partial_types = true
283
+ strict = true
284
+ disallow_any_unimported = true
285
+ disallow_any_decorated = true
286
+ warn_unreachable = true
287
+ show_error_codes = true
288
+ no_color_output = true
289
+ overrides = [
290
+ { module = "tests.*", disallow_any_decorated = false },
291
+ ]
@@ -0,0 +1,37 @@
1
+ # Copyright (c) 2025 Nick Stockton
2
+ # -----------------------------------------------------------------------------
3
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ # of this software and associated documentation files (the "Software"), to deal
5
+ # in the Software without restriction, including without limitation the rights
6
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ # copies of the Software, and to permit persons to whom the Software is
8
+ # furnished to do so, subject to the following conditions:
9
+ # -----------------------------------------------------------------------------
10
+ # The above copyright notice and this permission notice shall be included in all
11
+ # copies or substantial portions of the Software.
12
+ # -----------------------------------------------------------------------------
13
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19
+ # SOFTWARE.
20
+
21
+ # Future Modules:
22
+ from __future__ import annotations
23
+
24
+ # Built-in Modules:
25
+ from contextlib import suppress
26
+ from typing import TYPE_CHECKING
27
+
28
+
29
+ __version__: str = "0.0.0"
30
+ if not TYPE_CHECKING:
31
+ with suppress(ImportError):
32
+ from ._version import __version__
33
+
34
+
35
+ __all__: list[str] = [
36
+ "__version__",
37
+ ]
@@ -0,0 +1 @@
1
+ __version__: str = "0.5.0"
@@ -0,0 +1,91 @@
1
+ # Copyright (c) 2025 Nick Stockton
2
+ # This Source Code Form is subject to the terms of the Mozilla Public
3
+ # License, v. 2.0. If a copy of the MPL was not distributed with this
4
+ # file, You can obtain one at http://mozilla.org/MPL/2.0/.
5
+
6
+ """Backported classes and functions."""
7
+
8
+ # Future Modules:
9
+ from __future__ import annotations
10
+
11
+ # Built-in Modules:
12
+ import io
13
+ import pathlib
14
+ import sys
15
+ from typing import Optional
16
+
17
+
18
+ if sys.version_info >= (3, 11):
19
+ from enum import StrEnum
20
+ else:
21
+ from backports.strenum import StrEnum
22
+
23
+
24
+ class Path(pathlib.Path):
25
+ """
26
+ Backported pathlib.Path functionality.
27
+
28
+ Currently backports the newline argument From 3.13 read_text, and 3.10 write_text.
29
+ """
30
+
31
+ def read_text(
32
+ self, encoding: Optional[str] = None, errors: Optional[str] = None, newline: Optional[str] = None
33
+ ) -> str:
34
+ """
35
+ Open the file in text mode, read it, and close the file.
36
+
37
+ Args:
38
+ encoding: The character encoding to use.
39
+ errors: How encoding errors should be handled.
40
+ newline: How newlines should be handled.
41
+
42
+ Returns:
43
+ The contents of the file.
44
+ """
45
+ if sys.version_info >= (3, 13):
46
+ text = super().read_text(encoding, errors, newline)
47
+ else:
48
+ if hasattr(io, "text_encoding"):
49
+ encoding = io.text_encoding(encoding)
50
+ with self.open(mode="r", encoding=encoding, errors=errors, newline=newline) as f:
51
+ text = f.read()
52
+ return text
53
+
54
+ def write_text(
55
+ self,
56
+ data: str,
57
+ encoding: Optional[str] = None,
58
+ errors: Optional[str] = None,
59
+ newline: Optional[str] = None,
60
+ ) -> int:
61
+ """
62
+ Open the file in text mode, write to it, and close the file.
63
+
64
+ Args:
65
+ data: The data to be written.
66
+ encoding: The character encoding to use.
67
+ errors: How encoding errors should be handled.
68
+ newline: How newlines should be handled.
69
+
70
+ Returns:
71
+ The number of bytes written.
72
+
73
+ Raises:
74
+ TypeError: Data is not an instance of `str`.
75
+ """
76
+ if sys.version_info >= (3, 10):
77
+ num_written = super().write_text(data, encoding, errors, newline)
78
+ else:
79
+ if not isinstance(data, str):
80
+ raise TypeError(f"data must be str, not {data.__class__.__name__}")
81
+ if hasattr(io, "text_encoding"):
82
+ encoding = io.text_encoding(encoding)
83
+ with self.open(mode="w", encoding=encoding, errors=errors, newline=newline) as f:
84
+ num_written = f.write(data)
85
+ return num_written
86
+
87
+
88
+ __all__: list[str] = [
89
+ "Path",
90
+ "StrEnum",
91
+ ]