diff options
Diffstat (limited to 'oslo_context')
-rw-r--r-- | oslo_context/context.py | 184 | ||||
-rw-r--r-- | oslo_context/fixture.py | 4 | ||||
-rw-r--r-- | oslo_context/version.py | 1 |
3 files changed, 97 insertions, 92 deletions
diff --git a/oslo_context/context.py b/oslo_context/context.py index 34e1e0c..148817e 100644 --- a/oslo_context/context.py +++ b/oslo_context/context.py @@ -30,6 +30,7 @@ import collections.abc import functools import itertools import threading +import typing as ty import uuid import warnings @@ -41,27 +42,21 @@ _request_store = threading.local() # These arguments will be passed to a new context from the first available # header to support backwards compatibility. -_ENVIRON_HEADERS = { - 'auth_token': ['HTTP_X_AUTH_TOKEN', - 'HTTP_X_STORAGE_TOKEN'], - 'user_id': ['HTTP_X_USER_ID', - 'HTTP_X_USER'], - 'project_id': ['HTTP_X_PROJECT_ID', - 'HTTP_X_TENANT_ID', - 'HTTP_X_TENANT'], +_ENVIRON_HEADERS: ty.Dict[str, ty.List[str]] = { + 'auth_token': ['HTTP_X_AUTH_TOKEN', 'HTTP_X_STORAGE_TOKEN'], + 'user_id': ['HTTP_X_USER_ID', 'HTTP_X_USER'], + 'project_id': ['HTTP_X_PROJECT_ID', 'HTTP_X_TENANT_ID', 'HTTP_X_TENANT'], 'domain_id': ['HTTP_X_DOMAIN_ID'], 'system_scope': ['HTTP_OPENSTACK_SYSTEM_SCOPE'], 'user_domain_id': ['HTTP_X_USER_DOMAIN_ID'], 'project_domain_id': ['HTTP_X_PROJECT_DOMAIN_ID'], 'user_name': ['HTTP_X_USER_NAME'], - 'project_name': ['HTTP_X_PROJECT_NAME', - 'HTTP_X_TENANT_NAME'], + 'project_name': ['HTTP_X_PROJECT_NAME', 'HTTP_X_TENANT_NAME'], 'user_domain_name': ['HTTP_X_USER_DOMAIN_NAME'], 'project_domain_name': ['HTTP_X_PROJECT_DOMAIN_NAME'], 'request_id': ['openstack.request_id'], 'global_request_id': ['openstack.global_request_id'], - 'service_token': ['HTTP_X_SERVICE_TOKEN'], 'service_user_id': ['HTTP_X_SERVICE_USER_ID'], 'service_user_name': ['HTTP_X_SERVICE_USER_NAME'], @@ -74,7 +69,7 @@ _ENVIRON_HEADERS = { } -def generate_request_id(): +def generate_request_id() -> str: """Generate a unique request id.""" return 'req-%s' % uuid.uuid4() @@ -87,11 +82,11 @@ class _DeprecatedPolicyValues(collections.abc.MutableMapping): these values as oslo.policy will do will trigger a DeprecationWarning. """ - def __init__(self, data): + def __init__(self, data: ty.Dict[str, ty.Any]): self._data = data - self._deprecated = {} + self._deprecated: ty.Dict[str, ty.Any] = {} - def __getitem__(self, k): + def __getitem__(self, k: str) -> ty.Any: try: return self._data[k] except KeyError: @@ -110,32 +105,33 @@ class _DeprecatedPolicyValues(collections.abc.MutableMapping): raise KeyError(k) - def __setitem__(self, k, v): + def __setitem__(self, k: str, v: ty.Any) -> None: self._deprecated[k] = v - def __delitem__(self, k): + def __delitem__(self, k: str) -> None: del self._deprecated[k] - def __iter__(self): + def __iter__(self) -> ty.Iterator[ty.Any]: return iter(self._dict) - def __len__(self): + def __len__(self) -> int: return len(self._dict) - def __str__(self): + def __str__(self) -> str: return self._dict.__str__() - def __repr__(self): + def __repr__(self) -> str: return self._dict.__repr__() @property - def _dict(self): + def _dict(self) -> ty.Dict[str, ty.Any]: d = self._deprecated.copy() d.update(self._data) return d -def _moved_msg(new_name, old_name): +# TODO(stephenfin): Remove this in the 4.0 release +def _moved_msg(new_name: str, old_name: ty.Optional[str]) -> None: if old_name: deprecated_msg = "Property '%(old_name)s' has moved to '%(new_name)s'" deprecated_msg = deprecated_msg % {'old_name': old_name, @@ -147,22 +143,23 @@ def _moved_msg(new_name, old_name): stacklevel=5) -def _moved_property(new_name, old_name=None, target=None): - - if not target: - target = new_name +def _moved_property( + new_name: str, + old_name: ty.Optional[str] = None, + target: ty.Optional[str] = None, +) -> ty.Any: - def getter(self): + def getter(self: ty.Any) -> ty.Any: _moved_msg(new_name, old_name) - return getattr(self, target) + return getattr(self, target or new_name) - def setter(self, value): + def setter(self: ty.Any, value: str) -> None: _moved_msg(new_name, old_name) - setattr(self, target, value) + setattr(self, target or new_name, value) - def deleter(self): + def deleter(self: ty.Any) -> None: _moved_msg(new_name, old_name) - delattr(self, target) + delattr(self, target or new_name) return property(getter, setter, deleter) @@ -181,47 +178,49 @@ class RequestContext(object): accesses the system, as well as additional request information. """ - user_idt_format = u'{user} {project_id} {domain} {user_domain} {p_domain}' + user_idt_format = '{user} {project_id} {domain} {user_domain} {p_domain}' # Can be overridden in subclasses to specify extra keys that should be # read when constructing a context using from_dict. - FROM_DICT_EXTRA_KEYS = [] + FROM_DICT_EXTRA_KEYS: ty.List[str] = [] @_renamed_kwarg('user', 'user_id') @_renamed_kwarg('domain', 'domain_id') @_renamed_kwarg('user_domain', 'user_domain_id') @_renamed_kwarg('project_domain', 'project_domain_id') - def __init__(self, - auth_token=None, - user_id=None, - project_id=None, - domain_id=None, - user_domain_id=None, - project_domain_id=None, - is_admin=False, - read_only=False, - show_deleted=False, - request_id=None, - resource_uuid=None, - overwrite=True, - roles=None, - user_name=None, - project_name=None, - domain_name=None, - user_domain_name=None, - project_domain_name=None, - is_admin_project=True, - service_token=None, - service_user_id=None, - service_user_name=None, - service_user_domain_id=None, - service_user_domain_name=None, - service_project_id=None, - service_project_name=None, - service_project_domain_id=None, - service_project_domain_name=None, - service_roles=None, - global_request_id=None, - system_scope=None): + def __init__( + self, + auth_token: ty.Optional[str] = None, + user_id: ty.Optional[str] = None, + project_id: ty.Optional[str] = None, + domain_id: ty.Optional[str] = None, + user_domain_id: ty.Optional[str] = None, + project_domain_id: ty.Optional[str] = None, + is_admin: bool = False, + read_only: bool = False, + show_deleted: bool = False, + request_id: ty.Optional[str] = None, + resource_uuid: ty.Optional[str] = None, + overwrite: bool = True, + roles: ty.Optional[ty.List[str]] = None, + user_name: ty.Optional[str] = None, + project_name: ty.Optional[str] = None, + domain_name: ty.Optional[str] = None, + user_domain_name: ty.Optional[str] = None, + project_domain_name: ty.Optional[str] = None, + is_admin_project: bool = True, + service_token: ty.Optional[str] = None, + service_user_id: ty.Optional[str] = None, + service_user_name: ty.Optional[str] = None, + service_user_domain_id: ty.Optional[str] = None, + service_user_domain_name: ty.Optional[str] = None, + service_project_id: ty.Optional[str] = None, + service_project_name: ty.Optional[str] = None, + service_project_domain_id: ty.Optional[str] = None, + service_project_domain_name: ty.Optional[str] = None, + service_roles: ty.Optional[ty.List[str]] = None, + global_request_id: ty.Optional[str] = None, + system_scope: ty.Optional[str] = None, + ): """Initialize the RequestContext :param overwrite: Set to False to ensure that the greenthread local @@ -280,12 +279,10 @@ class RequestContext(object): # to the same private variable rather than each other. user = _moved_property('user_id', 'user', target='_user_id') domain = _moved_property('domain_id', 'domain', target='_domain_id') - user_domain = _moved_property('user_domain_id', - 'user_domain', - target='_user_domain_id') - project_domain = _moved_property('project_domain_id', - 'project_domain', - target='_project_domain_id') + user_domain = _moved_property( + 'user_domain_id', 'user_domain', target='_user_domain_id') + project_domain = _moved_property( + 'project_domain_id', 'project_domain', target='_project_domain_id') user_id = _moved_property('_user_id') project_id = _moved_property('_project_id') @@ -293,11 +290,11 @@ class RequestContext(object): user_domain_id = _moved_property('_user_domain_id') project_domain_id = _moved_property('_project_domain_id') - def update_store(self): + def update_store(self) -> None: """Store the context in the current thread.""" _request_store.context = self - def to_policy_values(self): + def to_policy_values(self) -> _DeprecatedPolicyValues: """A dictionary of context attributes to enforce policy with. oslo.policy enforcement requires a dictionary of attributes @@ -326,16 +323,18 @@ class RequestContext(object): 'service_user_domain_id': self.service_user_domain_id, 'service_project_id': self.service_project_id, 'service_project_domain_id': self.service_project_domain_id, - 'service_roles': self.service_roles}) + 'service_roles': self.service_roles, + }) - def to_dict(self): + def to_dict(self) -> ty.Dict[str, ty.Any]: """Return a dictionary of context attributes.""" user_idt = self.user_idt_format.format( user=self.user_id or '-', project_id=self.project_id or '-', domain=self.domain_id or '-', user_domain=self.user_domain_id or '-', - p_domain=self.project_domain_id or '-') + p_domain=self.project_domain_id or '-', + ) return {'user': self.user_id, 'project_id': self.project_id, @@ -355,7 +354,7 @@ class RequestContext(object): 'user_identity': user_idt, 'is_admin_project': self.is_admin_project} - def get_logging_values(self): + def get_logging_values(self) -> ty.Dict[str, ty.Any]: """Return a dictionary of logging specific context attributes.""" values = {'user_name': self.user_name, 'project_name': self.project_name, @@ -379,7 +378,7 @@ class RequestContext(object): return values @property - def global_id(self): + def global_id(self) -> str: """Return a sensible value for global_id to pass on. When we want to make a call with to another service, it's @@ -393,7 +392,9 @@ class RequestContext(object): @_renamed_kwarg('domain', 'domain_id') @_renamed_kwarg('user_domain', 'user_domain_id') @_renamed_kwarg('project_domain', 'project_domain_id') - def from_dict(cls, values, **kwargs): + def from_dict( + cls, values: ty.Dict[str, ty.Any], **kwargs: ty.Any, + ) -> 'RequestContext': """Construct a context object from a provided dictionary.""" kwargs.setdefault('auth_token', values.get('auth_token')) kwargs.setdefault('user_id', values.get('user')) @@ -426,7 +427,9 @@ class RequestContext(object): @_renamed_kwarg('domain', 'domain_id') @_renamed_kwarg('user_domain', 'user_domain_id') @_renamed_kwarg('project_domain', 'project_domain_id') - def from_environ(cls, environ, **kwargs): + def from_environ( + cls, environ: ty.Dict[str, ty.Any], **kwargs: ty.Any, + ) -> 'RequestContext': """Load a context object from a request environment. If keyword arguments are provided then they override the values in the @@ -469,7 +472,7 @@ class RequestContext(object): return cls(**kwargs) -def get_admin_context(show_deleted=False): +def get_admin_context(show_deleted: bool = False) -> RequestContext: """Create an administrator context.""" context = RequestContext(None, project_id=None, @@ -479,13 +482,16 @@ def get_admin_context(show_deleted=False): return context -def get_context_from_function_and_args(function, args, kwargs): +def get_context_from_function_and_args( + function: ty.Callable, + args: ty.List[ty.Any], + kwargs: ty.Dict[str, ty.Any], +) -> ty.Optional[RequestContext]: """Find an arg of type RequestContext and return it. - This is useful in a couple of decorators where we don't - know much about the function we're wrapping. + This is useful in a couple of decorators where we don't know much about the + function we're wrapping. """ - for arg in itertools.chain(kwargs.values(), args): if isinstance(arg, RequestContext): return arg @@ -493,7 +499,7 @@ def get_context_from_function_and_args(function, args, kwargs): return None -def is_user_context(context): +def is_user_context(context: RequestContext) -> bool: """Indicates if the request context is a normal user.""" if not context or not isinstance(context, RequestContext): return False @@ -502,7 +508,7 @@ def is_user_context(context): return True -def get_current(): +def get_current() -> ty.Optional[RequestContext]: """Return this thread's current context If no context is set, returns None diff --git a/oslo_context/fixture.py b/oslo_context/fixture.py index a7bb0ff..715f43a 100644 --- a/oslo_context/fixture.py +++ b/oslo_context/fixture.py @@ -24,7 +24,7 @@ class ClearRequestContext(fixtures.Fixture): run later in the same process. """ - def setUp(self): + def setUp(self) -> None: super(ClearRequestContext, self).setUp() # we need to clear both when we start, and when we finish, # because there might be other tests running that don't handle @@ -32,7 +32,7 @@ class ClearRequestContext(fixtures.Fixture): self._remove_cached_context() self.addCleanup(self._remove_cached_context) - def _remove_cached_context(self): + def _remove_cached_context(self) -> None: """Remove the thread-local context stored in the module.""" try: del context._request_store.context diff --git a/oslo_context/version.py b/oslo_context/version.py index 19e4fb1..e9810b7 100644 --- a/oslo_context/version.py +++ b/oslo_context/version.py @@ -12,7 +12,6 @@ # License for the specific language governing permissions and limitations # under the License. - import pbr.version version_info = pbr.version.VersionInfo('oslo.context') |