hunterMakesPy 0.3.3__py3-none-any.whl → 0.4.0__py3-none-any.whl

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.
@@ -0,0 +1,70 @@
1
+ """Protocols for callable functions with full type safety."""
2
+ from collections.abc import Callable
3
+ from types import CellType, CodeType, MethodType
4
+ from typing import Any, overload, ParamSpec, Protocol, runtime_checkable, Self, TypeVar, TypeVarTuple
5
+ import sys
6
+
7
+ #======== Stolen, uh, I mean copied from typeshed:stdlib\_typeshed\__init__.pyi ========
8
+ type AnnotationForm = Any
9
+
10
+ if sys.version_info >= (3, 14):
11
+ from annotationlib import Format
12
+
13
+ # NOTE These return annotations, which can be arbitrary objects
14
+ type AnnotateFunc = Callable[[Format], dict[str, AnnotationForm]]
15
+ type EvaluateFunc = Callable[[Format], AnnotationForm]
16
+ #======== End stolen, uh, I mean copied from typeshed:stdlib\_typeshed\__init__.pyi ========
17
+
18
+ @runtime_checkable
19
+ class CallableFunction[**P, R](Protocol):
20
+ """A Protocol representing callable functions with descriptor support.
21
+
22
+ Mimics types.FunctionType while being a drop-in replacement for `collections.abc.Callable`. Includes all standard function
23
+ attributes and the descriptor protocol for proper method binding.
24
+
25
+ Note: @runtime_checkable only validates attribute presence, not signatures.
26
+ """
27
+
28
+ # NOTE: The eehhhh, IDK... section
29
+ __doc__: str | None
30
+ __wrapped__: Any # For functools.wraps support
31
+ # NOTE: End eehhhh, IDK... section
32
+
33
+ @property
34
+ def __closure__(self) -> tuple[CellType, ...] | None:
35
+ """Tuple of cells that contain bindings for the function's free variables."""
36
+ ...
37
+ __code__: CodeType
38
+ __defaults__: tuple[Any, ...] | None
39
+ __dict__: dict[str, Any]
40
+ @property
41
+ def __globals__(self) -> dict[str, Any]:
42
+ """The global namespace in which the function was defined."""
43
+ ...
44
+ __name__: str
45
+ __qualname__: str
46
+ __annotations__: dict[str, AnnotationForm]
47
+ if sys.version_info >= (3, 14):
48
+ __annotate__: AnnotateFunc | None
49
+ __kwdefaults__: dict[str, Any] | None
50
+ @property
51
+ def __builtins__(self) -> dict[str, Any]:
52
+ """The built-in namespace in which the function was defined."""
53
+ ...
54
+ __type_params__: tuple[TypeVar | ParamSpec | TypeVarTuple, ...]
55
+ __module__: str
56
+
57
+ def __call__(self, *args: P.args, **kwargs: P.kwargs) -> R:
58
+ """Execute the callable with the given arguments."""
59
+ ...
60
+
61
+ @overload
62
+ def __get__(self, instance: None, owner: type, /) -> Self: ...
63
+ @overload
64
+ def __get__(self, instance: object, owner: type | None = None, /) -> MethodType: ...
65
+ def __get__(self, instance: object | None, owner: type | None = None) -> Self | MethodType:
66
+ """Descriptor protocol for method binding.
67
+
68
+ Returns self when accessed on the class, or a bound MethodType when accessed on an instance.
69
+ """
70
+ ...
hunterMakesPy/__init__.py CHANGED
@@ -8,15 +8,22 @@ This package provides:
8
8
 
