advscope 0.1.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.
- advscope-0.1.0/PKG-INFO +13 -0
- advscope-0.1.0/advscope/__init__.py +19 -0
- advscope-0.1.0/advscope/core.py +150 -0
- advscope-0.1.0/advscope.egg-info/PKG-INFO +13 -0
- advscope-0.1.0/advscope.egg-info/SOURCES.txt +7 -0
- advscope-0.1.0/advscope.egg-info/dependency_links.txt +1 -0
- advscope-0.1.0/advscope.egg-info/top_level.txt +1 -0
- advscope-0.1.0/pyproject.toml +25 -0
- advscope-0.1.0/setup.cfg +4 -0
advscope-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: advscope
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Advanced scope utilities for Python.
|
|
5
|
+
Author: Olan
|
|
6
|
+
License: MIT
|
|
7
|
+
Keywords: scope,namespace,utilities
|
|
8
|
+
Classifier: Development Status :: 3 - Alpha
|
|
9
|
+
Classifier: Intended Audience :: Developers
|
|
10
|
+
Classifier: Programming Language :: Python :: 3
|
|
11
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
12
|
+
Classifier: Operating System :: OS Independent
|
|
13
|
+
Requires-Python: >=3.8
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
from .core import (
|
|
2
|
+
Namespace,
|
|
3
|
+
Scope,
|
|
4
|
+
GlobalScope,
|
|
5
|
+
LocalScope,
|
|
6
|
+
private,
|
|
7
|
+
isnamespace,
|
|
8
|
+
PrivateAccessError,
|
|
9
|
+
)
|
|
10
|
+
|
|
11
|
+
__all__ = [
|
|
12
|
+
"Namespace",
|
|
13
|
+
"Scope",
|
|
14
|
+
"GlobalScope",
|
|
15
|
+
"LocalScope",
|
|
16
|
+
"private",
|
|
17
|
+
"isnamespace",
|
|
18
|
+
"PrivateAccessError",
|
|
19
|
+
]
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
import functools
|
|
2
|
+
import inspect
|
|
3
|
+
import sys
|
|
4
|
+
import types
|
|
5
|
+
import weakref
|
|
6
|
+
|
|
7
|
+
class Namespace:
|
|
8
|
+
_private_methods = weakref.WeakKeyDictionary()
|
|
9
|
+
|
|
10
|
+
def __new__(cls, *args, **kwargs):
|
|
11
|
+
raise TypeError(
|
|
12
|
+
f"{cls.__name__} is a namespace and cannot be instantiated."
|
|
13
|
+
)
|
|
14
|
+
|
|
15
|
+
def __init_subclass__(cls):
|
|
16
|
+
super().__init_subclass__()
|
|
17
|
+
|
|
18
|
+
for name, value in list(cls.__dict__.items()):
|
|
19
|
+
func = value
|
|
20
|
+
|
|
21
|
+
if isinstance(value, staticmethod):
|
|
22
|
+
func = value.__func__
|
|
23
|
+
|
|
24
|
+
if isinstance(func, types.FunctionType):
|
|
25
|
+
original = getattr(
|
|
26
|
+
func,
|
|
27
|
+
"__advscope_original__",
|
|
28
|
+
func
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
if getattr(func, "__advscope_private__", False):
|
|
32
|
+
Namespace._private_methods[original] = cls
|
|
33
|
+
else:
|
|
34
|
+
setattr(
|
|
35
|
+
cls,
|
|
36
|
+
name,
|
|
37
|
+
staticmethod(func)
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
def isnamespace(obj):
|
|
41
|
+
"""
|
|
42
|
+
Return True if obj is a subclass of Namespace.
|
|
43
|
+
"""
|
|
44
|
+
|
|
45
|
+
return isinstance(obj, type) and issubclass(obj, Namespace)
|
|
46
|
+
|
|
47
|
+
class PrivateAccessError(Exception):
|
|
48
|
+
"""
|
|
49
|
+
Raised when a private member is accessed from outside
|
|
50
|
+
its allowed namespace.
|
|
51
|
+
"""
|
|
52
|
+
|
|
53
|
+
pass
|
|
54
|
+
|
|
55
|
+
def private(func):
|
|
56
|
+
if not isinstance(func, types.FunctionType):
|
|
57
|
+
raise TypeError("@private can only be used on functions")
|
|
58
|
+
|
|
59
|
+
@functools.wraps(func)
|
|
60
|
+
def wrapper(*args, **kwargs):
|
|
61
|
+
owner = Namespace._private_methods.get(func)
|
|
62
|
+
|
|
63
|
+
if owner is None:
|
|
64
|
+
raise PrivateAccessError(
|
|
65
|
+
f"Private member '{func.__name__}' has no namespace owner."
|
|
66
|
+
)
|
|
67
|
+
|
|
68
|
+
frame = inspect.currentframe().f_back
|
|
69
|
+
|
|
70
|
+
while frame:
|
|
71
|
+
for member in owner.__dict__.values():
|
|
72
|
+
if isinstance(member, staticmethod):
|
|
73
|
+
member = member.__func__
|
|
74
|
+
|
|
75
|
+
if isinstance(member, types.FunctionType):
|
|
76
|
+
if frame.f_code is member.__code__:
|
|
77
|
+
return func(*args, **kwargs)
|
|
78
|
+
|
|
79
|
+
frame = frame.f_back
|
|
80
|
+
|
|
81
|
+
raise PrivateAccessError(
|
|
82
|
+
f"Cannot access private member "
|
|
83
|
+
f"'{owner.__name__}.{func.__name__}' outside its namespace."
|
|
84
|
+
)
|
|
85
|
+
|
|
86
|
+
wrapper.__advscope_private__ = True
|
|
87
|
+
wrapper.__advscope_original__ = func
|
|
88
|
+
|
|
89
|
+
return wrapper
|
|
90
|
+
|
|
91
|
+
class GlobalScope:
|
|
92
|
+
"""
|
|
93
|
+
Represents a global scope shared across the application.
|
|
94
|
+
"""
|
|
95
|
+
|
|
96
|
+
def __new__(cls, *args, **kwargs):
|
|
97
|
+
raise TypeError(
|
|
98
|
+
"GlobalScope cannot be instantiated."
|
|
99
|
+
)
|
|
100
|
+
|
|
101
|
+
class LocalScopeMeta(type):
|
|
102
|
+
_storage = {}
|
|
103
|
+
|
|
104
|
+
def __getattr__(cls, name):
|
|
105
|
+
module = sys._getframe(1).f_globals["__name__"]
|
|
106
|
+
|
|
107
|
+
scope = cls._storage.get(module, {})
|
|
108
|
+
|
|
109
|
+
if name in scope:
|
|
110
|
+
return scope[name]
|
|
111
|
+
|
|
112
|
+
raise AttributeError(
|
|
113
|
+
f"{name!r} does not exist in local scope of {module}"
|
|
114
|
+
)
|
|
115
|
+
|
|
116
|
+
def __setattr__(cls, name, value):
|
|
117
|
+
if name == "_storage":
|
|
118
|
+
return super().__setattr__(name, value)
|
|
119
|
+
|
|
120
|
+
module = sys._getframe(1).f_globals["__name__"]
|
|
121
|
+
|
|
122
|
+
if module not in cls._storage:
|
|
123
|
+
cls._storage[module] = {}
|
|
124
|
+
|
|
125
|
+
cls._storage[module][name] = value
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
class LocalScope(metaclass=LocalScopeMeta):
|
|
129
|
+
"""
|
|
130
|
+
Scope that belongs only to the module using it.
|
|
131
|
+
"""
|
|
132
|
+
|
|
133
|
+
def __new__(cls, *args, **kwargs):
|
|
134
|
+
raise TypeError("LocalScope cannot be instantiated.")
|
|
135
|
+
|
|
136
|
+
class Scope:
|
|
137
|
+
"""
|
|
138
|
+
A dynamic attribute-based scope.
|
|
139
|
+
"""
|
|
140
|
+
|
|
141
|
+
def __init__(self, **kwargs):
|
|
142
|
+
for name, value in kwargs.items():
|
|
143
|
+
setattr(self, name, value)
|
|
144
|
+
|
|
145
|
+
def __repr__(self):
|
|
146
|
+
attrs = ", ".join(
|
|
147
|
+
f"{key}={value!r}"
|
|
148
|
+
for key, value in self.__dict__.items()
|
|
149
|
+
)
|
|
150
|
+
return f"Scope({attrs})"
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: advscope
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Advanced scope utilities for Python.
|
|
5
|
+
Author: Olan
|
|
6
|
+
License: MIT
|
|
7
|
+
Keywords: scope,namespace,utilities
|
|
8
|
+
Classifier: Development Status :: 3 - Alpha
|
|
9
|
+
Classifier: Intended Audience :: Developers
|
|
10
|
+
Classifier: Programming Language :: Python :: 3
|
|
11
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
12
|
+
Classifier: Operating System :: OS Independent
|
|
13
|
+
Requires-Python: >=3.8
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
advscope
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=61.0"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "advscope"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "Advanced scope utilities for Python."
|
|
9
|
+
requires-python = ">=3.8"
|
|
10
|
+
license = { text = "MIT" }
|
|
11
|
+
authors = [
|
|
12
|
+
{ name = "Olan" }
|
|
13
|
+
]
|
|
14
|
+
keywords = [
|
|
15
|
+
"scope",
|
|
16
|
+
"namespace",
|
|
17
|
+
"utilities"
|
|
18
|
+
]
|
|
19
|
+
classifiers = [
|
|
20
|
+
"Development Status :: 3 - Alpha",
|
|
21
|
+
"Intended Audience :: Developers",
|
|
22
|
+
"Programming Language :: Python :: 3",
|
|
23
|
+
"Programming Language :: Python :: 3 :: Only",
|
|
24
|
+
"Operating System :: OS Independent"
|
|
25
|
+
]
|
advscope-0.1.0/setup.cfg
ADDED