Skip to content

Commit

Permalink
Merge pull request #90 from globality-corp/thread-safe-opaque
Browse files Browse the repository at this point in the history
Make opaque thread safe
  • Loading branch information
jamie-chang-globality committed May 25, 2023
2 parents 13bcbfd + d29bf06 commit c5fefd9
Show file tree
Hide file tree
Showing 5 changed files with 40 additions and 48 deletions.
2 changes: 1 addition & 1 deletion .bumpversion.cfg
@@ -1,5 +1,5 @@
[bumpversion]
current_version = 3.1.0
current_version = 3.2.0
commit = False
tag = False

Expand Down
29 changes: 15 additions & 14 deletions .circleci/config.yml
Expand Up @@ -212,7 +212,11 @@ jobs:
- attach_workspace:
at: ~/repo
- run:
name: Deploy # If package publishing enabled, always push RCs to JFrog
name: Override Version
command: |
sed -i -e "s/^\(version = \".*\)\"$/\1.dev${CIRCLE_BUILD_NUM}\"/" setup.py
- run:
name: Authenticate
command: |
echo "[distutils]" > ~/.pypirc
echo "index-servers =" >> ~/.pypirc
Expand All @@ -223,12 +227,9 @@ jobs:
echo "username:$JFROG_USERNAME" >> ~/.pypirc
echo "password:$JFROG_PASSWORD" >> ~/.pypirc
echo >> ~/.pypirc
echo >> ~/.pypirc
version=0.${CIRCLE_BUILD_NUM}.dev${CIRCLE_BUILD_NUM}
sed -i '/version \=/s/\".*\"/'"\"${version}\"/" setup.py
python setup.py register -r jfrog
python setup.py sdist
twine upload --repository jfrog dist/microcosm-${version}.tar.gz
- run:
name: Publish
command: python setup.py sdist upload -r jfrog

publish_library:
<<: *defaults
Expand Down Expand Up @@ -259,14 +260,14 @@ workflows:
build-and-release:
jobs:
- checkout:
context:
context:
- Globality-Common
filters:
# run for all branches and tags
tags:
only: /.*/
- build_docker:
context:
context:
- Globality-Common
requires:
- checkout
Expand All @@ -275,7 +276,7 @@ workflows:
tags:
only: /.*/
- lint:
context:
context:
- Globality-Common
requires:
- build_docker
Expand All @@ -284,7 +285,7 @@ workflows:
tags:
only: /.*/
- test:
context:
context:
- Globality-Common
requires:
- build_docker
Expand All @@ -293,14 +294,14 @@ workflows:
tags:
only: /.*/
- deploy_jfrog_rc:
context:
context:
- Globality-Common
requires:
- test
- lint
- typehinting
- typehinting:
context:
context:
- Globality-Common
requires:
- build_docker
Expand All @@ -309,7 +310,7 @@ workflows:
tags:
only: /.*/
- publish_library:
context:
context:
- Globality-Common
- Python-Context
requires:
Expand Down
2 changes: 1 addition & 1 deletion Dockerfile
Expand Up @@ -12,7 +12,7 @@
#

# ----------- deps -----------
FROM python:3.7-stretch as deps
FROM python:3.7-slim-bullseye as deps

#
# Most services will use the same set of packages here, though a few will install
Expand Down
53 changes: 22 additions & 31 deletions microcosm/opaque.py
Expand Up @@ -19,33 +19,23 @@
"""
from collections.abc import MutableMapping
from contextlib import ContextDecorator, ExitStack
from contextlib import contextmanager
from contextvars import ContextVar
from copy import deepcopy
from types import MethodType
from typing import Optional


def _make_initializer(opaque):
@contextmanager
def initialiser(func, *args, **kwargs):
token = opaque._store.set(deepcopy(opaque._store.get()))
opaque.update(func(*args, **kwargs))
try:
yield
finally:
opaque._store.reset(token)

class OpaqueInitializer(ContextDecorator, ExitStack):
def __init__(self, func, *args, **kwargs):
super().__init__()

def member_func(self):
return func(*args, **kwargs)

self.func = MethodType(member_func, self)
self.saved = None

def __enter__(self):
self.saved = deepcopy(opaque._store)
opaque.update(self.func())

def __exit__(self, *exc):
opaque._store = self.saved
self.saved = None
super().__exit__(*exc)

return OpaqueInitializer
return initialiser


class Opaque(MutableMapping):
Expand All @@ -70,28 +60,29 @@ def foo():
See tests for usage examples.
"""
def __init__(self, *args, **kwargs):
self.service_name = kwargs.pop("name", None)
self._store = dict(*args, **kwargs)

def __init__(self, *args, **kwargs) -> None:
self.service_name: Optional[str] = kwargs.pop("name", None)
self._store = ContextVar("store", default=dict(*args, **kwargs))
self.initialize = _make_initializer(self)

def __getitem__(self, key):
return self._store[key]
return self._store.get()[key]

def __setitem__(self, key, value):
self._store[key] = value
self._store.get()[key] = value

def __delitem__(self, key):
del self._store[key]
del self._store.get()[key]

def __iter__(self):
return iter(self._store)
return iter(self._store.get())

def __len__(self):
return len(self._store)
return len(self._store.get())

def as_dict(self):
return self._store
return self._store.get()


def configure_opaque(graph):
Expand Down
2 changes: 1 addition & 1 deletion setup.py
Expand Up @@ -3,7 +3,7 @@


project = "microcosm"
version = "3.1.0"
version = "3.2.0"

setup(
name=project,
Expand Down

0 comments on commit c5fefd9

Please sign in to comment.