stlib-ext 0.1.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,17 @@
1
+ from typing import Any
2
+ import warnings
3
+
4
+ def importDefaults(module) -> dict[str, Any]:
5
+ if not hasattr(module, "__defaults__"):
6
+ return {}
7
+ vals = {}
8
+ for obj in module.__defaults__:
9
+ if obj.__name__ in globals().keys():
10
+ warnings.warn(f"Warning: importDefaults may overwrite globals()[{repr(obj.__name__)}]")
11
+ vals[obj.__name__] = obj
12
+ return vals
13
+
14
+ from . import cache
15
+ from . import pyexperimental as exp
16
+
17
+ globals().update(importDefaults(exp))
morefunctools/cache.py ADDED
@@ -0,0 +1,59 @@
1
+ import math
2
+ from functools import lru_cache
3
+ from functools import wraps
4
+ from typing import Optional, Any
5
+ from collections.abc import Callable
6
+ from moretyping.visualise import VisLink
7
+ from .pyexperimental import experimental
8
+
9
+ type MaxSize = int | bool
10
+
11
+ class CacheInfo:
12
+ def __init__(self, hits: int, misses: int, maxsize: MaxSize, currsize: int) -> None:
13
+ self.hits = hits
14
+ self.misses = misses
15
+ self.maxsize = maxsize
16
+ self.currsize = currsize
17
+ self.locked = False
18
+
19
+ def lock(self) -> None:
20
+ self.locked = True
21
+
22
+ def __setattr__(self, name, value):
23
+ if self.locked == False:
24
+ self.__dict__[name] = value
25
+ else:
26
+ raise RuntimeError("Attempted to modify immutable object: CacheInfo")
27
+
28
+ # TODO: Implement cache_clear()
29
+ # TODO: Implement cache_info()
30
+ # TODO: Implement cache_entries()
31
+ @experimental
32
+ def fifo_cache(maxsize: Optional[MaxSize]) -> Callable[[Callable], Callable]:
33
+ if isinstance(maxsize, bool):
34
+ maxsize = math.inf if maxsize else 0
35
+
36
+ def decorator(function: Callable):
37
+ cache = {}
38
+ cacheList = [] # TODO: Switch to deque
39
+
40
+ @wraps(function)
41
+ def wrapper(*args, **kwargs) -> Any:
42
+ key = VisLink((tuple(args), tuple(kwargs.items()))).string
43
+ if key in set(cache.keys()): # TODO: Remove set()
44
+ return cache.get(key)
45
+
46
+ value = function(*args, **kwargs)
47
+ cacheList.append(key)
48
+ cache[key] = value
49
+
50
+ if len(cacheList) > maxsize:
51
+ removalKey = cacheList.pop(0)
52
+ cache.pop(removalKey)
53
+ print(f"Removing key: {removalKey}") # TODO: Remove debug print statements
54
+
55
+ return value
56
+
57
+ return wrapper
58
+
59
+ return decorator
@@ -0,0 +1,48 @@
1
+ from functools import wraps
2
+ from collections.abc import Callable
3
+ from typing import Any, Optional, overload
4
+ import warnings
5
+
6
+ class ExperimentalWarning(Warning):
7
+ def __init__(self, message: str) -> None:
8
+ self.msg = message
9
+ super().__init__(message)
10
+
11
+ @overload
12
+ def experimental(message: Optional[str] = None, category: type[Warning] = ExperimentalWarning, stacklevel: int = 2) -> Callable[[Callable], Callable]:
13
+ ...
14
+
15
+ @overload
16
+ def experimental(fn: Callable) -> Callable:
17
+ ...
18
+
19
+ # TODO: Clean up a little
20
+ def experimental(message: Optional[str] | Callable = None, category: type[Warning] = ExperimentalWarning, stacklevel: int = 2) -> Callable:
21
+ newMessage = None if callable(message) else message
22
+ if callable(message):
23
+ fn = message
24
+ message = None
25
+
26
+ @wraps(fn)
27
+ def wrapper(*args, **kwargs) -> Any:
28
+ warnings.warn(newMessage or f"Function {'{'}{fn.__name__}{'}'} is experimental. Expect bugs or incomplete behaviour.", category = category, stacklevel = stacklevel)
29
+ return fn(*args, **kwargs)
30
+
31
+ return wrapper
32
+
33
+ def decorator(fn: Callable) -> Callable:
34
+ @wraps(fn)
35
+ def wrapper(*args, **kwargs) -> Any:
36
+ warnings.warn(newMessage or f"Function {'{'}{fn.__name__}{'}'} is experimental. Expect bugs or incomplete behaviour.", category = category, stacklevel = stacklevel)
37
+ return fn(*args, **kwargs)
38
+ return wrapper
39
+
40
+ return decorator
41
+
42
+ @experimental
43
+ def test():
44
+ ...
45
+
46
+ __defaults__ = (
47
+ experimental,
48
+ )
moretyping/__init__.py ADDED
@@ -0,0 +1,4 @@
1
+ from . import data
2
+
3
+ from . import visualise
4
+ vis = visualise
@@ -0,0 +1 @@
1
+ from .number import Number
@@ -0,0 +1,35 @@
1
+ from typing import Any
2
+
3
+ class ProcessMeta(type):
4
+ __output_classes__: tuple[type, ...]
5
+
6
+ def __new__(mcls, name: str, bases: tuple[type, ...], namespace: dict[str, Any], *, output_classes: tuple[type, ...], **kwargs: Any) -> type:
7
+ oldnew = namespace["__new__"]
8
+
9
+ def __new__(cls: type, *args: Any, **kwargs: Any) -> Any:
10
+ value = oldnew(cls, *args, **kwargs)
11
+
12
+ for t in output_classes:
13
+ if isinstance(value, t):
14
+ break
15
+ else:
16
+ raise TypeError(f"Data processor `{name}` returned a value of type {type(value)} -- not one of {output_classes}")
17
+
18
+ return value
19
+
20
+ def __init__(self: Any, *_: Any, **__: Any) -> None:
21
+ raise RuntimeError(f"Attempted to initialise instance of {type(self)} (data processor). Invalid operation.")
22
+
23
+ namespace["__init__"] = __init__
24
+ namespace["__new__"] = __new__
25
+ namespace["__output_classes__"] = output_classes
26
+
27
+ cls = super().__new__(mcls, name, bases, namespace, **kwargs)
28
+ return cls
29
+
30
+ def __instancecheck__(cls: "ProcessMeta", instance: object) -> bool:
31
+ for t in cls.__output_classes__:
32
+ if isinstance(instance, t):
33
+ return True
34
+
35
+ return False
@@ -0,0 +1,27 @@
1
+ from typing import Any
2
+ from ._meta_process import ProcessMeta
3
+
4
+ type Numeric = int | float
5
+
6
+ class Number(metaclass=ProcessMeta, output_classes=(int, float)):
7
+ """
8
+ Convert an object of unknown type to a Numeric (`int|float`) value.
9
+
10
+ Args:
11
+ value: Numeric | Any — The value to cast to a Numeric type.
12
+
13
+ Returns:
14
+ Numeric — The value cast to a Numeric type.
15
+
16
+ Raises:
17
+ ValueError: If the value can't be cast to a numeric type.
18
+
19
+ Details:
20
+ If the value is an integer, return it unchanged.
21
+
22
+ Otherwise, return `float(value)`
23
+ """
24
+ def __new__(cls, value: Numeric | Any) -> int | float: # type: ignore[misc]
25
+ if isinstance(value, int):
26
+ return value
27
+ return float(value)
File without changes
@@ -0,0 +1,2 @@
1
+ from .lists import *
2
+ from .other import *
@@ -0,0 +1 @@
1
+ from .link import VisLink
@@ -0,0 +1,16 @@
1
+ from ..shared import VisualiseMeta
2
+ from typing import Any
3
+ from functools import cached_property
4
+ from collections.abc import Iterable
5
+
6
+ class VisLink(metaclass=VisualiseMeta):
7
+ def __init__(self, data: list[Any]) -> None:
8
+ self.data = tuple(data)
9
+
10
+ @cached_property
11
+ def strdata(self) -> Iterable[str]:
12
+ return map(lambda x: str(x), self.data)
13
+
14
+ @cached_property
15
+ def string(self) -> str:
16
+ return f"[ {" > ".join(self.strdata)} ]"
@@ -0,0 +1 @@
1
+ from .showjson import ViewJSON
@@ -0,0 +1,12 @@
1
+ from ..shared import VisualiseMeta
2
+ from functools import cached_property
3
+ from typing import Any, Optional
4
+ import json
5
+
6
+ class ViewJSON(metaclass=VisualiseMeta):
7
+ def __init__(self, data: Optional[Any] = {}) -> None:
8
+ self.data = data
9
+
10
+ @cached_property
11
+ def string(self) -> str:
12
+ return json.dumps(self.data, indent = 4)
@@ -0,0 +1,16 @@
1
+ from __future__ import annotations
2
+ from typing import Any
3
+
4
+ class VisualiseMeta(type):
5
+ def __new__(mcls: type[VisualiseMeta], name: str, bases: tuple[type, ...], namespace: dict[str, Any]) -> "VisualiseMeta":
6
+ def __repr__(self: Any) -> str:
7
+ return f"<{type(self).__name__} object> {self.__str__()}"
8
+
9
+ def __str__(self: Any) -> str:
10
+ return str(self.string)
11
+
12
+ namespace["__repr__"] = namespace.get("__repr__") or __repr__
13
+ namespace["__str__"] = namespace.get("__str__") or __str__
14
+ cls = super().__new__(mcls, name, bases, namespace)
15
+ return cls
16
+
stlib_ext/__init__.py ADDED
@@ -0,0 +1,2 @@
1
+ import moretyping
2
+ import morefunctools
@@ -0,0 +1,8 @@
1
+ Metadata-Version: 2.3
2
+ Name: stlib-ext
3
+ Version: 0.1.0
4
+ Summary: Add your description here
5
+ Requires-Python: >=3.13
6
+ Description-Content-Type: text/markdown
7
+
8
+ # stlib-ext
@@ -0,0 +1,18 @@
1
+ morefunctools/__init__.py,sha256=pntkIUGrDS0GLSo6gpSOis5yHzyN5RR45yPpNjVuplY,488
2
+ morefunctools/cache.py,sha256=tB7wLl0JQE1vU-v5cSiIyb7xQ5J8R8YeXVVNjUD_INc,1807
3
+ morefunctools/pyexperimental.py,sha256=kBO3J1wml4gaWyiMXhUyqfdUOBdidb0C3zHGfBN3PiY,1559
4
+ moretyping/__init__.py,sha256=y4oDRCAX70hi5l4AlHajG1NLLx9wYnAGKuLM2jMMvVc,60
5
+ moretyping/data/__init__.py,sha256=1VwgRodn7CEgyix_yyTEPLEsFSNw1HahvZPTnEU5aJw,27
6
+ moretyping/data/_meta_process.py,sha256=8Zq-50OZtXEfiYQMPXG-3WSfEI0T5nI9MUHQO785X4g,1342
7
+ moretyping/data/number.py,sha256=q94wYTPNyqP1-0jnVvamDBY9dpAXjfMyeXlm9CRcQeM,763
8
+ moretyping/meta/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
9
+ moretyping/visualise/__init__.py,sha256=D0d0F9kfpxuuBD2tTINmdXCFtsOa9oCzAeZX1lb2X8I,41
10
+ moretyping/visualise/lists/__init__.py,sha256=hEfBxoBKPOV3oaPiE-Td2tGkxAuSNiwiWP8GhFBp__E,25
11
+ moretyping/visualise/lists/link.py,sha256=Cdu_2gLc-Su3SsLv3foqnVq9bpWCw0d_lmjdUslIhpg,465
12
+ moretyping/visualise/other/__init__.py,sha256=Jq9DZTNQGhLfnjste45_ekTIn7w26iBUxGXFXNVeadA,30
13
+ moretyping/visualise/other/showjson.py,sha256=C_LRFqE0_Nw7EpDZkKvDUgaqR5evf2na4qTldoRUnHM,343
14
+ moretyping/visualise/shared.py,sha256=SkLR53iY1lqXBoMq4jY_LXPBhoNWMltZ2J04ptfB_v4,627
15
+ stlib_ext/__init__.py,sha256=ndgh7JT2wTwGdkUdTwUJPc1-WOGy_qfDzTqikmKStUg,39
16
+ stlib_ext-0.1.0.dist-info/WHEEL,sha256=CoDSoyhtC_eO_tlxRYzsTraPv1fPJRXFx91k6ISeAvA,81
17
+ stlib_ext-0.1.0.dist-info/METADATA,sha256=jgXS9mgg6UeH2Z5X9g32WYPmZn0S24t54Fju-_gDqAo,164
18
+ stlib_ext-0.1.0.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: uv 0.11.28
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any