9
9
  """
10
10
 
11
- from hunterMakesPy.theTypes import identifierDotAttribute as identifierDotAttribute, Ordinals as Ordinals
11
+ # isort: split
12
+ from hunterMakesPy.theTypes import (
13
+ CallableFunction as CallableFunction, identifierDotAttribute as identifierDotAttribute, Ordinals as Ordinals)
12
14
 
15
+ # isort: split
13
16
  from hunterMakesPy.coping import PackageSettings as PackageSettings, raiseIfNone as raiseIfNone
14
17
 
18
+ # isort: split
15
19
  from hunterMakesPy.parseParameters import defineConcurrencyLimit, intInnit, oopsieKwargsie
16
20
 
21
+ # isort: split
17
22
  from hunterMakesPy.filesystemToolkit import (
18
23
  importLogicalPath2Identifier, importPathFilename2Identifier, makeDirsSafely, writePython, writeStringToHere)
19
24
 
25
+ # isort: split
20
26
  from hunterMakesPy.dataStructures import autoDecodingRLE, stringItUp, updateExtendPolishDictionaryLists
21
27
 
28
+ # isort: split
22
29
  from hunterMakesPy._theSSOT import settingsPackage # pyright: ignore[reportUnusedImport]
hunterMakesPy/coping.py CHANGED
@@ -2,14 +2,12 @@
2
2
  from importlib.util import find_spec
3
3
  from pathlib import Path
4
4
  from tomllib import loads as tomllib_loads
5
- from typing import TYPE_CHECKING, TypeVar
5
+ from typing import TYPE_CHECKING
6
6
  import dataclasses
7
7
 
8
8
  if TYPE_CHECKING:
9
9
  from importlib.machinery import ModuleSpec
10
10
 
11
- TypeSansNone = TypeVar('TypeSansNone')
12
-
13
11
  def getIdentifierPackagePACKAGING(identifierPackageFALLBACK: str) -> str:
14
12
  """Get package name from pyproject.toml or fallback to provided value."""
15
13
  try:
@@ -85,7 +83,7 @@ class PackageSettings:
85
83
  if self.pathPackage == Path() and self.identifierPackage:
86
84
  self.pathPackage = getPathPackageINSTALLING(self.identifierPackage)
87
85
 
88
- def raiseIfNone(expression: TypeSansNone | None, errorMessage: str | None = None) -> TypeSansNone:
86
+ def raiseIfNone[TypeSansNone](expression: TypeSansNone | None, errorMessage: str | None = None) -> TypeSansNone:
89
87
  """Convert the `expression` return annotation from '`cerPytainty | None`' to '`cerPytainty`' because `expression` cannot be `None`; `raise` an `Exception` if you're wrong.
90
88
 
91
89
  The Python interpreter evaluates `expression` to a value: think of a function call or an attribute access. You can use
