# -*- coding: utf8 -*-
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals
import suds
from pylero._compatible import basestring
from pylero.base_polarion import BasePolarion
from pylero.custom import ArrayOfCustom
from pylero.custom import Custom
from pylero.enum_option_id import ArrayOfEnumOptionId
from pylero.enum_option_id import EnumOptionId
from pylero.exceptions import PyleroLibException
from pylero.plan_record import ArrayOfPlanRecord
from pylero.plan_record import PlanRecord
from pylero.plan_statistics import PlanStatistics
from pylero.project import Project
from pylero.subterra_uri import SubterraURI
from pylero.text import Text
from pylero.user import User
from pylero.work_item import _WorkItem
[docs]class Plan(BasePolarion):
"""Object to handle the Polarion WSDL tns6:Plan class
Attributes:
allowed_types (ArrayOfEnumOptionId)
author_uri (SubterraURI)
calculation_type (EnumOptionId)
capacity (float)
color (string)
created (dateTime)
custom_fields (ArrayOfCustom)
default_estimate (float)
description (Text)
due_date (date)
estimation_field (string)
finished_on (dateTime)
is_template (boolean)
location (Location)
name (string)
parent (Plan)
plan_id (string)
previous_time_spent (duration)
prioritization_field (string)
project_uri (SubterraURI)
records (ArrayOfPlanRecord)
sort_order (int)
start_date (date)
started_on (dateTime)
status (EnumOptionId)
template_uri (SubterraURI)
updated (dateTime)"""
_cls_suds_map = {
"allowed_types": {
"field_name": "allowedTypes",
"is_array": True,
"cls": EnumOptionId,
"arr_cls": ArrayOfEnumOptionId,
"inner_field_name": "EnumOptionId",
"enum_id": "workitem-type",
},
"author": {
"field_name": "authorURI",
"cls": User,
"named_arg": "uri",
"sync_field": "uri",
},
"calculation_type": {"field_name": "calculationType", "cls": EnumOptionId},
"capacity": "capacity",
"color": "color",
"created": "created",
"custom_fields": {
"field_name": "customFields",
"is_array": True,
"cls": Custom,
"arr_cls": ArrayOfCustom,
"inner_field_name": "Custom",
},
"default_estimate": "defaultEstimate",
"description": {"field_name": "description", "cls": Text},
"due_date": "dueDate",
"estimation_field": "estimationField",
"finished_on": "finishedOn",
"is_template": "isTemplate",
"location": "location",
"name": "name",
# the parent field exists when creating an object Plan(), however the
# field is not returned in a get or search operation. Because of this,
# the attribute should not be accessible. the _fix_circular_refs is
# also commented out for the same reason. If this attribute become
# relevant in the future, that funciton should be activated.
# "parent":
# {"field_name": "parent"}, # populated in circ refs
"plan_id": "id",
"previous_time_spent": "previousTimeSpent",
"prioritization_field": "prioritizationField",
"project_id": {
"field_name": "projectURI",
"cls": Project,
"named_arg": "uri",
"sync_field": "uri",
},
"records": {
"field_name": "records",
"is_array": True,
"cls": PlanRecord,
"arr_cls": ArrayOfPlanRecord,
"inner_field_name": "PlanRecord",
},
"sort_order": "sortOrder",
"start_date": "startDate",
"started_on": "startedOn",
"status": {"field_name": "status", "cls": EnumOptionId},
"template_uri": {"field_name": "templateURI", "cls": SubterraURI},
"updated": "updated",
"uri": "_uri",
"_unresolved": "_unresolved",
}
_obj_client = "planning_client"
_obj_struct = "tns4:Plan"
_id_field = "plan_id"
[docs] @classmethod
def create(cls, plan_id, plan_name, project_id, parent_id, template_id):
"""Creates a new plan
Args:
plan_id (str): The id of the new plan
plan_name: The name of the new plan
project_id (str): The project the plan will be created in
parent_id: The id of the parent plan (can be null)
template_id: The id of the template used for this plan
Returns:
Plan Object
References:
Planning.createPlan
"""
uri = cls.session.planning_client.service.createPlan(
project_id, plan_name, plan_id, parent_id, template_id
)
return Plan(uri=uri)
[docs] @classmethod
def create_plan_template(cls, template_id, template_name, project_id, parent_id):
"""Creates a new plan template
Args:
template_id (str): The id of the new template
template_name: The name of the new template
project_id (str): The project the plan will be created in
parent_id: The id of the template the new template is based on
(can be null)
Returns:
Plan Object
References:
Planning.createPlanTemplate
"""
uri = cls.session.planning_client.service.createPlanTemplate(
project_id, template_name, template_id, parent_id
)
return Plan(uri=uri)
[docs] @classmethod
def delete_plans(cls, project_id, plan_ids):
"""Delete specified plans
Args:
project_id: the project the plans will be deleted in
plan_ids: list of plan ids to delete.
Returns:
None
References:
Planning.deletePlans
"""
cls.session.planning_client.service.deletePlans(project_id, plan_ids)
[docs] @classmethod
def search(cls, query, sort="plan_id", limit=-1, fields=[], search_templates=False):
"""search plans or plan templates
Args
query
sort
limit: the maximum number of records to be returned, -1 for no limit.
fields: list of the fields requested.
Returns:
list of Plan objects
References:
Planning.searchPlanTemplates
Planning.searchPlanTemplatesWithFields
Planning.searchPlans
Planning.searchPlansWithFields
"""
# function names and parameter lists generated dynamically based on
# parameters passed in.
if search_templates:
function_name = "searchPlanTemplates"
else:
function_name = "searchPlans"
if fields:
function_name += "WithFields"
p_sort = (
cls._cls_suds_map[sort]
if not isinstance(cls._cls_suds_map[sort], dict)
else cls._cls_suds_map[sort]["field_name"]
)
parms = [query, p_sort, limit] + (
[cls._convert_obj_fields_to_polarion(fields)] if fields else []
)
plans = []
for sud_plan in getattr(cls.session.planning_client.service, function_name)(
*parms
):
plans.append(Plan(suds_object=sud_plan))
return plans
[docs] def __init__(self, plan_id=None, project_id=None, uri=None, suds_object=None):
"""Plan Constructor
Args:
plan_id: ID of the plan
project_id: ID of the project that contains the specific plan
required when plan_id is given
uri: the SubterraURI of the plan to load
suds_object: the Polarion Plan object
Returns:
None
References:
Planning.getPlanById
Planning.getPlanByUri
"""
super(self.__class__, self).__init__(obj_id=plan_id, suds_object=suds_object)
if plan_id:
if not project_id:
raise PyleroLibException(
"When plan_id is passed in, " "project_id is required"
)
self._suds_object = self.session.planning_client.service.getPlanById(
project_id, plan_id
)
elif uri:
self._suds_object = self.session.planning_client.service.getPlanByUri(uri)
if plan_id or uri:
if getattr(self._suds_object, "_unresolvable", True):
raise PyleroLibException("The Plan {0} was not found.".format(plan_id))
# The parent variable is commented out, see above for explanation.
# in the event that the parent atrtribute becomes relevant, this function will
# need to be uncommented out as well
# def _fix_circular_refs(self):
# # The module references itself as a class attribute, which is not
# # allowed, so the self reference is defined here.
# self._cls_suds_map["parent"]["cls"] = self.__class__
[docs] def add_plan_items(self, work_items):
"""Add plan records to the plan.
Args:
items: list of work_item_ids
Returns:
None
References:
Planning.addPlanItems
"""
self._verify_obj()
if work_items:
if not isinstance(work_items, list):
raise PyleroLibException(
"work_items must be a list of _WorkItem objects"
)
p_items = []
for item in work_items:
wi = _WorkItem(self.project_id, work_item_id=item)
p_items.append(wi.uri)
self.session.planning_client.service.addPlanItems(self.uri, p_items)
[docs] def get_statistics(self):
"""get statistics of the plan
Args:
None
Returns:
PlanStatistics object
References:
Planning.getPlanStatistics
"""
self._verify_obj()
suds_stat = self.session.planning_client.service.getPlanStatistics(self.uri)
return PlanStatistics(suds_object=suds_stat)
[docs] def get_wiki_content(self):
"""Returns the wiki content of the plan
Args:
None
Returns:
Text object
References:
Planning.getPlanWikiContent
"""
self._verify_obj()
suds_obj = self.session.planning_client.service.getPlanWikiContent(self.uri)
return Text(suds_object=suds_obj)
[docs] def remove_plan_items(self, work_items):
"""Remove plan records to the plan.
Args:
items: list of work_item_ids
Returns:
None
References:
Planning.removePlanItems
"""
self._verify_obj()
if work_items:
if not isinstance(work_items, list):
raise PyleroLibException(
"work_items must be a list of _WorkItem objects"
)
p_items = []
for item in work_items:
wi = _WorkItem(self.project_id, work_item_id=item)
p_items.append(wi.uri)
self.session.planning_client.service.removePlanItems(self.uri, p_items)
[docs] def set_wiki_content(self, content):
"""method set_wiki_content updates the wiki for the current Plan
Args:
Content (str or Text object)
Returns:
None
References:
Planning.setPlanWikiContent
"""
self._verify_obj()
if content:
if isinstance(content, basestring):
obj_content = Text(content=content)
suds_content = obj_content._suds_object
elif isinstance(content, Text):
suds_content = content._suds_object
else: # is a suds object
suds_content = content
else:
suds_content = suds.null()
self.session.planning_client.service.setPlanWikiContent(self.uri, suds_content)
[docs] def update(self):
"""updates the server with the current plan content
Args:
None
Returns:
None
References:
Planning.updatePlan
"""
self._verify_obj()
self.session.planning_client.service.updatePlan(self._suds_object)
[docs] def was_started(self):
"""checks if the plan was started yet
Args:
None
Returns:
bool
References:
Planning.wasPlanStarted
"""
self._verify_obj()
return self.session.planning_client.service.wasPlanStarted(self.uri)
[docs]class ArrayOfPlan(BasePolarion):
_obj_client = "builder_client"
_obj_struct = "tns6:ArrayOfPlan"