Skip to content

Commit

Permalink
Merge pull request #124 from KE-works/#100-siblings-of-activity
Browse files Browse the repository at this point in the history
#100 added subprocess(), siblings() and children() methods to activity
  • Loading branch information
jberends authored Jun 5, 2017
2 parents 793bed8 + ed6755c commit 0a0bca0
Show file tree
Hide file tree
Showing 26 changed files with 356 additions and 33 deletions.
14 changes: 14 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,20 @@ Change Log

pykechain changelog

1.8.0 (UNRELEASED)
------------------
* Added `Activity.subprocess()`, `Activity.siblings()` and `Activity.children()` methods to the `Activity`. It eases
relative retrieval of other tasks in the task tree. Documentation is included.
* added `Activity.activity_type` property to the Activity.
* added `ActivityType` enumaration. This can be used to check if the `activity_type` of an `Activity` is either a
Usertask or a Subprocess.
* Added ability to retrieve an `Activity` based on an id. As this included in the low level `Client` object, it can
be used almost everywhere to retrieve an activity by its id (or primary key, pk) eg. in the `Scope.activity`.
* Added ability to add additional keyword to the activities searcher
* Added a FutureDeprecationWarning to the `Activity.create_activity()` method. This will is replace with the
`Activity.create()` method. Update your code please!
* added tests for all new features.
* Updated the documentation.

