memorymanagement 1.4.1__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.1 → memorymanagement-1.4.2}/PKG-INFO +1 -1
- {memorymanagement-1.4.1 → memorymanagement-1.4.2}/memorymanagement/__init__.py +0 -1
- {memorymanagement-1.4.1 → memorymanagement-1.4.2}/memorymanagement/cleaning/__init__.py +26 -2
- {memorymanagement-1.4.1 → memorymanagement-1.4.2}/memorymanagement/cleaning/core.py +63 -2
- {memorymanagement-1.4.1 → memorymanagement-1.4.2}/memorymanagement/pointers/__init__.py +0 -1
- {memorymanagement-1.4.1 → memorymanagement-1.4.2}/memorymanagement/pointers/core.py +117 -18
- {memorymanagement-1.4.1 → memorymanagement-1.4.2}/memorymanagement/pointers/decorators.py +15 -3
- {memorymanagement-1.4.1 → memorymanagement-1.4.2}/memorymanagement.egg-info/PKG-INFO +1 -1
- {memorymanagement-1.4.1 → memorymanagement-1.4.2}/setup.cfg +1 -1
- {memorymanagement-1.4.1 → memorymanagement-1.4.2}/LICENSE +0 -0
- {memorymanagement-1.4.1 → memorymanagement-1.4.2}/README.md +0 -0
- {memorymanagement-1.4.1 → memorymanagement-1.4.2}/memorymanagement.egg-info/SOURCES.txt +0 -0
- {memorymanagement-1.4.1 → memorymanagement-1.4.2}/memorymanagement.egg-info/dependency_links.txt +0 -0
- {memorymanagement-1.4.1 → memorymanagement-1.4.2}/memorymanagement.egg-info/top_level.txt +0 -0
- {memorymanagement-1.4.1 → memorymanagement-1.4.2}/pyproject.toml +0 -0
|
@@ -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,9 +157,12 @@ 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
|
|
|
@@ -156,13 +176,20 @@ class Cleaner:
|
|
|
156
176
|
exclude : `str`|`list[str]`|`tuple[str]`|`None`, Optional
|
|
157
177
|
Variables not to be included into the `flagged` list
|
|
158
178
|
"""
|
|
179
|
+
# Introduce excluded variables into the "flagged" list
|
|
159
180
|
self._flagged.extend(self.excluded)
|
|
181
|
+
# Clear the "excluded" list
|
|
160
182
|
self._excluded.clear()
|
|
161
183
|
|
|
184
|
+
# If the are exceptions
|
|
162
185
|
if exclude:
|
|
186
|
+
# If "exclude" content is a string
|
|
163
187
|
if isinstance(exclude,str):
|
|
188
|
+
# Exclude variable
|
|
164
189
|
self.exclude(exclude)
|
|
190
|
+
# Else
|
|
165
191
|
else:
|
|
192
|
+
# Exclude variables (unpacking)
|
|
166
193
|
self.exclude(*exclude)
|
|
167
194
|
|
|
168
195
|
# Exclude all flagged variables
|
|
@@ -175,13 +202,20 @@ class Cleaner:
|
|
|
175
202
|
include : `str`|`list[str]`|`tuple[str]`|`None`, Optional
|
|
176
203
|
Variables not to be excluded from the `flagged` list
|
|
177
204
|
"""
|
|
205
|
+
# Introduce excluded variables into the "excluded" list
|
|
178
206
|
self._excluded.extend(self.flagged)
|
|
207
|
+
# Clear the "flagged" list
|
|
179
208
|
self._flagged.clear()
|
|
180
209
|
|
|
210
|
+
# If there are exceptions
|
|
181
211
|
if include:
|
|
212
|
+
# If "include" content is a string
|
|
182
213
|
if isinstance(include,str):
|
|
214
|
+
# Include varianle
|
|
183
215
|
self.include(include)
|
|
216
|
+
# Else
|
|
184
217
|
else:
|
|
218
|
+
# Include variables (unpacking)
|
|
185
219
|
self.include(*include)
|
|
186
220
|
|
|
187
221
|
# Purge flagged and excluded variables
|
|
@@ -196,11 +230,17 @@ class Cleaner:
|
|
|
196
230
|
excluded : `bool`, Optional
|
|
197
231
|
Wether the `excluded` list should be purged (`True`) or not (`False`). `True` by default
|
|
198
232
|
"""
|
|
233
|
+
# If there is no list to be purged
|
|
199
234
|
if not flagged and not excluded:
|
|
235
|
+
# Pass
|
|
200
236
|
pass
|
|
237
|
+
# If "flagged" is set to be purged
|
|
201
238
|
if flagged:
|
|
239
|
+
# Clear "flagged"
|
|
202
240
|
self._flagged.clear()
|
|
241
|
+
# If "excluded" is set to be purged
|
|
203
242
|
if excluded:
|
|
243
|
+
# Clear "excluded"
|
|
204
244
|
self._excluded.clear()
|
|
205
245
|
|
|
206
246
|
# Clean
|
|
@@ -209,9 +249,13 @@ class Cleaner:
|
|
|
209
249
|
Culminates the cleaning process.
|
|
210
250
|
Erases all the flagged references.
|
|
211
251
|
"""
|
|
252
|
+
# Loop for "flagged" list
|
|
212
253
|
for var in self._flagged:
|
|
254
|
+
# If current variable name is between the global variables of "__main__"
|
|
213
255
|
if var in list(vars(modules["__main__"])):
|
|
256
|
+
# Delete variable
|
|
214
257
|
del vars(modules["__main__"])[var]
|
|
258
|
+
# Clear "flagged" list
|
|
215
259
|
self._flagged.clear()
|
|
216
260
|
|
|
217
261
|
#* PROPERTIES
|
|
@@ -219,18 +263,31 @@ class Cleaner:
|
|
|
219
263
|
@property
|
|
220
264
|
# Getter
|
|
221
265
|
def not_delete(self):
|
|
266
|
+
# If reference is not set or it doesn't point to the "Cleaner" object
|
|
222
267
|
if not self._name or vars(modules["__main__"])[self._name] is not self:
|
|
268
|
+
# Loop for variables dictionary
|
|
223
269
|
for key,value in vars(modules["__main__"]).items():
|
|
270
|
+
# If current value is the "Cleaner" object
|
|
224
271
|
if value is self:
|
|
272
|
+
# Store the reference
|
|
225
273
|
self._name=key
|
|
274
|
+
# Add it to the "not_delete" list
|
|
226
275
|
self._not_delete.append(self._name)
|
|
276
|
+
# Break
|
|
227
277
|
break
|
|
278
|
+
# Else
|
|
228
279
|
else:
|
|
280
|
+
# Reference is still empty
|
|
229
281
|
self._name=None
|
|
282
|
+
# If reference remains empty
|
|
230
283
|
if not self._name:
|
|
284
|
+
# Raise a "ReferenceError"
|
|
231
285
|
raise ReferenceError("\"Cleaner\" object is not referenced")
|
|
286
|
+
# Else, if reference is not in the "not_delete" list
|
|
232
287
|
elif self._name not in self._not_delete:
|
|
288
|
+
# Add reference to the "not_delete" list
|
|
233
289
|
self._not_delete.append(self._name)
|
|
290
|
+
# Return a shallow copy of the "not_delete" list
|
|
234
291
|
return self._not_delete.copy()
|
|
235
292
|
#^ No setter
|
|
236
293
|
#^ No deleter
|
|
@@ -239,6 +296,7 @@ class Cleaner:
|
|
|
239
296
|
@property
|
|
240
297
|
# Getter
|
|
241
298
|
def excluded(self):
|
|
299
|
+
# Return a shallow copy of the "excluded" list
|
|
242
300
|
return self._excluded.copy()
|
|
243
301
|
#^ No setter
|
|
244
302
|
#^ No deleter
|
|
@@ -247,6 +305,7 @@ class Cleaner:
|
|
|
247
305
|
@property
|
|
248
306
|
# Getter
|
|
249
307
|
def flagged(self):
|
|
308
|
+
# Return a shallow copy of the "flagged" list
|
|
250
309
|
return self._flagged.copy()
|
|
251
310
|
#^ No setter
|
|
252
311
|
#^ No deleter
|
|
@@ -254,6 +313,7 @@ class Cleaner:
|
|
|
254
313
|
#* SCREEN DUNDER METHODS
|
|
255
314
|
# __str__
|
|
256
315
|
def __str__(self):
|
|
316
|
+
# Return a string with the instance's components
|
|
257
317
|
return f"""
|
|
258
318
|
Flagged: {self.flagged}
|
|
259
319
|
|
|
@@ -264,4 +324,5 @@ class Cleaner:
|
|
|
264
324
|
|
|
265
325
|
# __repr__
|
|
266
326
|
def __repr__(self):
|
|
327
|
+
# Return a string able to rebuild the instance if needed
|
|
267
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{memorymanagement-1.4.1 → memorymanagement-1.4.2}/memorymanagement.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|