@@ -6,5 +6,4 @@ Note: These test functions are now in `hunterMakesPy.tests` with all other tests
6
6
  """
7
7
 
8
8
  from hunterMakesPy.tests.test_parseParameters import (
9
- PytestFor_defineConcurrencyLimit as PytestFor_defineConcurrencyLimit, PytestFor_intInnit as PytestFor_intInnit,
10
- PytestFor_oopsieKwargsie as PytestFor_oopsieKwargsie)
9
+ PytestFor_defineConcurrencyLimit, PytestFor_intInnit, PytestFor_oopsieKwargsie)
@@ -1,3 +1,11 @@
1
+ """Configuration and fixtures for pytest.
2
+
3
+ (AI generated docstring)
4
+
5
+ This module provides shared fixtures and utility functions for the test suite,
6
+ including data paths, source code samples, and standardized assertion helpers.
7
+
8
+ """
1
9
  # pyright: standard
2
10
  from collections.abc import Callable
3
11
  from typing import Any
@@ -6,11 +14,26 @@ import pathlib
6
14
  import pytest
7
15
 
8
16
  # SSOT for test data paths and filenames
9
- pathDataSamples = pathlib.Path("hunterMakesPy/tests/dataSamples")
17
+ pathDataSamples: pathlib.Path = pathlib.Path("hunterMakesPy/tests/dataSamples")
10
18
 
11
19
  # Fixture to provide a temporary directory for filesystem tests
12
20
  @pytest.fixture
13
21
  def pathTmpTesting(tmp_path: pathlib.Path) -> pathlib.Path:
22
+ """Provide a temporary directory for filesystem tests.
23
+
24
+ (AI generated docstring)
25
+
26
+ Parameters
27
+ ----------
28
+ tmp_path : pathlib.Path
29
+ The pytest built-in temporary path fixture.
30
+
31
+ Returns
32
+ -------
33
+ pathTmpTesting : pathlib.Path
34
+ The path to the temporary directory.
35
+
36
+ """
14
37
  return tmp_path
15
38
 
16
39
  # Fixture for predictable Python source code samples
@@ -44,7 +67,27 @@ def listFileContentsFibonacci() -> list[str]:
44
67
  return ['fibonacci8', 'fibonacci13', 'fibonacci21', 'fibonacci34']
45
68
 
46
69
  def uniformTestFailureMessage(expected: Any, actual: Any, functionName: str, *arguments: Any, **keywordArguments: Any) -> str:
47
- """Format assertion message for any test comparison."""
70
+ """Format assertion message for any test comparison.
71
+
72
+ Parameters
73
+ ----------
74
+ expected : Any
75
+ The expected value or outcome.
76
+ actual : Any
77
+ The actual value or outcome received.
78
+ functionName : str
79
+ The name of the function or test case being executed.
80
+ *arguments : Any
81
+ Positional arguments passed to the function having its return value checked.
82
+ **keywordArguments : Any
83
+ Keyword arguments passed to the function having its return value checked.
84
+
85
+ Returns
86
+ -------
87
+ message : str
88
+ A formatted failure message detailing the expectation vs reality.
89
+
90
+ """
48
91
  listArgumentComponents: list[str] = [str(parameter) for parameter in arguments]
49
92
  listKeywordComponents: list[str] = [f"{key}={value}" for key, value in keywordArguments.items()]
50
93
  joinedArguments: str = ', '.join(listArgumentComponents + listKeywordComponents)
@@ -54,7 +97,22 @@ def uniformTestFailureMessage(expected: Any, actual: Any, functionName: str, *ar
54
97
  f"Got: {actual}")
55
98
 
56
99
  def standardizedEqualTo(expected: Any, functionTarget: Callable[..., Any], *arguments: Any, **keywordArguments: Any) -> None:
57
- """Template for most tests to compare the actual outcome with the expected outcome, including expected errors."""
100
+ """Template for most tests to compare actual outcome with expected outcome.
101
+
102
+ Includes handling for expected errors/exceptions.
103
+
104
+ Parameters
105
+ ----------
106
+ expected : Any
107
+ The expected return value, or an Exception type if an error is expected.
108
+ functionTarget : Callable[..., Any]
109
+ The function to call and test.
110
+ *arguments : Any
111
+ Positional arguments to pass to `functionTarget`.
112
+ **keywordArguments : Any
113
+ Keyword arguments to pass to `functionTarget`.
114
+
115
+ """
58
116
  if type(expected) == type[Exception]: # noqa: E721
59
117
  messageExpected: str = expected.__name__
60
118
  else:
@@ -63,7 +121,23 @@ def standardizedEqualTo(expected: Any, functionTarget: Callable[..., Any], *argu
63
121
  try:
64
122
  messageActual = actual = functionTarget(*arguments, **keywordArguments)
65
123
  except Exception as actualError:
66
- messageActual: str = type(actualError).__name__
124
+ messageActual = type(actualError).__name__
67
125
  actual = type(actualError)
68
126
 
69
- assert actual == expected, uniformTestFailureMessage(messageExpected, messageActual, functionTarget.__name__, *arguments, **keywordArguments)
127
+ functionName: str = getattr(functionTarget, "__name__", functionTarget.__class__.__name__)
128
+ assert actual == expected, uniformTestFailureMessage(messageExpected, messageActual, functionName, *arguments, **keywordArguments)
129
+
130
+ # Why I wish I could figure out how to implement standardized* test functions.
131
+ # ruff: noqa: ERA001
132
+ # standardizedEqualTo(expected, updateExtendPolishDictionaryLists, *value_dictionaryLists, **keywordArguments)
133
+ # NOTE one line of code with `standardizedEqualTo` (above) replaced the following ten lines of code. Use `standardizedEqualTo`.
134
+ # if isinstance(expected, type) and issubclass(expected, Exception):
135
+ # with pytest.raises(expected):
136
+ # updateExtendPolishDictionaryLists(*value_dictionaryLists, **keywordArguments)
137
+ # else:
138
+ # result = updateExtendPolishDictionaryLists(*value_dictionaryLists, **keywordArguments)
139
+ # if description == "Set values": # Special handling for unordered sets
140
+ # for key in result:
141
+ # assert sorted(result[key]) == sorted(expected[key])
142
+ # else:
143
+ # assert result == expected