-
Notifications
You must be signed in to change notification settings - Fork 22
add Context manager and default context under threading #38
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from 5 commits
6f06584
b0be767
cc95c56
d496980
345142f
f9083b7
113df5f
74a0da7
ac4f449
96a5af2
2ae695f
71da6cd
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -6,6 +6,11 @@ Reference: Basic Building Blocks | |
| Context | ||
| ------- | ||
|
|
||
| .. note:: this class implements Python's ``__copy__`` and ``__deepcopy__`` | ||
| protocals. Copying of objects of this class always returns the identity. | ||
|
|
||
| .. seealso:: :ref:`sec-context-management` | ||
|
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please add a note on
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done. @functools.lru_cache(maxsize=None)
def _get_context_by_id(ctx_id):
return Context()
def context_reduce(self):
if self == get_default_context():
return (get_default_context, ())
return (_get_context_by_id, (hash(self), ))What do you think? |
||
|
|
||
| .. autoclass:: Context() | ||
| :members: | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -20,6 +20,8 @@ | |
| THE SOFTWARE. | ||
| """ | ||
|
|
||
| import sys | ||
|
|
||
| import islpy._isl as _isl | ||
| from islpy.version import VERSION, VERSION_TEXT # noqa | ||
| import six | ||
|
|
@@ -145,14 +147,107 @@ | |
| EXPR_CLASSES = tuple(cls for cls in ALL_CLASSES | ||
| if "Aff" in cls.__name__ or "Polynomial" in cls.__name__) | ||
|
|
||
| DEFAULT_CONTEXT = Context() | ||
inducer marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| def _module_property(func): | ||
| """Decorator to turn module functions into properties. | ||
| Function names must be prefixed with an underscore.""" | ||
| module = sys.modules[func.__module__] | ||
|
|
||
| def base_getattr(name): | ||
| raise AttributeError( | ||
| f"module '{module.__name__}' has no attribute '{name}'") | ||
|
|
||
| old_getattr = getattr(module, "__getattr__", base_getattr) | ||
|
|
||
| def new_getattr(name): | ||
| if f"_{name}" == func.__name__: | ||
| return func() | ||
| else: | ||
| return old_getattr(name) | ||
|
|
||
| module.__getattr__ = new_getattr | ||
| return func | ||
|
|
||
|
|
||
| import threading | ||
|
|
||
|
|
||
| _thread_local_storage = threading.local() | ||
|
|
||
|
|
||
| def _check_init_default_context(): | ||
| if not hasattr(_thread_local_storage, "islpy_default_contexts"): | ||
| _thread_local_storage.islpy_default_contexts = [Context()] | ||
|
|
||
|
|
||
| def get_default_context(): | ||
inducer marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| """Get or create the default context under current thread. | ||
|
|
||
| :return: the current default :class:`Context` | ||
|
|
||
| .. versionadded:: TODO_VERSION | ||
thisiscam marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| """ | ||
| _check_init_default_context() | ||
| return _thread_local_storage.islpy_default_contexts[-1] | ||
|
|
||
|
|
||
| def _get_default_context(): | ||
| """A callable to get the default context for the benefit of Python's | ||
| ``__reduce__`` protocol. | ||
| from warnings import warn | ||
| warn("It appears that you might be deserializing an islpy.Context" | ||
| "that was serialized by a previous version of islpy." | ||
| "If so, this is discouraged and please consider to re-serialize" | ||
| "the Context with the newer version to avoid possible inconsistencies.", | ||
| UserWarning) | ||
| return get_default_context() | ||
|
|
||
|
|
||
| import contextlib | ||
|
||
|
|
||
|
|
||
| @contextlib.contextmanager | ||
| def push_context(ctx=None): | ||
| """Context manager to push new default :class:`Context` | ||
|
|
||
| :param ctx: an optional explicit context that is pushed to | ||
| the stack of default :class:`Context` s | ||
|
|
||
| .. versionadded:: TODO_VERSION | ||
thisiscam marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| :mod:`islpy` internally maintains a stack of default :class:`Context` s | ||
| for each Python thread. | ||
| By default, each stack is initialized with a base default :class:`Context`. | ||
| ISL objects being unpickled or initialized from strings will be | ||
| instantiated within the top :class:`Context` of the stack of | ||
| the executing thread. | ||
|
|
||
| Usage example:: | ||
|
|
||
| with islpy.push_context() as dctx: | ||
| s = islpy.Set("{[0]: }") | ||
| assert s.get_ctx() == dctx | ||
|
|
||
| """ | ||
| return DEFAULT_CONTEXT | ||
| if ctx is None: | ||
| ctx = Context() | ||
| _check_init_default_context() | ||
| _thread_local_storage.islpy_default_contexts.append(ctx) | ||
| yield ctx | ||
| _thread_local_storage.islpy_default_contexts.pop() | ||
|
|
||
|
|
||
| @_module_property | ||
| def _DEFAULT_CONTEXT(): # noqa: N802 | ||
| from warnings import warn | ||
| warn("Use of islpy.DEFAULT_CONTEXT is deprecated " | ||
| "and will be removed in 2022." | ||
| " Please use `islpy.get_default_context()` instead. ", | ||
| FutureWarning, | ||
| stacklevel=3) | ||
| return get_default_context() | ||
|
|
||
|
|
||
| if sys.version_info < (3, 7): | ||
| DEFAULT_CONTEXT = get_default_context() | ||
|
|
||
|
|
||
| def _read_from_str_wrapper(cls, context, s): | ||
|
|
@@ -168,10 +263,14 @@ def _add_functionality(): | |
| # {{{ Context | ||
|
|
||
| def context_reduce(self): | ||
| if self._wraps_same_instance_as(DEFAULT_CONTEXT): | ||
| return (_get_default_context, ()) | ||
| else: | ||
| return (Context, ()) | ||
| return (get_default_context, ()) | ||
inducer marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| def context_copy(self): | ||
| return self | ||
|
|
||
| def context_deepcopy(self, memo): | ||
| del memo | ||
| return self | ||
inducer marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| def context_eq(self, other): | ||
| return isinstance(other, Context) and self._wraps_same_instance_as(other) | ||
|
|
@@ -180,9 +279,10 @@ def context_ne(self, other): | |
| return not self.__eq__(other) | ||
|
|
||
| Context.__reduce__ = context_reduce | ||
| Context.__copy__ = context_copy | ||
| Context.__deepcopy__ = context_deepcopy | ||
| Context.__eq__ = context_eq | ||
| Context.__ne__ = context_ne | ||
|
|
||
| # }}} | ||
|
|
||
| # {{{ generic initialization, pickling | ||
|
|
@@ -197,7 +297,7 @@ def obj_new(cls, s=None, context=None): | |
| return cls._prev_new(cls) | ||
|
|
||
| if context is None: | ||
| context = DEFAULT_CONTEXT | ||
| context = get_default_context() | ||
|
|
||
| result = cls.read_from_str(context, s) | ||
| return result | ||
|
|
@@ -473,7 +573,7 @@ def obj_get_coefficients_by_name(self, dimtype=None, dim_to_name=None): | |
|
|
||
| def id_new(cls, name, user=None, context=None): | ||
| if context is None: | ||
| context = DEFAULT_CONTEXT | ||
| context = get_default_context() | ||
|
|
||
| result = cls.alloc(context, name, user) | ||
| result._made_from_python = True | ||
|
|
@@ -777,7 +877,7 @@ def expr_like_floordiv(self, other): | |
|
|
||
| def val_new(cls, src, context=None): | ||
| if context is None: | ||
| context = DEFAULT_CONTEXT | ||
| context = get_default_context() | ||
|
|
||
| if isinstance(src, six.string_types): | ||
| result = cls.read_from_str(context, src) | ||
|
|
@@ -1274,7 +1374,7 @@ def make_zero_and_vars(set_vars, params=[], ctx=None): | |
| ) | ||
| """ | ||
| if ctx is None: | ||
| ctx = DEFAULT_CONTEXT | ||
| ctx = get_default_context() | ||
|
|
||
| if isinstance(set_vars, str): | ||
| set_vars = [s.strip() for s in set_vars.split(",")] | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.