Skip to content
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

#100 added subprocess(), siblings() and children() methods to activity #124

Merged
merged 3 commits into from
Jun 5, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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