* Added a convenience method to retrieve models and instances related to a task at once: `Activity.associated_parts()`.
Making use of the already provided method in `Activity.parts()`. (#118)
Expand Down
30 changes: 18 additions & 12 deletions pykechain/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ def login(self, username=None, password=None, token=None):
>>> client = Client()
>>> client.login('username','password')
"""
if token:
self.headers['Authorization'] = 'Token {}'.format(token)
Expand Down Expand Up @@ -206,22 +206,28 @@ def scope(self, *args, **kwargs):

return _scopes[0]

def activities(self, name=None, scope=None):
# type: (Optional[str], Optional[str]) -> List[Activity]
def activities(self, name=None, pk=None, scope=None, **kwargs):
# type: (Optional[str], Optional[str], Optional[str], **Any) -> List[Activity]
"""Search on activities with optional name filter.
:param pk: id (primary key) of the activity to retrieve
:param name: filter the activities by name
:param scope: filter by scope id
:return: :obj:`list` of :obj:`Activity`
:raises: NotFoundError
"""
r = self._request('GET', self._build_url('activities'), params={
request_params = {
'id': pk,
'name': name,
'scope': scope
})
}
if kwargs:
request_params.update(**kwargs)

r = self._request('GET', self._build_url('activities'), params=request_params)

if r.status_code != requests.codes.ok: # pragma: no cover
raise NotFoundError("Could not retrieve activities")
raise NotFoundError("Could not retrieve activities. Server responded with {}".format(str(r)))

data = r.json()

Expand Down Expand Up @@ -275,22 +281,22 @@ def parts(self,
Examples
--------
Return all parts (defaults to instances) with exact name 'Gears'.
>>> client = Client(url='https://default.localhost:9443', verify=False)
>>> client.login('admin','pass')
>>> client.parts(name='Gears') # doctest:Ellipsis
...
Return all parts with category is MODEL or category is INSTANCE.
>>> client.parts(name='Gears', category=None) # doctest:Ellipsis
...
Return a maximum of 5 parts
>>> client.parts(limit=5) # doctest:Ellipsis
...
"""
# if limit is provided and the batchsize is bigger than the limit, ensure that the batch size is maximised
if limit and limit < batch:
Expand Down Expand Up @@ -470,8 +476,8 @@ def create_proxy_model(self, model, parent, name, multiplicity='ZERO_MANY'):
whole subassembly to the 'parent' model.
:param name: Name of the new proxy model
:param parent: parent of the
:param multiplicity: the multiplicity of the new proxy model (default ONE_MANY)
:param parent: parent of the
:param multiplicity: the multiplicity of the new proxy model (default ONE_MANY)
:return: the new proxy model part
"""
assert model.category == Category.MODEL, "The model should be of category MODEL"
Expand Down
8 changes: 8 additions & 0 deletions pykechain/enums.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,3 +50,11 @@ class PropertyType(Enum):
BOOLEAN_VALUE = "BOOLEAN_VALUE"
CHAR_VALUE = "CHAR_VALUE"
ATTACHMENT_VALUE = "ATTACHMENT_VALUE"


class ActivityType(Enum):
"""The various Acitivity types that are accepted by KE-chain."""

USERTASK = "UserTask"
SERVICETASK = "ServiceTask" # RND code only
SUBPROCESS = "Subprocess"
76 changes: 72 additions & 4 deletions pykechain/models/activity.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
from six import text_type
from typing import Any # flake8: noqa

from pykechain.enums import Category
from pykechain.enums import Category, ActivityType
from pykechain.exceptions import APIError, NotFoundError
from pykechain.models.base import Base

Expand All @@ -21,6 +21,8 @@ def __init__(self, json, **kwargs):
super(Activity, self).__init__(json, **kwargs)

self.scope = json.get('scope')
self.activity_type = json.get('activity_class', None)
self.status = json.get('status', None)

def parts(self, *args, **kwargs):
"""Retrieve parts belonging to this activity.
Expand Down Expand Up @@ -86,13 +88,81 @@ def delete(self):
if r.status_code != 204:
raise APIError("Could not delete activity: {} with id {}".format(self.name, self.id))

def create_activity(self, *args, **kwargs):
def subprocess(self):
"""Retrieve the subprocess in which this activity is defined.
If this is a task on top level, it raises NotFounderror
:return: subprocess `Activity`
:raises: NotFoundError when it is a task in the top level of a project
Example
-------
>>> task = project.activity('Subtask')
>>> subprocess = task.subprocess()
"""
subprocess_id = self._json_data.get('container')
if subprocess_id == self._json_data.get('root_container'):
raise NotFoundError("Cannot find subprocess for this task '{}', "
"as this task exist on top level.".format(self.name))
return self._client.activity(pk=subprocess_id, scope=self._json_data['scope']['id'])

def children(self):
"""Retrieve the direct activities of this subprocess.
It returns a combination of Tasks (a.o. UserTasks) and Subprocesses on the direct descending level.
Only when the activity is a Subprocess, otherwise it raises a NotFoundError
:return: list of activities
:raises: NotFoundError when this task is not of type `ActivityType.SUBPROCESS`
Example
-------
>>> subprocess = project.subprocess('Subprocess')
>>> children = subprocess.children()
"""
if self.activity_type != ActivityType.SUBPROCESS:
raise NotFoundError("Only subprocesses can have children, please choose a subprocess instead of a '{}' "
"(activity '{}')".format(self.activity_type, self.name))

return self._client.activities(container=self.id, scope=self._json_data['scope']['id'])

def siblings(self):
"""Retrieve the other activities that also belong to the subprocess.
It returns a combination of Tasks (a.o. UserTasks) and Subprocesses on the level of the current task.
This also works if the activity is of type `ActivityType.SUBPROCESS`.
:return: list of activities
Example
-------
>>> task = project.activity('Some Task')
>>> siblings = task.siblings()
"""
container_id = self._json_data.get('container')
return self._client.activities(container=container_id, scope=self._json_data['scope']['id'])

def create(self, *args, **kwargs):
"""Create a new activity belonging to this subprocess.
See :class:`pykechain.Client.create_activity` for available parameters.
"""
assert self.activity_type == ActivityType.SUBPROCESS, "One can only create a task under a subprocess."
return self._client.create_activity(self.id, *args, **kwargs)

def create_activity(self, *args, **kwargs):
"""See :method:`pykechain.Activity.create`. This method will be deprecated in version 1.9 onwards.
See :class:`pykechain.Client.create_activity` for available parameters.
"""
warnings.warn('This method will be deprecated in version 1.9 and replaced with `Activity.create()` '
'for consistency reasons.', PendingDeprecationWarning)
return self.create(*args, **kwargs)

def edit(self, name=None, description=None, start_date=None, due_date=None, assignee=None):
"""Edit the details of an activity.
Expand Down Expand Up @@ -187,7 +257,6 @@ def edit(self, name=None, description=None, start_date=None, due_date=None, assi
if start_date:
self._json_data['start_date'] = str(start_date)


def customize(self, config):
"""Customize an activity.
Expand Down Expand Up @@ -224,4 +293,3 @@ def customize(self, config):
activity=self.id,
config=json.dumps(config, indent=4))
)

Large diffs are not rendered by default.

Loading

0 comments on commit 0a0bca0

Please sign in to comment.