-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
added some docs + tests and refactored some code. Also removed Delaye…
…d class.
- Loading branch information
Matthew Chan
committed
Oct 26, 2017
1 parent
cdb2f94
commit 3db72d9
Showing
3 changed files
with
179 additions
and
64 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,111 @@ | ||
from functools import wraps | ||
|
||
|
||
# | ||
# Decorators | ||
# | ||
|
||
def onetime(varname: str): | ||
""" | ||
Prevents basic Python types from being changed after setting. | ||
Numpy arrays also need the read-only flag set on them. | ||
For use with Python setters, must be decorated before (closer to the function) @setter is | ||
called. | ||
Parameters | ||
---------- | ||
varname | ||
Name of the variable being tested. It does not need to be defined at interpretation | ||
time. | ||
Returns | ||
------- | ||
""" | ||
|
||
def decorator(func): | ||
@wraps(func) | ||
def wrapper(self, *args, **kwargs): | ||
if getattr(self, varname, None) is not None: | ||
print("Trying to set a one-time attribute {varname}. Ignored") | ||
return | ||
func(self, *args, **kwargs) | ||
|
||
return wrapper | ||
|
||
return decorator | ||
|
||
|
||
def cache(varname: str): | ||
""" | ||
Returns a variable if it is already defined. Otherwise, it calls the code in the property. | ||
Must be decorated before (closer to the function) @property. | ||
Parameters | ||
---------- | ||
varname | ||
Name of variable to cache. It does not need to be defined at interpretation. | ||
Returns | ||
------- | ||
""" | ||
|
||
def decorator(func): | ||
@wraps(func) | ||
def wrapper(self, *args, **kwargs): | ||
val = getattr(self, varname, None) | ||
if val is None: | ||
val = func(self, *args, **kwargs) | ||
setattr(self, varname, val) | ||
return val | ||
|
||
return wrapper | ||
|
||
return decorator | ||
|
||
|
||
def delayed(func): | ||
""" | ||
Safety check to make sure the instance has the second stage of instantiation. | ||
The function decorated will return AttributeError if the function with @finalize has not | ||
been called yet. | ||
Parameters | ||
---------- | ||
func | ||
Returns | ||
------- | ||
""" | ||
|
||
@wraps(func) | ||
def wrapper(self, *args, **kwargs): | ||
if not getattr(self, "init_finished", False): | ||
print("Instance must finalize instantiation before calling compute functions.") | ||
raise AttributeError | ||
return func(self, *args, **kwargs) | ||
|
||
return wrapper | ||
|
||
|
||
def finalize(func): | ||
""" | ||
When the function decorated completes, the instance will be marked as fully instantiated. | ||
Parameters | ||
---------- | ||
func | ||
Returns | ||
------- | ||
""" | ||
|
||
@wraps(func) | ||
def wrapper(self, *args, **kwargs): | ||
func(self, *args, **kwargs) | ||
self.init_finished = True | ||
|
||
return wrapper |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
from numpy.testing import assert_raises | ||
|
||
from decorators import onetime, cache, delayed, finalize | ||
|
||
|
||
def test_onetime(): | ||
class A: | ||
_x = 5 | ||
|
||
@property | ||
def x(self): | ||
return self._x | ||
|
||
@x.setter | ||
@onetime("_x") | ||
def x(self, y): | ||
self._x = y | ||
|
||
a = A() | ||
a.x = 10 | ||
assert a.x == 5 | ||
|
||
|
||
def test_cache(): | ||
class A: | ||
_x = 5 | ||
|
||
@property | ||
@cache("_x") | ||
def x(self): | ||
return 10 | ||
|
||
a = A() | ||
assert a.x == 5 | ||
|
||
|
||
def test_delayed_finalize(): | ||
class A: | ||
@finalize | ||
def finish(self): | ||
pass | ||
|
||
@delayed | ||
def do(self): | ||
pass | ||
|
||
a = A() | ||
with assert_raises(AttributeError): | ||
a.do() | ||
|
||
a.finish() | ||
a.do() |