memorymanagement 1.4.0__tar.gz → 1.4.2__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.
- {memorymanagement-1.4.0 → memorymanagement-1.4.2}/PKG-INFO +13 -1
- {memorymanagement-1.4.0 → memorymanagement-1.4.2}/README.md +12 -0
- {memorymanagement-1.4.0 → memorymanagement-1.4.2}/memorymanagement/__init__.py +0 -1
- {memorymanagement-1.4.0 → memorymanagement-1.4.2}/memorymanagement/cleaning/__init__.py +26 -2
- {memorymanagement-1.4.0 → memorymanagement-1.4.2}/memorymanagement/cleaning/core.py +105 -11
- {memorymanagement-1.4.0 → memorymanagement-1.4.2}/memorymanagement/pointers/__init__.py +0 -1
- {memorymanagement-1.4.0 → memorymanagement-1.4.2}/memorymanagement/pointers/core.py +117 -18
- {memorymanagement-1.4.0 → memorymanagement-1.4.2}/memorymanagement/pointers/decorators.py +15 -3
- {memorymanagement-1.4.0 → memorymanagement-1.4.2}/memorymanagement.egg-info/PKG-INFO +13 -1
- {memorymanagement-1.4.0 → memorymanagement-1.4.2}/setup.cfg +1 -1
- {memorymanagement-1.4.0 → memorymanagement-1.4.2}/LICENSE +0 -0
- {memorymanagement-1.4.0 → memorymanagement-1.4.2}/memorymanagement.egg-info/SOURCES.txt +0 -0
- {memorymanagement-1.4.0 → memorymanagement-1.4.2}/memorymanagement.egg-info/dependency_links.txt +0 -0
- {memorymanagement-1.4.0 → memorymanagement-1.4.2}/memorymanagement.egg-info/top_level.txt +0 -0
- {memorymanagement-1.4.0 → memorymanagement-1.4.2}/pyproject.toml +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: memorymanagement
|
|
3
|
-
Version: 1.4.
|
|
3
|
+
Version: 1.4.2
|
|
4
4
|
Summary: Adds support for memory management
|
|
5
5
|
Home-page: https://github.com/Ricardo-Werner-Rivas/memorymanagement/tree/PyPI
|
|
6
6
|
Author: Ricardo Werner Rivas
|
|
@@ -104,6 +104,18 @@ cleaner.exclude(<name_var_1>,<name_var_2>,...)
|
|
|
104
104
|
```py
|
|
105
105
|
cleaner.include(<name_var_1>,<name_var_2>,...)
|
|
106
106
|
```
|
|
107
|
+
To flag all the excluded variables at once, you can use:
|
|
108
|
+
```py
|
|
109
|
+
cleaner.include_all(exclude=[<var_1>,<var_2>,...]) # exclude: optional keyword argument, accepts strings and iterables of strings
|
|
110
|
+
```
|
|
111
|
+
You can also exclude all the flagged variables like so:
|
|
112
|
+
```py
|
|
113
|
+
cleaner.exclude_all(include=[<var_1>,<var_2>,...]) # include: optional keyword argument, accepts strings and iterables of strings
|
|
114
|
+
```
|
|
115
|
+
And reset the cleaner's parameters like so:
|
|
116
|
+
```py
|
|
117
|
+
cleaner.purge()
|
|
118
|
+
```
|
|
107
119
|
### Class `Pointer`
|
|
108
120
|
Example:
|
|
109
121
|
```py
|
|
@@ -88,6 +88,18 @@ cleaner.exclude(<name_var_1>,<name_var_2>,...)
|
|
|
88
88
|
```py
|
|
89
89
|
cleaner.include(<name_var_1>,<name_var_2>,...)
|
|
90
90
|
```
|
|
91
|
+
To flag all the excluded variables at once, you can use:
|
|
92
|
+
```py
|
|
93
|
+
cleaner.include_all(exclude=[<var_1>,<var_2>,...]) # exclude: optional keyword argument, accepts strings and iterables of strings
|
|
94
|
+
```
|
|
95
|
+
You can also exclude all the flagged variables like so:
|
|
96
|
+
```py
|
|
97
|
+
cleaner.exclude_all(include=[<var_1>,<var_2>,...]) # include: optional keyword argument, accepts strings and iterables of strings
|
|
98
|
+
```
|
|
99
|
+
And reset the cleaner's parameters like so:
|
|
100
|
+
```py
|
|
101
|
+
cleaner.purge()
|
|
102
|
+
```
|
|
91
103
|
### Class `Pointer`
|
|
92
104
|
Example:
|
|
93
105
|
```py
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
"""
|
|
2
|
-
|
|
3
|
-
Implements the class `Cleaner` to keep track of the references and erase it easily.
|
|
2
|
+
Implements the class `Cleaner` to keep track of the references and erase them easily.
|
|
4
3
|
## Overview
|
|
5
4
|
Initialize a `Cleaner` object:
|
|
6
5
|
```
|
|
@@ -36,6 +35,31 @@ Flagged: ["x","y","z"]
|
|
|
36
35
|
Excluded: []
|
|
37
36
|
|
|
38
37
|
Not delete: <list(vars(modules["main"]))> # Unchanged since initialization
|
|
38
|
+
```
|
|
39
|
+
To delete these variables from memory, use the `clean()` method:
|
|
40
|
+
```
|
|
41
|
+
# Cleans memory
|
|
42
|
+
cleaner.clean()
|
|
43
|
+
|
|
44
|
+
# Print again the `Cleaner` instance
|
|
45
|
+
print(cleaner)
|
|
46
|
+
```
|
|
47
|
+
The output will now be:
|
|
48
|
+
```
|
|
49
|
+
Flagged: []
|
|
50
|
+
|
|
51
|
+
Excluded: []
|
|
52
|
+
|
|
53
|
+
Not delete: <list(vars(modules["main"]))> # Unchanged since initialization
|
|
54
|
+
```
|
|
55
|
+
And if we print the global variables:
|
|
56
|
+
```
|
|
57
|
+
print(list(globals()))
|
|
58
|
+
```
|
|
59
|
+
The output will be:
|
|
60
|
+
```
|
|
61
|
+
["Cleaner","cleaner"]
|
|
62
|
+
```
|
|
39
63
|
"""
|
|
40
64
|
# Imports
|
|
41
65
|
from .core import Cleaner
|
|
@@ -19,7 +19,6 @@ from sys import modules
|
|
|
19
19
|
#* MAIN CLASS
|
|
20
20
|
# Class "Cleaner"
|
|
21
21
|
class Cleaner:
|
|
22
|
-
#& Code comments
|
|
23
22
|
"""
|
|
24
23
|
Class for references management. It keeps track of the names of the global variables to be deleted and deletes them when ordered.
|
|
25
24
|
|
|
@@ -71,18 +70,23 @@ class Cleaner:
|
|
|
71
70
|
|
|
72
71
|
Arguments
|
|
73
72
|
---------
|
|
74
|
-
not_delete : `list[str]`, Optional
|
|
73
|
+
not_delete : `list[str]`|`None`, Optional
|
|
75
74
|
List of variables to never be deleted. It takes the list of global variables of the main module by default.
|
|
76
75
|
excluded : `list[str]`, Optional
|
|
77
76
|
List of variables to be excluded from the memory cleaning process. Empty list by default.
|
|
78
77
|
flagged : `list[str]`, Optional
|
|
79
78
|
List of variables to be erased from memory. Empty list by default.
|
|
80
79
|
"""
|
|
80
|
+
# If a "not_delete" list is not passed
|
|
81
81
|
if not not_delete:
|
|
82
|
+
# Take the list of global variables of the main module
|
|
82
83
|
not_delete=list(vars(modules["__main__"]))
|
|
84
|
+
# Loop through the global variables' dictionary of the main module
|
|
83
85
|
for key,value in vars(modules["__main__"]).copy().items():
|
|
86
|
+
# Delete every other "Cleaner" object
|
|
84
87
|
if isinstance(value,Cleaner) and key in vars(modules["__main__"]).keys():
|
|
85
88
|
del vars(modules["__main__"])[key]
|
|
89
|
+
# Declare the main attributes
|
|
86
90
|
self._not_delete=not_delete.copy()
|
|
87
91
|
self._excluded=excluded.copy()
|
|
88
92
|
self._flagged=flagged.copy()
|
|
@@ -102,16 +106,26 @@ class Cleaner:
|
|
|
102
106
|
include : `str`|`list[str]`|`tuple[str]`|`None`, Optional
|
|
103
107
|
Allows you to include a single (`str`) or multiple (`list` or `tuple`) variables. `None` by default.
|
|
104
108
|
"""
|
|
109
|
+
# If there are variables to exclude
|
|
105
110
|
if exclude:
|
|
111
|
+
# If "exclude" content is a string
|
|
106
112
|
if isinstance(exclude,str):
|
|
113
|
+
# Make it a list
|
|
107
114
|
exclude=[exclude]
|
|
115
|
+
# Introduce the excluded variables into the corresponding lists
|
|
108
116
|
self._excluded.extend([var for var in exclude if var not in self._excluded])
|
|
117
|
+
# If the are excluded variables to include
|
|
109
118
|
if include:
|
|
119
|
+
# If "include" content is a string
|
|
110
120
|
if isinstance(include,str):
|
|
121
|
+
# Make it a list
|
|
111
122
|
include=[include]
|
|
123
|
+
# Loop for "include"
|
|
112
124
|
for var in include:
|
|
125
|
+
# Remove every occurrence of the variables to include from the "excluded" list
|
|
113
126
|
while var in self._excluded:
|
|
114
127
|
self._excluded.remove(var)
|
|
128
|
+
# Rebuild the "flagged" list
|
|
115
129
|
self._flagged=[var for var in list(vars(modules["__main__"]))if var not in self.not_delete and var not in self.excluded]
|
|
116
130
|
|
|
117
131
|
# Exclude
|
|
@@ -124,9 +138,12 @@ class Cleaner:
|
|
|
124
138
|
exclude : `tuple[str]`
|
|
125
139
|
Stream of references to be excluded.
|
|
126
140
|
"""
|
|
141
|
+
# Loop for the variables to exclude
|
|
127
142
|
for var in exclude:
|
|
143
|
+
# Remove from the "flagged" list
|
|
128
144
|
while var in self._flagged:
|
|
129
145
|
self._flagged.remove(var)
|
|
146
|
+
# Introduce variable into the "excluded" list
|
|
130
147
|
if var not in self._excluded:
|
|
131
148
|
self._excluded.append(var)
|
|
132
149
|
|
|
@@ -140,35 +157,91 @@ class Cleaner:
|
|
|
140
157
|
include : `tuple[str]`
|
|
141
158
|
Stream of references to be included.
|
|
142
159
|
"""
|
|
160
|
+
# Loop for the variables to "include"
|
|
143
161
|
for var in include:
|
|
162
|
+
# Introduce variable into the "flagged" list
|
|
144
163
|
if var not in self._flagged:
|
|
145
164
|
self._flagged.append(var)
|
|
165
|
+
# Remove from excluded list
|
|
146
166
|
while var in self._excluded:
|
|
147
167
|
self._excluded.remove(var)
|
|
148
168
|
|
|
149
169
|
# Include all excluded variables
|
|
150
|
-
def include_all(self):
|
|
170
|
+
def include_all(self,*,exclude:str|list[str]|tuple[str]|None=None):
|
|
151
171
|
"""
|
|
152
172
|
Flag all the excluded variables and clear the `excluded` list
|
|
173
|
+
|
|
174
|
+
Arguments
|
|
175
|
+
---------
|
|
176
|
+
exclude : `str`|`list[str]`|`tuple[str]`|`None`, Optional
|
|
177
|
+
Variables not to be included into the `flagged` list
|
|
153
178
|
"""
|
|
179
|
+
# Introduce excluded variables into the "flagged" list
|
|
154
180
|
self._flagged.extend(self.excluded)
|
|
181
|
+
# Clear the "excluded" list
|
|
155
182
|
self._excluded.clear()
|
|
183
|
+
|
|
184
|
+
# If the are exceptions
|
|
185
|
+
if exclude:
|
|
186
|
+
# If "exclude" content is a string
|
|
187
|
+
if isinstance(exclude,str):
|
|
188
|
+
# Exclude variable
|
|
189
|
+
self.exclude(exclude)
|
|
190
|
+
# Else
|
|
191
|
+
else:
|
|
192
|
+
# Exclude variables (unpacking)
|
|
193
|
+
self.exclude(*exclude)
|
|
156
194
|
|
|
157
195
|
# Exclude all flagged variables
|
|
158
|
-
def exclude_all(self):
|
|
196
|
+
def exclude_all(self,*,include:str|list[str]|tuple[str]|None=None):
|
|
159
197
|
"""
|
|
160
198
|
Exclude all the flagged variables and clear the `flagged` list
|
|
199
|
+
|
|
200
|
+
Arguments
|
|
201
|
+
---------
|
|
202
|
+
include : `str`|`list[str]`|`tuple[str]`|`None`, Optional
|
|
203
|
+
Variables not to be excluded from the `flagged` list
|
|
161
204
|
"""
|
|
205
|
+
# Introduce excluded variables into the "excluded" list
|
|
162
206
|
self._excluded.extend(self.flagged)
|
|
207
|
+
# Clear the "flagged" list
|
|
163
208
|
self._flagged.clear()
|
|
209
|
+
|
|
210
|
+
# If there are exceptions
|
|
211
|
+
if include:
|
|
212
|
+
# If "include" content is a string
|
|
213
|
+
if isinstance(include,str):
|
|
214
|
+
# Include varianle
|
|
215
|
+
self.include(include)
|
|
216
|
+
# Else
|
|
217
|
+
else:
|
|
218
|
+
# Include variables (unpacking)
|
|
219
|
+
self.include(*include)
|
|
164
220
|
|
|
165
221
|
# Purge flagged and excluded variables
|
|
166
|
-
def purge(self):
|
|
222
|
+
def purge(self,*,flagged:bool=True,excluded:bool=True):
|
|
167
223
|
"""
|
|
168
224
|
Clears both `flagged` and `excluded` lists from the `Cleaner` object.
|
|
225
|
+
|
|
226
|
+
Arguments
|
|
227
|
+
---------
|
|
228
|
+
flagged : `bool`, Optional
|
|
229
|
+
Wether the `flagged` list should be purged (`True`) or not (`False`). `True` by default
|
|
230
|
+
excluded : `bool`, Optional
|
|
231
|
+
Wether the `excluded` list should be purged (`True`) or not (`False`). `True` by default
|
|
169
232
|
"""
|
|
170
|
-
|
|
171
|
-
|
|
233
|
+
# If there is no list to be purged
|
|
234
|
+
if not flagged and not excluded:
|
|
235
|
+
# Pass
|
|
236
|
+
pass
|
|
237
|
+
# If "flagged" is set to be purged
|
|
238
|
+
if flagged:
|
|
239
|
+
# Clear "flagged"
|
|
240
|
+
self._flagged.clear()
|
|
241
|
+
# If "excluded" is set to be purged
|
|
242
|
+
if excluded:
|
|
243
|
+
# Clear "excluded"
|
|
244
|
+
self._excluded.clear()
|
|
172
245
|
|
|
173
246
|
# Clean
|
|
174
247
|
def clean(self):
|
|
@@ -176,9 +249,13 @@ class Cleaner:
|
|
|
176
249
|
Culminates the cleaning process.
|
|
177
250
|
Erases all the flagged references.
|
|
178
251
|
"""
|
|
252
|
+
# Loop for "flagged" list
|
|
179
253
|
for var in self._flagged:
|
|
254
|
+
# If current variable name is between the global variables of "__main__"
|
|
180
255
|
if var in list(vars(modules["__main__"])):
|
|
256
|
+
# Delete variable
|
|
181
257
|
del vars(modules["__main__"])[var]
|
|
258
|
+
# Clear "flagged" list
|
|
182
259
|
self._flagged.clear()
|
|
183
260
|
|
|
184
261
|
#* PROPERTIES
|
|
@@ -186,19 +263,32 @@ class Cleaner:
|
|
|
186
263
|
@property
|
|
187
264
|
# Getter
|
|
188
265
|
def not_delete(self):
|
|
266
|
+
# If reference is not set or it doesn't point to the "Cleaner" object
|
|
189
267
|
if not self._name or vars(modules["__main__"])[self._name] is not self:
|
|
268
|
+
# Loop for variables dictionary
|
|
190
269
|
for key,value in vars(modules["__main__"]).items():
|
|
270
|
+
# If current value is the "Cleaner" object
|
|
191
271
|
if value is self:
|
|
272
|
+
# Store the reference
|
|
192
273
|
self._name=key
|
|
274
|
+
# Add it to the "not_delete" list
|
|
193
275
|
self._not_delete.append(self._name)
|
|
276
|
+
# Break
|
|
194
277
|
break
|
|
278
|
+
# Else
|
|
195
279
|
else:
|
|
280
|
+
# Reference is still empty
|
|
196
281
|
self._name=None
|
|
282
|
+
# If reference remains empty
|
|
197
283
|
if not self._name:
|
|
198
|
-
|
|
284
|
+
# Raise a "ReferenceError"
|
|
285
|
+
raise ReferenceError("\"Cleaner\" object is not referenced")
|
|
286
|
+
# Else, if reference is not in the "not_delete" list
|
|
199
287
|
elif self._name not in self._not_delete:
|
|
288
|
+
# Add reference to the "not_delete" list
|
|
200
289
|
self._not_delete.append(self._name)
|
|
201
|
-
|
|
290
|
+
# Return a shallow copy of the "not_delete" list
|
|
291
|
+
return self._not_delete.copy()
|
|
202
292
|
#^ No setter
|
|
203
293
|
#^ No deleter
|
|
204
294
|
|
|
@@ -206,7 +296,8 @@ class Cleaner:
|
|
|
206
296
|
@property
|
|
207
297
|
# Getter
|
|
208
298
|
def excluded(self):
|
|
209
|
-
|
|
299
|
+
# Return a shallow copy of the "excluded" list
|
|
300
|
+
return self._excluded.copy()
|
|
210
301
|
#^ No setter
|
|
211
302
|
#^ No deleter
|
|
212
303
|
|
|
@@ -214,13 +305,15 @@ class Cleaner:
|
|
|
214
305
|
@property
|
|
215
306
|
# Getter
|
|
216
307
|
def flagged(self):
|
|
217
|
-
|
|
308
|
+
# Return a shallow copy of the "flagged" list
|
|
309
|
+
return self._flagged.copy()
|
|
218
310
|
#^ No setter
|
|
219
311
|
#^ No deleter
|
|
220
312
|
|
|
221
313
|
#* SCREEN DUNDER METHODS
|
|
222
314
|
# __str__
|
|
223
315
|
def __str__(self):
|
|
316
|
+
# Return a string with the instance's components
|
|
224
317
|
return f"""
|
|
225
318
|
Flagged: {self.flagged}
|
|
226
319
|
|
|
@@ -231,4 +324,5 @@ class Cleaner:
|
|
|
231
324
|
|
|
232
325
|
# __repr__
|
|
233
326
|
def __repr__(self):
|
|
327
|
+
# Return a string able to rebuild the instance if needed
|
|
234
328
|
return f"{self.__class__.__name__}(not_delete={self.not_delete},excluded={self.excluded},flagged={self.flagged})"
|
|
@@ -25,7 +25,6 @@ PT=TypeVar("PT")
|
|
|
25
25
|
#* MAIN CLASS
|
|
26
26
|
# Define the class "Pointer" with generic type
|
|
27
27
|
class Pointer(Generic[PT]):
|
|
28
|
-
#& Missing code comments
|
|
29
28
|
"""
|
|
30
29
|
Implements pointers in Python for both mutable (though unneded) and non-mutable objects.
|
|
31
30
|
These pointers are completely safe and do not work internally as C's pointers, they are just an imitation of their behaviour.
|
|
@@ -102,31 +101,53 @@ class Pointer(Generic[PT]):
|
|
|
102
101
|
local : `bool`, Optional
|
|
103
102
|
Indicates if the value to point to is a local variable (`True` for yes and `False` for no). `False` by default.
|
|
104
103
|
"""
|
|
104
|
+
# If pointing to local variable
|
|
105
105
|
if local:
|
|
106
|
+
# Take the local frame
|
|
106
107
|
vars_dict=currentframe().f_back.f_locals
|
|
108
|
+
# Else
|
|
107
109
|
else:
|
|
110
|
+
# Take the global frame
|
|
108
111
|
vars_dict=vars(modules["__main__"])
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
self.
|
|
112
|
+
|
|
113
|
+
# Store hidden attributes
|
|
114
|
+
self._value=value # Pointer's value
|
|
115
|
+
self._vars_dict=vars_dict # Variables' frame
|
|
116
|
+
self._attr=attr # Instance attribute to point to
|
|
117
|
+
|
|
118
|
+
# If there is an instance's attribute to point to and it doesn't belong to the given value
|
|
112
119
|
if self._attr and self._attr not in dir(self._value):
|
|
120
|
+
# Raise an "AttributeError"
|
|
113
121
|
raise AttributeError(f"\"{attr}\" is not an attribute of \"{self._value}\"")
|
|
122
|
+
# If a reference is given
|
|
114
123
|
if reference:
|
|
124
|
+
# If the reference is in the variables' frame and points to the given value
|
|
115
125
|
if reference in vars_dict and vars_dict[reference] is value:
|
|
126
|
+
# Store the reference in "name" local variable
|
|
116
127
|
name=reference
|
|
128
|
+
# Else, if the reference isn't in the variables' frame
|
|
117
129
|
elif reference not in vars_dict:
|
|
130
|
+
# Raise a "NameError"
|
|
118
131
|
raise NameError(f"Name \"{reference}\" is not defined")
|
|
132
|
+
# Else, if the reference doesn't point to the given value
|
|
119
133
|
elif vars_dict[reference] is not value:
|
|
134
|
+
# Raise a "ValueError"
|
|
120
135
|
raise ValueError(f"Name \"{reference}\" doesn't point to given value ({value})")
|
|
136
|
+
# Else
|
|
121
137
|
else:
|
|
138
|
+
# Store every reference pointing to the given value
|
|
122
139
|
name=[key for key,v in vars_dict.items() if v is value]
|
|
123
|
-
|
|
140
|
+
# Set to "None" if no reference was found
|
|
141
|
+
name=name[0] if len(name)!=0 else None
|
|
142
|
+
# Store the reference in the hidden attribute "_name"
|
|
124
143
|
self._name=name
|
|
144
|
+
# If there is no reference
|
|
125
145
|
if self._name==None:
|
|
146
|
+
# Raise a "NameError"
|
|
126
147
|
raise NameError(f"No reference is pointing to given value \"{self._value}\"")
|
|
127
148
|
|
|
128
149
|
# Point to
|
|
129
|
-
def point_to(self,reference:str|None=None
|
|
150
|
+
def point_to(self,value=None,reference:str|None=None,*,attr:str|None=None):
|
|
130
151
|
"""
|
|
131
152
|
Changes the address which the `Pointer` object points to.
|
|
132
153
|
|
|
@@ -139,48 +160,103 @@ class Pointer(Generic[PT]):
|
|
|
139
160
|
attr : `str`|`None`, Optional
|
|
140
161
|
Attribute of the class if class object was passed through `reference` or `value`.
|
|
141
162
|
"""
|
|
163
|
+
# If no reference or value is given
|
|
142
164
|
if not reference and not value:
|
|
143
|
-
|
|
165
|
+
# If an instance's attribute name is given
|
|
166
|
+
if attr:
|
|
167
|
+
# If the attribute belongs to the pointer's value
|
|
168
|
+
if attr in dir(self._value):
|
|
169
|
+
# Store the attribute name into its corresponding hidden attribute
|
|
170
|
+
self._attr=attr
|
|
171
|
+
# Else
|
|
172
|
+
else:
|
|
173
|
+
# Raise an "AttributeError"
|
|
174
|
+
raise AttributeError(f"\"{attr}\" isn't an attribute of the variable \"{self._name}\" with value \"{self._value}\" (\"{self._value.__class__.__name__}\")")
|
|
175
|
+
# Else
|
|
176
|
+
else:
|
|
177
|
+
# Raise a "ValueError"
|
|
178
|
+
raise ValueError("No argument was given")
|
|
179
|
+
# Else, if both reference and value are given
|
|
144
180
|
elif reference and value:
|
|
181
|
+
# If the reference is in the variables' frame and it points to the given value
|
|
145
182
|
if reference in self._vars_dict and self._vars_dict[reference] is value:
|
|
183
|
+
# Store both into their corresponding hidden attributes
|
|
146
184
|
self._name,self._value=reference,value
|
|
185
|
+
# If an attribute name is given
|
|
147
186
|
if attr:
|
|
187
|
+
# If the attribute belongs to the given value
|
|
148
188
|
if attr in dir(self._value):
|
|
189
|
+
# Store attribute name into its corresponding hidden attribute
|
|
149
190
|
self._attr=attr
|
|
191
|
+
# Else
|
|
150
192
|
else:
|
|
193
|
+
# Raise an "AttributeError"
|
|
151
194
|
raise AttributeError(f"\"{attr}\" is not an attribute of \"{self._value}\"")
|
|
195
|
+
# Else, if the reference isn't in the variables' frame
|
|
152
196
|
elif reference not in self._vars_dict:
|
|
197
|
+
# Raise a "NameError"
|
|
153
198
|
raise NameError(f"Name \"{reference}\" is not defined")
|
|
199
|
+
# Else, if the reference doesn't point to the given value
|
|
154
200
|
elif self._vars_dict[reference] is not value:
|
|
201
|
+
# Raise a "ValueError"
|
|
155
202
|
raise ValueError(f"Name \"{reference}\" doesn't point to given value \"{value}\"")
|
|
203
|
+
# Else, if only a reference is given
|
|
156
204
|
elif reference:
|
|
205
|
+
# If the reference is in the variables' frame
|
|
157
206
|
if reference in self._vars_dict:
|
|
207
|
+
# Store the reference and the value it is pointing to into their corresponding hidden attributes
|
|
158
208
|
self._name,self._value=reference,self._vars_dict[reference]
|
|
209
|
+
# If an instance's attribute name is given
|
|
159
210
|
if attr:
|
|
211
|
+
# If the attribute belongs to the new value
|
|
160
212
|
if attr in dir(self._value):
|
|
213
|
+
# Store the attribute name into its corresponding hidden attribute
|
|
161
214
|
self._attr=attr
|
|
215
|
+
# Else
|
|
162
216
|
else:
|
|
217
|
+
# Raise an "AttributeError"
|
|
163
218
|
raise AttributeError(f"\"{attr}\" is not an attribute of \"{self._value}\"")
|
|
219
|
+
# Else
|
|
164
220
|
else:
|
|
221
|
+
# Raise a "NameError"
|
|
165
222
|
raise NameError(f"Name \"{reference}\" is not defined")
|
|
223
|
+
# Else, if only a value is given
|
|
166
224
|
elif value:
|
|
225
|
+
# Store the given value and its references into their corresponding hidden attributes
|
|
167
226
|
self._name,self._value=[key for key,v in self._vars_dict.items() if v is value],value
|
|
168
|
-
|
|
227
|
+
# Modify the "_name" hidden attribute to be a string or "None"
|
|
228
|
+
self._name=self._name[0] if len(self._name)!=0 else None
|
|
229
|
+
# If no reference was found
|
|
169
230
|
if self._name==None:
|
|
231
|
+
# Raise a "NameError"
|
|
170
232
|
raise NameError(f"No reference is pointing to given value \"{self._value}\"")
|
|
233
|
+
# If an instance's attribute name is given
|
|
171
234
|
if attr:
|
|
235
|
+
# If the attribute belongs to the new value
|
|
172
236
|
if attr in dir(self._value):
|
|
237
|
+
# Store the attribute name into its corresponding hidden attribute
|
|
173
238
|
self._attr=attr
|
|
239
|
+
# Else
|
|
174
240
|
else:
|
|
241
|
+
# Raise an "AttributeError"
|
|
175
242
|
raise AttributeError(f"\"{attr}\" is not an attribute of \"{self._value}\"")
|
|
176
243
|
|
|
177
244
|
# Get references
|
|
178
|
-
def get_refs(self):
|
|
245
|
+
def get_refs(self)->tuple[str]:
|
|
179
246
|
"""
|
|
180
247
|
Gets all the references pointing to the same current value of the `Pointer` object.
|
|
181
248
|
"""
|
|
249
|
+
# Find and return all the references pointing to the pointer's value
|
|
182
250
|
return tuple(key for key,v in self._vars_dict.items() if v is self._value)
|
|
183
251
|
|
|
252
|
+
# Print references
|
|
253
|
+
def print_refs(self):
|
|
254
|
+
"""
|
|
255
|
+
Prints all the references pointing to the same current value of the pointer.
|
|
256
|
+
"""
|
|
257
|
+
# Print all the references pointing to the pointer's value
|
|
258
|
+
print(tuple(key for key,v in self._vars_dict.items() if v is self._value))
|
|
259
|
+
|
|
184
260
|
# Switch reference
|
|
185
261
|
def switch_ref(self,reference:str):
|
|
186
262
|
"""
|
|
@@ -191,65 +267,90 @@ class Pointer(Generic[PT]):
|
|
|
191
267
|
reference : `str`
|
|
192
268
|
Reference to switch the pointer to.
|
|
193
269
|
"""
|
|
270
|
+
# If the given reference is in the variables' frame but it doesn' point to current the pointer's value
|
|
194
271
|
if reference in self._vars_dict and self._vars_dict[reference] is not self.value:
|
|
272
|
+
# Raise a "ValueError"
|
|
195
273
|
raise ValueError(f"Name \"{reference}\" doesn't point to pointer's value \"{self.value}\"")
|
|
274
|
+
# Else, if the given reference is not in the variables' frame
|
|
196
275
|
elif reference not in self._vars_dict:
|
|
276
|
+
# Raise a "NameError"
|
|
197
277
|
raise NameError(f"Name \"{reference}\" is not defined")
|
|
278
|
+
# Store the reference into its corresponding hidden attribute
|
|
198
279
|
self._name=reference
|
|
199
280
|
|
|
200
|
-
# Print references
|
|
201
|
-
def print_refs(self):
|
|
202
|
-
"""
|
|
203
|
-
Prints all the references pointing to the same current value of the pointer.
|
|
204
|
-
"""
|
|
205
|
-
print(tuple(key for key,v in self._vars_dict.items() if v is self._value))
|
|
206
|
-
|
|
207
281
|
#* PROPERTIES
|
|
208
282
|
# Value
|
|
209
283
|
@property
|
|
210
284
|
# Getter
|
|
211
285
|
def value(self):
|
|
286
|
+
# If an instance's attribute name is stored
|
|
212
287
|
if self.attr:
|
|
288
|
+
# If the stored reference is not in the variables' frame
|
|
213
289
|
if self.reference not in self._vars_dict:
|
|
290
|
+
# Delete the pointer's value and the stored attribute name
|
|
214
291
|
del self._value,self.attr
|
|
292
|
+
# Raise a "NameError"
|
|
215
293
|
raise NameError("The class instance has already been deleted, so the pointer no longer has access to it.")
|
|
294
|
+
# Else, if the stored attribute name doesn't belong to the pointer's value
|
|
216
295
|
elif self.attr not in dir(self._value):
|
|
296
|
+
# Raise an "AttributeError"
|
|
217
297
|
raise AttributeError(f"The atribute \"{self._attr}\" has already been deleted, so the pointer no longer has access to it.")
|
|
298
|
+
# Return the instance attribute's value
|
|
218
299
|
return getattr(self._value,self.attr)
|
|
300
|
+
# Else
|
|
219
301
|
else:
|
|
302
|
+
# If the stored reference is not in the variables' frame
|
|
220
303
|
if self.reference not in self._vars_dict:
|
|
304
|
+
# Delete the pointer's hidden attribute "_value"
|
|
221
305
|
del self._value
|
|
306
|
+
# Raise a "NameError"
|
|
222
307
|
raise NameError("The variable has already been deleted, so the pointer no longer has access to it.")
|
|
308
|
+
# If the original value differs from the stored one (because it was changed)
|
|
223
309
|
if self._value is not self._vars_dict[self.reference]:
|
|
310
|
+
# Update the pointer's value
|
|
224
311
|
self._value=self._vars_dict[self.reference]
|
|
312
|
+
# Return the pointer's value
|
|
225
313
|
return self._value
|
|
226
314
|
# Setter
|
|
227
315
|
@value.setter
|
|
228
316
|
def value(self,value):
|
|
317
|
+
# If an attribute name is stored
|
|
229
318
|
if self.attr:
|
|
319
|
+
# Set the instance' attribute to the new value
|
|
230
320
|
setattr(self._value,self.attr,value)
|
|
321
|
+
# Else
|
|
231
322
|
else:
|
|
323
|
+
# Set the pointers value to the new value
|
|
232
324
|
self._value=value
|
|
325
|
+
# If the new pointer's value differs from the original variable
|
|
233
326
|
if value is not self._vars_dict[self.reference]:
|
|
327
|
+
# Update the original variable setting it to the new value
|
|
234
328
|
self._vars_dict[self.reference]=value
|
|
235
329
|
# Deleter
|
|
236
330
|
@value.deleter
|
|
237
331
|
def value(self):
|
|
332
|
+
# If an attribute name is stored
|
|
238
333
|
if self.attr:
|
|
334
|
+
# Delete the attribute from the stored instance
|
|
239
335
|
delattr(self._value,self.attr)
|
|
336
|
+
# Else
|
|
240
337
|
else:
|
|
338
|
+
# Delete the "_value" pointer's hidden attribute
|
|
241
339
|
del self._value
|
|
340
|
+
# Delete the corresponding variable
|
|
242
341
|
del self._vars_dict[self.reference]
|
|
243
342
|
|
|
244
343
|
# Reference
|
|
245
344
|
@property
|
|
246
345
|
# Getter
|
|
247
346
|
def reference(self):
|
|
347
|
+
# Return the stored reference
|
|
248
348
|
return self._name
|
|
249
349
|
|
|
250
350
|
# Attribute
|
|
251
351
|
@property
|
|
252
352
|
def attr(self):
|
|
353
|
+
# Return the stored attribute name
|
|
253
354
|
return self._attr
|
|
254
355
|
|
|
255
356
|
#* INDEXATION
|
|
@@ -259,11 +360,9 @@ class Pointer(Generic[PT]):
|
|
|
259
360
|
# Setter
|
|
260
361
|
def __setitem__(self,index,value):
|
|
261
362
|
self.value[index]=value
|
|
262
|
-
return
|
|
263
363
|
# Deleter
|
|
264
364
|
def __delitem__(self,index):
|
|
265
365
|
del self.value[index]
|
|
266
|
-
return
|
|
267
366
|
|
|
268
367
|
#* ARITHMETIC OPERATIONS
|
|
269
368
|
# Addition
|
|
@@ -35,10 +35,14 @@ def pointerize(func):
|
|
|
35
35
|
func : `FunctionType`
|
|
36
36
|
Decorated function.
|
|
37
37
|
"""
|
|
38
|
+
#* IDENTITY MANAGEMENT
|
|
38
39
|
# Makes the decorating function to keep its identity
|
|
39
40
|
@wraps(func)
|
|
41
|
+
|
|
42
|
+
#* WRAPPER
|
|
40
43
|
# Define the wrapper
|
|
41
44
|
def wrapper(*args,**kwargs):
|
|
45
|
+
#* SIGNATURE
|
|
42
46
|
# Obtain the signature (parameters and defaults) of the decorated function
|
|
43
47
|
sig=signature(func)
|
|
44
48
|
# Bind call arguments to the signature
|
|
@@ -46,6 +50,7 @@ def pointerize(func):
|
|
|
46
50
|
# Defaults all the arguments which haven't been passed
|
|
47
51
|
bound.apply_defaults()
|
|
48
52
|
|
|
53
|
+
#* ARGUMENTS' MAPPING
|
|
49
54
|
# Dictionary containing all the parameters
|
|
50
55
|
param_map=bound.arguments
|
|
51
56
|
|
|
@@ -55,6 +60,7 @@ def pointerize(func):
|
|
|
55
60
|
if isinstance(val,Pointer)
|
|
56
61
|
}
|
|
57
62
|
|
|
63
|
+
#* EXECUTION ARGUMENTS
|
|
58
64
|
# List containing all the positional arguments to be passed to the decorated function
|
|
59
65
|
exec_args=[
|
|
60
66
|
val.value if isinstance(val,Pointer) else val
|
|
@@ -66,7 +72,8 @@ def pointerize(func):
|
|
|
66
72
|
for k,v in bound.kwargs.items()
|
|
67
73
|
}
|
|
68
74
|
|
|
69
|
-
|
|
75
|
+
#* TRACKING
|
|
76
|
+
# Empty dictionary, future source to update pointers' values
|
|
70
77
|
frame_data={}
|
|
71
78
|
|
|
72
79
|
# Tracer function compatible with the sys.settrace API
|
|
@@ -74,10 +81,12 @@ def pointerize(func):
|
|
|
74
81
|
if event=="return" and frame.f_code is func.__code__:
|
|
75
82
|
frame_data.update(frame.f_locals)
|
|
76
83
|
return tracer
|
|
84
|
+
|
|
77
85
|
# Activate tracing
|
|
78
86
|
settrace(tracer)
|
|
79
|
-
#
|
|
87
|
+
# Try to execute the function
|
|
80
88
|
try:
|
|
89
|
+
# Storing its result
|
|
81
90
|
result=func(*exec_args,**exec_kwargs)
|
|
82
91
|
# Even if the program meets an error
|
|
83
92
|
finally:
|
|
@@ -85,13 +94,16 @@ def pointerize(func):
|
|
|
85
94
|
settrace(None)
|
|
86
95
|
# If no exception or error is raised, the program continues from here
|
|
87
96
|
|
|
97
|
+
#* POINTERS' UPDATING
|
|
88
98
|
# Iterates through the pointers
|
|
89
99
|
for name,ptr in pointer_map.items():
|
|
90
|
-
#
|
|
100
|
+
# Check if the parameter name is in the traced frame (of local variables of the decorated function)
|
|
91
101
|
if name in frame_data:
|
|
92
102
|
# In which case, the pointer's value is updated
|
|
93
103
|
ptr.value=frame_data[name]
|
|
104
|
+
#* RETURNS
|
|
94
105
|
# Return the result of the decorated function
|
|
95
106
|
return result
|
|
107
|
+
#* RETURNS
|
|
96
108
|
# Return the wrapper
|
|
97
109
|
return wrapper
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: memorymanagement
|
|
3
|
-
Version: 1.4.
|
|
3
|
+
Version: 1.4.2
|
|
4
4
|
Summary: Adds support for memory management
|
|
5
5
|
Home-page: https://github.com/Ricardo-Werner-Rivas/memorymanagement/tree/PyPI
|
|
6
6
|
Author: Ricardo Werner Rivas
|
|
@@ -104,6 +104,18 @@ cleaner.exclude(<name_var_1>,<name_var_2>,...)
|
|
|
104
104
|
```py
|
|
105
105
|
cleaner.include(<name_var_1>,<name_var_2>,...)
|
|
106
106
|
```
|
|
107
|
+
To flag all the excluded variables at once, you can use:
|
|
108
|
+
```py
|
|
109
|
+
cleaner.include_all(exclude=[<var_1>,<var_2>,...]) # exclude: optional keyword argument, accepts strings and iterables of strings
|
|
110
|
+
```
|
|
111
|
+
You can also exclude all the flagged variables like so:
|
|
112
|
+
```py
|
|
113
|
+
cleaner.exclude_all(include=[<var_1>,<var_2>,...]) # include: optional keyword argument, accepts strings and iterables of strings
|
|
114
|
+
```
|
|
115
|
+
And reset the cleaner's parameters like so:
|
|
116
|
+
```py
|
|
117
|
+
cleaner.purge()
|
|
118
|
+
```
|
|
107
119
|
### Class `Pointer`
|
|
108
120
|
Example:
|
|
109
121
|
```py
|
|
File without changes
|
|
File without changes
|
{memorymanagement-1.4.0 → memorymanagement-1.4.2}/memorymanagement.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|