Skip to content

Commit

Permalink
Merge pull request #25 from taskbadger/sk/scope
Browse files Browse the repository at this point in the history
add concept of scope to store global task data
  • Loading branch information
snopoke authored Nov 1, 2023
2 parents a7f154b + 38b0ffe commit 2fef54e
Show file tree
Hide file tree
Showing 4 changed files with 94 additions and 3 deletions.
6 changes: 5 additions & 1 deletion taskbadger/__init__.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from .decorators import track
from .integrations import Action, EmailIntegration, WebhookIntegration
from .internal.models import StatusEnum
from .mug import Session
from .mug import Badger, Session
from .safe_sdk import create_task_safe, update_task_safe
from .sdk import DefaultMergeStrategy, Task, create_task, get_task, init, update_task

Expand All @@ -15,3 +15,7 @@
__version__ = importlib_metadata.version(__name__)
except importlib_metadata.PackageNotFoundError:
__version__ = "dev"


def current_scope():
return Badger.current.scope()
27 changes: 27 additions & 0 deletions taskbadger/mug.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,29 @@ def __exit__(self, *args, **kwargs):
self.client = None


class Scope:
"""Scope holds global data which will be added to every task created within the current scope.
Scope data will be merged with task data when creating a task where data provided directly to the task
will override scope data.
"""

def __init__(self):
self.stack = []
self.context = {}

def __enter__(self):
self.stack.append(self.context)
self.context = self.context.copy()
return self

def __exit__(self, *args):
self.context = self.stack.pop()

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


class MugMeta(type):
@property
def current(cls):
Expand All @@ -94,6 +117,7 @@ def __init__(self, settings_or_mug=None):
self.settings = settings_or_mug

self._session = ReentrantSession()
self._scope = Scope()

def bind(self, settings):
self.settings = settings
Expand All @@ -104,6 +128,9 @@ def session(self) -> ReentrantSession:
def client(self) -> AuthenticatedClient:
return self.settings.get_client()

def scope(self) -> Scope:
return self._scope

@classmethod
def is_configured(cls):
return cls.current.settings is not None
Expand Down
6 changes: 4 additions & 2 deletions taskbadger/sdk.py
Original file line number Diff line number Diff line change
Expand Up @@ -100,8 +100,10 @@ def create_task(
task = TaskRequest(
name=name, status=status, value=value, value_max=value_max, max_runtime=max_runtime, stale_timeout=stale_timeout
)
if data:
task.data = TaskRequestData.from_dict(data)
scope_data = Badger.current.scope().context
if scope_data or data:
data = data or {}
task.data = TaskRequestData.from_dict({**scope_data, **data})
if actions:
task.additional_properties = {"actions": [a.to_dict() for a in actions]}
kwargs = _make_args(json_body=task)
Expand Down
58 changes: 58 additions & 0 deletions tests/test_scope.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import random
import threading
import time

import pytest

from taskbadger import create_task, init
from taskbadger.mug import GLOBAL_MUG, Badger
from tests.test_sdk_primatives import _json_task_response, _verify_task


def test_scope_singleton():
assert Badger.current == GLOBAL_MUG
scope = Badger.current.scope()
assert scope.context == {}
assert scope.stack == []
assert scope == Badger.current.scope()


def test_scope_context():
scope = Badger.current.scope()
assert scope.context == {}
assert scope.stack == []
with scope:
assert scope.stack == [{}]
scope.context["foo"] = "bar"
with scope:
assert scope.stack == [{}, {"foo": "bar"}]
assert scope.context == {"foo": "bar"}
scope.context["bar"] = "bazz"
with scope:
assert scope.context == {"foo": "bar", "bar": "bazz"}
scope.context.clear()
assert scope.context == {"foo": "bar"}
assert scope.stack == [{}]
assert scope.context == {}
assert scope.stack == []


@pytest.fixture(autouse=True)
def init_skd():
init("org", "project", "token")


def test_create_task_with_scope(httpx_mock):
with Badger.current.scope() as scope:
scope["foo"] = "bar"
scope["bar"] = "bazz"
httpx_mock.add_response(
url="https://taskbadger.net/api/org/project/tasks/",
method="POST",
match_headers={"Authorization": "Bearer token"},
match_content=b'{"name": "name", "status": "pending", "data": {"foo": "bar", "bar": "buzzer"}}',
json=_json_task_response(),
status_code=201,
)
task = create_task("name", data={"bar": "buzzer"})
_verify_task(task)

0 comments on commit 2fef54e

Please sign in to comment.