Beispiel #1
0
    def _update_scope_project_team(self, select_action, user, user_type):
        """
        Update the Project Team of the Scope. Updates include addition or removing of managers or members.

        :param select_action: type of action to be applied
        :param user: the username of the user to which the action applies to
        :param user_type: the type of the user (member or manager)
        """
        if isinstance(user, str):
            users = self._client._retrieve_users()
            manager_object = next(
                (item
                 for item in users['results'] if item["username"] == user),
                None)
            if manager_object:
                url = self._client._build_url('scope', scope_id=self.id)
                r = self._client._request(
                    'PUT',
                    url,
                    params={'select_action': select_action},
                    data={'user_id': manager_object['pk']})
                if r.status_code != requests.codes.ok:  # pragma: no cover
                    raise APIError("Could not {} {} in Scope".format(
                        select_action.split('_')[0], user_type))
            else:
                raise NotFoundError("User {} does not exist".format(user))
        else:
            raise TypeError(
                "User {} should be defined as a string".format(user))
Beispiel #2
0
    def property(self, name):
        # type: (str) -> Property
        """Retrieve the property with name belonging to this part.

        If you need to retrieve the property using eg. the id, use :meth:`pykechain.Client.properties`.

        :param name: property name to search for
        :return: a single :class:`pykechain.models.Property`
        :raises: NotFoundError

        Example
        -------

        >>> part = project.part('Bike')
        >>> part.properties
        [<pyke Property ...>, ...]
        # this returns a list of all properties of this part

        >>> gears = part.property('Gears')
        >>> gears.value
        6
        """
        found = find(self.properties, lambda p: name == p.name)

        if not found:
            raise NotFoundError(
                "Could not find property with name {}".format(name))

        return found
Beispiel #3
0
    def proxy_model(self):
        """
        Retrieve the proxy model of this proxied `Part` as a `Part`.

        Allows you to retrieve the model of a proxy. But trying to get the catalog model of a part that
        has no proxy, will raise an NotFoundError. Only models can have a proxy.

        :return: pykechain.models.Part
        :raises: NotFoundError

        Example
        -------

        >>> proxy_part = project.model('Proxy based on catalog model')
        >>> catalog_model_of_proxy_part = proxy_part.proxy_model()

        >>> proxied_material_of_the_bolt_model = project.model('Bolt Material')
        >>> proxy_basis_for_the_material_model = proxied_material_of_the_bolt_model.proxy_model()

        """
        if self.category != Category.MODEL:
            raise IllegalArgumentError(
                "Part {} is not a model, therefore it cannot have a proxy model"
                .format(self))
        if 'proxy' in self._json_data and self._json_data.get('proxy'):
            catalog_model_id = self._json_data['proxy'].get('id')
            return self._client.model(pk=catalog_model_id)
        else:
            raise NotFoundError("Part {} is not a proxy".format(self.name))
Beispiel #4
0
    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'])
Beispiel #5
0
    def model(self):
        """
        Retrieve the model of this `Part` as `Part`.

        For instance, you can get the part model of a part instance. But trying to get the model of a part that
        has no model, like a part model, will raise a NotFoundError.

        :return: pykechain.models.Part
        :raises: NotFoundError

        Example
        -------
        >>> front_fork = project.part('Front Fork')
        >>> front_fork_model = front_fork.model()

        """
        if self.category == Category.INSTANCE:
            model_id = self._json_data['model'].get('id')
            return self._client.model(pk=model_id)
        else:
            raise NotFoundError("Part {} has no model".format(self.name))
Beispiel #6
0
    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'])
Beispiel #7
0
    def instances(self):
        """
        Retrieve the instances of this `Part` as a `PartSet`.

        For instance, if you have a model part, you can get the list of instances that are created based on this
        moodel. If there are no instances (only possible if the multiplicity is `Multiplicity.ZERO_MANY` than a
        NotFoundError is returned

        :return: pykechain.models.PartSet
        :raises: NotFoundError

        Example
        -------
        >>> wheel_model = project.model('Wheel')
        >>> wheel_instance_set = wheel_model.instances()

        """
        if self.category == Category.MODEL:
            return self._client.parts(model=self, category=Category.INSTANCE)
        else:
            raise NotFoundError(
                "Part {} has no instances or is not a model".format(self.name))
Beispiel #8
0
    def edit(self,
             name=None,
             description=None,
             start_date=None,
             due_date=None,
             assignees=None,
             status=None):
        """Edit the details of an activity.

        :param name: (optionally) edit the name of the activity
        :param description: (optionally) edit the description of the activity
        :param start_date: (optionally) edit the start date of the activity as a datetime object (UTC time/timezone
                            aware preferred)
        :param due_date: (optionally) edit the due_date of the activity as a datetime object (UTC time/timzeone
                            aware preferred)
        :param assignees: (optionally) edit the assignees of the activity as a list, will overwrite all assignees
        :param status: (optionally) edit the status of the activity as a string

        :return: None
        :raises: NotFoundError, TypeError, APIError

        Example
        -------
        >>> from datetime import datetime
        >>> specify_wheel_diameter = project.activity('Specify wheel diameter')
        >>> specify_wheel_diameter.edit(name='Specify wheel diameter and circumference',
        ...                             description='The diameter and circumference are specified in inches',
        ...                             start_date=datetime.utcnow(),  # naive time is interpreted as UTC time
        ...                             assignee='testuser')

        If we want to provide timezone aware datetime objects we can use the 3rd party convenience library `pytz`.
        Mind that we need to fetch the timezone first and use `<timezone>.localize(<your datetime>)` to make it
        work correctly. Using datetime(2017,6,1,23,59,0 tzinfo=<tz>) does NOT work for most timezones with a
        daylight saving time. Check the pytz documentation.
        (see http://pythonhosted.org/pytz/#localized-times-and-date-arithmetic)

        >>> import pytz
        >>> start_date_tzaware = datetime.now(pytz.utc)
        >>> mytimezone = pytz.timezone('Europe/Amsterdam')
        >>> due_date_tzaware = mytimezone.localize(datetime(2019, 10, 27, 23, 59, 0))
        >>> specify_wheel_diameter.edit(due_date=due_date_tzaware, start_date=start_date_tzaware)

        """
        update_dict = {'id': self.id}
        if name:
            if isinstance(name, (str, text_type)):
                update_dict.update({'name': name})
                self.name = name
            else:
                raise TypeError('Name should be a string')

        if description:
            if isinstance(description, (str, text_type)):
                update_dict.update({'description': description})
                self.description = description
            else:
                raise TypeError('Description should be a string')

        if start_date:
            if isinstance(start_date, datetime.datetime):
                if not start_date.tzinfo:
                    warnings.warn(
                        "The startdate '{}' is naive and not timezone aware, use pytz.timezone info. "
                        "This date is interpreted as UTC time.".format(
                            start_date.isoformat(sep=' ')))
                update_dict.update(
                    {'start_date': start_date.isoformat(sep='T')})
            else:
                raise TypeError(
                    'Start date should be a datetime.datetime() object')

        if due_date:
            if isinstance(due_date, datetime.datetime):
                if not due_date.tzinfo:
                    warnings.warn(
                        "The duedate '{}' is naive and not timezone aware, use pytz.timezone info. "
                        "This date is interpreted as UTC time.".format(
                            due_date.isoformat(sep=' ')))
                update_dict.update({'due_date': due_date.isoformat(sep='T')})
            else:
                raise TypeError(
                    'Due date should be a datetime.datetime() object')

        if assignees:
            if isinstance(assignees, list):
                project = self._client.scope(self._json_data['scope']['name'])
                members_list = [
                    member['username']
                    for member in project._json_data['members']
                ]
                for assignee in assignees:
                    if assignee not in members_list:
                        raise NotFoundError(
                            "Assignee '{}' should be a member of the scope".
                            format(assignee))
                update_dict.update({'assignees': assignees})
            else:
                raise TypeError('Assignees should be a list')

        if status:
            if isinstance(status, (str, text_type)):
                update_dict.update({'status': status})
            else:
                raise TypeError('Status should be a string')

        url = self._client._build_url('activity', activity_id=self.id)
        r = self._client._request('PUT', url, json=update_dict)

        if r.status_code != requests.codes.ok:  # pragma: no cover
            raise APIError("Could not update Activity ({})".format(r))

        if status:
            self._json_data['status'] = str(status)
        if assignees:
            self._json_data['assignees'] = assignees
        if due_date:
            self._json_data['due_date'] = str(due_date)
        if start_date:
            self._json_data['start_date'] = str(start_date)