py_jama_rest_client.client

   1import json
   2import logging
   3
   4from .core import Core, CoreException
   5
   6# This is the py_jama_rest_client logger.
   7py_jama_rest_client_logger = logging.getLogger('py_jama_rest_client')
   8
   9
  10class APIException(Exception):
  11    """This is the base class for all exceptions raised by the JamaClient"""
  12
  13    def __init__(self, message, status_code=None, reason=None):
  14        super(APIException, self).__init__(message)
  15        self.status_code = status_code
  16        self.reason = reason
  17
  18
  19class UnauthorizedException(APIException):
  20    """This exception is thrown whenever the api returns a 401 unauthorized response."""
  21    pass
  22
  23
  24class TooManyRequestsException(APIException):
  25    """This exception is thrown whenever the api returns a 429 too many requests response."""
  26    pass
  27
  28
  29class ResourceNotFoundException(APIException):
  30    """This exception is raised whenever the api returns a 404 not found response."""
  31    pass
  32
  33
  34class AlreadyExistsException(APIException):
  35    """This exception is thrown when the API returns a 400 response with a message that the resource already exists."""
  36    pass
  37
  38
  39class APIClientException(APIException):
  40    """This exception is thrown whenever a unknown 400 error is encountered."""
  41    pass
  42
  43
  44class APIServerException(APIException):
  45    """This exception is thrown whenever an unknown 500 response is encountered."""
  46    pass
  47
  48
  49class JamaClient:
  50    """A class to abstract communication with the Jama Connect API"""
  51
  52    __allowed_results_per_page = 20  # Default is 20, Max is 50. if set to greater than 50, only 50 will items return.
  53
  54    def __init__(self, host_domain,
  55                 credentials=('username|clientID', 'password|clientSecret'),
  56                 api_version='/rest/v1/',
  57                 oauth=False,
  58                 verify=True,
  59                 allowed_results_per_page=20):
  60        """Jama Client initializer
  61        :rtype: JamaClient
  62        :param host_domain: String The domain associated with the Jama Connect host
  63        :param credentials: the user name and password as a tuple or client id and client secret if using Oauth.
  64        :param api_version: valid args are '/rest/[v1|latest|labs]/'
  65        :param verify: Defaults to True, Setting this to False will skip SSL Certificate verification"""
  66        self.__credentials = credentials
  67        self.__allowed_results_per_page = allowed_results_per_page
  68        try:
  69            self.__core = Core(host_domain, credentials, api_version=api_version, oauth=oauth, verify=verify)
  70        except CoreException as err:
  71            py_jama_rest_client_logger.error(err)
  72            raise APIException(str(err))
  73
  74        # Log client creation
  75        py_jama_rest_client_logger.info('Created a new JamaClient instance. Domain: {} '
  76                                        'Connecting via Oauth: {}'.format(host_domain, oauth))
  77
  78    def get_available_endpoints(self):
  79        """
  80        Returns a list of all the available endpoints.
  81
  82        Returns: an array of available endpoints for this API
  83
  84        """
  85        try:
  86            response = self.__core.get('')
  87        except CoreException as err:
  88            py_jama_rest_client_logger.error(err)
  89            raise APIException(str(err))
  90        JamaClient.__handle_response_status(response)
  91        return response.json()['data']
  92
  93    def get_baselines(self, project_id, allowed_results_per_page=__allowed_results_per_page):
  94        """
  95        Returns a list of Baseline objects
  96        Args:
  97            project_id:  the Id of the project to fetch baselines for
  98            allowed_results_per_page: number of results per page
  99
 100        Returns: a list of Baseline objects
 101        """
 102        resource_path = 'baselines'
 103        params = {'project': project_id}
 104        baseline_data = self.__get_all(resource_path, params=params, allowed_results_per_page=allowed_results_per_page)
 105        return baseline_data
 106
 107    def get_baseline(self, baseline_id):
 108        """
 109        This method will return a baseline
 110        Args:
 111            baseline_id: the id of the baseline to fetch
 112
 113        Returns: a dictionary object representing the baseline
 114
 115        """
 116        resource_path = 'baselines/' + str(baseline_id)
 117        try:
 118            response = self.__core.get(resource_path)
 119        except CoreException as err:
 120            py_jama_rest_client_logger.error(err)
 121            raise APIException(str(err))
 122        JamaClient.__handle_response_status(response)
 123        return response.json()['data']
 124
 125    def get_baselines_versioneditems(self, baseline_id, allowed_results_per_page=__allowed_results_per_page):
 126        """
 127        Get all baseline items in a baseline with the specified ID
 128        Args:
 129            baseline_id:  The id of the baseline to fetch items for.
 130            allowed_results_per_page: Number of results per page
 131        Returns: A list of versioned items belonging to the baseline
 132        """
 133        resource_path = 'baselines/' + str(baseline_id) + '/versioneditems'
 134        baseline_items = self.__get_all(resource_path,  allowed_results_per_page=allowed_results_per_page)
 135        return baseline_items
 136
 137    def get_projects(self, allowed_results_per_page=__allowed_results_per_page):
 138        """This method will return all projects as JSON object
 139        :return: JSON Array of Item Objects.
 140        """
 141        resource_path = 'projects'
 142        project_data = self.__get_all(resource_path,  allowed_results_per_page=allowed_results_per_page)
 143        return project_data
 144
 145    def get_filter_results(self, filter_id, project_id=None, allowed_results_per_page=__allowed_results_per_page):
 146        """
 147        Get all results items for the filter with the specified ID
 148
 149        Args:
 150            filter_id: The ID of the filter to fetch the results for.
 151            project_id: Use this only for filters that run on any project, where projectScope is CURRENT
 152            allowed_results_per_page: Number of results per page
 153
 154        Returns:
 155            A List of items that match the filter.
 156
 157        """
 158        resource_path = 'filters/' + str(filter_id) + '/results'
 159        params = None
 160        if project_id is not None:
 161            params = {'project': str(project_id)}
 162        filter_results = self.__get_all(resource_path, params=params, allowed_results_per_page=allowed_results_per_page)
 163        return filter_results
 164
 165    def get_items(self, project_id, allowed_results_per_page=__allowed_results_per_page):
 166        """
 167        This method will return all items in the specified project.
 168        Args:
 169            project_id: the project ID
 170            allowed_results_per_page: number of results per page
 171
 172        Returns: a Json array of item objects
 173
 174        """
 175        resource_path = 'items'
 176        params = {'project': project_id}
 177        item_data = self.__get_all(resource_path, params=params, allowed_results_per_page=allowed_results_per_page)
 178        return item_data
 179
 180    def get_item(self, item_id):
 181        """
 182        This method will return a singular item of a specified item id
 183        Args:
 184            item_id: the item id of the item to fetch
 185
 186        Returns: a dictonary object representing the item
 187
 188        """
 189        resource_path = 'items/' + str(item_id)
 190        try:
 191            response = self.__core.get(resource_path)
 192        except CoreException as err:
 193            py_jama_rest_client_logger.error(err)
 194            raise APIException(str(err))
 195        JamaClient.__handle_response_status(response)
 196        return response.json()['data']
 197
 198    def get_item_lock(self, item_id):
 199        """
 200        Get the locked state, last locked date, and last locked by user for the item with the specified ID
 201        Args:
 202            item_id: The API ID of the item to get the lock info for.
 203
 204        Returns:
 205            A JSON object with the lock information for the item with the specified ID.
 206
 207        """
 208        resource_path = 'items/' + str(item_id) + '/lock'
 209        try:
 210            response = self.__core.get(resource_path)
 211        except CoreException as err:
 212            py_jama_rest_client_logger.error(err)
 213            raise APIException(str(err))
 214        JamaClient.__handle_response_status(response)
 215        return response.json()['data']
 216
 217    def put_item_lock(self, item_id, locked):
 218        """
 219        Update the locked state of the item with the specified ID
 220        Args:
 221            item_id: the API id of the item to be updated
 222            locked: boolean lock state to apply to this item
 223
 224        Returns:
 225            response status 200
 226
 227        """
 228        body = {
 229            "locked": locked,
 230        }
 231        resource_path = 'items/' + str(item_id) + '/lock'
 232        headers = {'content-type': 'application/json'}
 233        try:
 234            response = self.__core.put(resource_path, data=json.dumps(body), headers=headers)
 235        except CoreException as err:
 236            py_jama_rest_client_logger.error(err)
 237            raise APIException(str(err))
 238        return self.__handle_response_status(response)
 239
 240    def get_item_tags(self, item_id, allowed_results_per_page=__allowed_results_per_page):
 241        """
 242        Return all tags for the item with the specified ID
 243
 244        Args:
 245            item_id: the item id of the item to fetch
 246            allowed_results_per_page: number of results
 247
 248        Returns: a dictionary object representing the item's tags
 249
 250        """
 251        resource_path = 'items/' + str(item_id) + '/tags'
 252        item_tags = self.__get_all(resource_path,  allowed_results_per_page=allowed_results_per_page)
 253        return item_tags
 254
 255    def get_attachment(self, attachment_id):
 256        """
 257        This method will return a singular attachment of a specified attachment id
 258        Args:
 259            attachment_id: the attachment id of the attachment to fetch
 260
 261        Returns: a dictonary object representing the attachment
 262
 263        """
 264        resource_path = 'attachments/' + str(attachment_id)
 265        try:
 266            response = self.__core.get(resource_path)
 267        except CoreException as err:
 268            py_jama_rest_client_logger.error(err)
 269            raise APIException(str(err))
 270        JamaClient.__handle_response_status(response)
 271        return response.json()['data']
 272
 273    def get_abstract_items_from_doc_key(self, doc_key_list, allowed_results_per_page=__allowed_results_per_page):
 274        """ DEPRECATED INSTEAD USE get_abstract_items below.
 275        This method will take in a list of document keys and return an array of JSON Objects associated with the
 276        document keys."""
 277        resource_path = 'abstractitems'
 278        params = {'documentKey': doc_key_list}
 279        abstract_items = self.__get_all(resource_path, params=params, allowed_results_per_page=allowed_results_per_page)
 280        return abstract_items
 281
 282    def get_relationship_rule_sets(self):
 283        """
 284        This method will return all relationship rule sets across all projects of the Jama Connect instance.
 285
 286        Returns: An array of dictionary objects representing a rule set and its associated rules
 287
 288        """
 289        resource_path = 'relationshiprulesets/'
 290        rule_sets = self.__get_all(resource_path)
 291        return rule_sets
 292
 293    def get_relationship_rule_set(self, id):
 294        """
 295        This method will return the relationship rule sets by id.
 296
 297        Returns: A dictionary object representing a rule set and its associated rules
 298
 299        """
 300        resource_path = 'relationshiprulesets/' + str(id)
 301        response = self.__core.get(resource_path)
 302        JamaClient.__handle_response_status(response)
 303        return response.json()['data']
 304
 305    def get_relationship_rule_set_projects(self, id):
 306        """
 307        This method will return the projects that have a given relationship rule set defined.
 308
 309        Returns: An array of the dictionary objects representing the projects with a given rule set assigned
 310
 311        """
 312        resource_path = 'relationshiprulesets/' + str(id) + '/projects'
 313        projects = self.__get_all(resource_path)
 314        return projects
 315
 316    def get_relationship_types(self, allowed_results_per_page=__allowed_results_per_page):
 317        """
 318        This method will return all relationship types of the across all projects of the Jama Connect instance.
 319
 320        Args:
 321            allowed_results_per_page: Number of results per page
 322
 323        Returns: An array of dictionary objects
 324
 325        """
 326        resource_path = 'relationshiptypes/'
 327        item_types = self.__get_all(resource_path,  allowed_results_per_page=allowed_results_per_page)
 328        return item_types
 329
 330    def get_relationship_type(self, relationship_type_id):
 331        """
 332        Gets relationship type information for a specific relationship type id.
 333
 334        Args:
 335            relationship_type_id: The api id of the item type to fetch
 336
 337        Returns: JSON object
 338
 339        """
 340        resource_path = 'relationshiptypes/' + str(relationship_type_id)
 341        try:
 342            response = self.__core.get(resource_path)
 343        except CoreException as err:
 344            py_jama_rest_client_logger.error(err)
 345            raise APIException(str(err))
 346        JamaClient.__handle_response_status(response)
 347        return response.json()['data']
 348
 349    def get_item_types(self, allowed_results_per_page=__allowed_results_per_page):
 350        """
 351        This method will return all item types of the across all projects of the Jama Connect instance.
 352
 353        Args:
 354            allowed_results_per_page: Number of results per page
 355
 356        Returns: An array of dictionary objects
 357
 358        """
 359        resource_path = 'itemtypes/'
 360        item_types = self.__get_all(resource_path,  allowed_results_per_page=allowed_results_per_page)
 361        return item_types
 362
 363    def get_item_type(self, item_type_id):
 364        """
 365        Gets item type information for a specific item type id.
 366
 367        Args:
 368            item_type_id: The api id of the item type to fetch
 369
 370        Returns: JSON object
 371
 372        """
 373        resource_path = 'itemtypes/' + str(item_type_id)
 374        try:
 375            response = self.__core.get(resource_path)
 376        except CoreException as err:
 377            py_jama_rest_client_logger.error(err)
 378            raise APIException(str(err))
 379        JamaClient.__handle_response_status(response)
 380        return response.json()['data']
 381
 382    def get_items_synceditems(self, item_id, allowed_results_per_page=__allowed_results_per_page):
 383        """
 384        Get all synchronized items for the item with the specified ID
 385
 386        Args:
 387            item_id: The API id of the item being
 388            allowed_results_per_page: Number of results per page
 389
 390        Returns: A list of JSON Objects representing the items that are in the same synchronization group as the
 391        specified item.
 392
 393        """
 394        resource_path = 'items/' + str(item_id) + '/synceditems'
 395        synced_items = self.__get_all(resource_path,  allowed_results_per_page=allowed_results_per_page)
 396        return synced_items
 397
 398    def get_items_synceditems_status(self, item_id, synced_item_id):
 399        """
 400        Get the sync status for the synced item with the specified ID
 401
 402        Args:
 403            item_id: The id of the item to compare against
 404            synced_item_id: the id of the item to check if it is in sync
 405
 406        Returns: The response JSON from the API which contains a single field 'inSync' with a boolean value.
 407
 408        """
 409        resource_path = 'items/' + str(item_id) + '/synceditems/' + str(synced_item_id) + '/syncstatus'
 410        try:
 411            response = self.__core.get(resource_path)
 412        except CoreException as err:
 413            py_jama_rest_client_logger.error(err)
 414            raise APIException(str(err))
 415        JamaClient.__handle_response_status(response)
 416        return response.json()['data']
 417
 418    def get_item_versions(self, item_id):
 419        """
 420        Get all versions for the item with the specified ID
 421
 422        Args:
 423            item_id: the item id of the item to fetch
 424
 425        Returns: JSON array with all versions for the item
 426        """
 427        resource_path = 'items/' + str(item_id) + '/versions'
 428        versions = self.__get_all(resource_path)
 429        return versions
 430
 431    def get_item_version(self, item_id, version_num):
 432        """
 433        Get the numbered version for the item with the specified ID
 434
 435        Args:
 436            item_id: the item id of the item to fetch
 437            version_num: the version number for the item
 438
 439        Returns: a dictionary object representing the numbered version
 440        """
 441        resource_path = 'items/' + str(item_id) + '/versions/' + str(version_num)
 442        try:
 443            response = self.__core.get(resource_path)
 444        except CoreException as err:
 445            py_jama_rest_client_logger.error(err)
 446            raise APIException(str(err))
 447        JamaClient.__handle_response_status(response)
 448        return response.json()['data']
 449
 450    def get_versioned_item(self, item_id, version_num):
 451        """
 452        Get the snapshot of the item at the specified version
 453
 454        Args:
 455            item_id: the item id of the item to fetch
 456            version_num: the version number for the item
 457
 458        Returns: a dictionary object representing the versioned item
 459        """
 460        resource_path = 'items/' + str(item_id) + '/versions/' + str(version_num) + '/versioneditem'
 461        try:
 462            response = self.__core.get(resource_path)
 463        except CoreException as err:
 464            py_jama_rest_client_logger.error(err)
 465            raise APIException(str(err))
 466        JamaClient.__handle_response_status(response)
 467        return response.json()['data']
 468
 469    def get_item_versions(self, item_id, allowed_results_per_page=__allowed_results_per_page):
 470        """
 471        Get all versions for the item with the specified ID
 472
 473        Args:
 474            item_id: the item id of the item to fetch
 475            allowed_results_per_page: number of results per page
 476
 477        Returns: JSON array with all versions for the item
 478        """
 479        resource_path = 'items/' + str(item_id) + '/versions'
 480        versions = self.__get_all(resource_path,  allowed_results_per_page=allowed_results_per_page)
 481        return versions
 482
 483    def get_item_version(self, item_id, version_num):
 484        """
 485        Get the numbered version for the item with the specified ID
 486
 487        Args:
 488            item_id: the item id of the item to fetch
 489            version_num: the version number for the item
 490
 491        Returns: a dictionary object representing the numbered version
 492        """
 493        resource_path = 'items/' + str(item_id) + '/versions/' + str(version_num)
 494        response = self.__core.get(resource_path)
 495        JamaClient.__handle_response_status(response)
 496        return response.json()['data']
 497
 498    def get_versioned_item(self, item_id, version_num):
 499        """
 500        Get the snapshot of the item at the specified version
 501
 502        Args:
 503            item_id: the item id of the item to fetch
 504            version_num: the version number for the item
 505
 506        Returns: a dictionary object representing the versioned item
 507        """
 508        resource_path = 'items/' + str(item_id) + '/versions/' + str(version_num) + '/versioneditem'
 509        response = self.__core.get(resource_path)
 510        JamaClient.__handle_response_status(response)
 511        return response.json()['data']
 512
 513    def get_pick_lists(self, allowed_results_per_page=__allowed_results_per_page):
 514        """
 515        Returns a list of all the pick lists
 516
 517        Args:
 518            allowed_results_per_page: number of results per page
 519
 520        Returns: an array of dictionary objects
 521
 522        """
 523        resource_path = 'picklists/'
 524        pick_lists = self.__get_all(resource_path,  allowed_results_per_page=allowed_results_per_page)
 525        return pick_lists
 526
 527    def get_pick_list(self, pick_list_id):
 528        """
 529        Gets all a singular picklist
 530
 531        Args:
 532            pick_list_id: The API id of the pick list to fetch
 533
 534        Returns: a dictionary object representing the picklist.
 535
 536        """
 537        resource_path = 'picklists/' + str(pick_list_id)
 538        try:
 539            response = self.__core.get(resource_path)
 540        except CoreException as err:
 541            py_jama_rest_client_logger.error(err)
 542            raise APIException(str(err))
 543        JamaClient.__handle_response_status(response)
 544        return response.json()['data']
 545
 546    def get_pick_list_options(self, pick_list_id, allowed_results_per_page=__allowed_results_per_page):
 547        """
 548        Gets all all the picklist options for a single picklist
 549        Args:
 550            pick_list_id: the api id of the picklist to fetch options for.
 551            allowed_results_per_page: number of results per page
 552
 553        Returns: an array of dictionary objects that represent the picklist options.
 554
 555        """
 556        resource_path = 'picklists/' + str(pick_list_id) + '/options'
 557        pick_list_options = self.__get_all(resource_path,  allowed_results_per_page=allowed_results_per_page)
 558        return pick_list_options
 559
 560    def get_pick_list_option(self, pick_list_option_id):
 561        """
 562        Fetches a single picklist option from the API
 563        Args:
 564            pick_list_option_id: The API ID of the picklist option to fetch
 565
 566        Returns: A dictonary object representing the picklist option.
 567
 568        """
 569        resource_path = 'picklistoptions/' + str(pick_list_option_id)
 570        try:
 571            response = self.__core.get(resource_path)
 572        except CoreException as err:
 573            py_jama_rest_client_logger.error(err)
 574            raise APIException(str(err))
 575        JamaClient.__handle_response_status(response)
 576        return response.json()['data']
 577
 578    def get_relationships(self, project_id, allowed_results_per_page=__allowed_results_per_page):
 579        """
 580        Returns a list of all relationships of a specified project
 581
 582        Args:
 583            project_id: the api project id of a project
 584            allowed_results_per_page: number of results per page
 585
 586        Returns: a list of dictionary objects that represents a relationships
 587
 588        """
 589        resource_path = 'relationships'
 590        params = {'project': project_id}
 591        relationship_data = self.__get_all(resource_path, params=params,
 592                                           allowed_results_per_page=allowed_results_per_page)
 593        return relationship_data
 594
 595    def get_relationship(self, relationship_id):
 596        """
 597        Returns a specific relationship object of a specified relationship ID
 598
 599        Args:
 600            relationship_id: the api project id of a relationship
 601
 602        Returns: a dictionary object that represents a relationship
 603
 604        """
 605        resource_path = 'relationships/' + str(relationship_id)
 606        try:
 607            response = self.__core.get(resource_path)
 608        except CoreException as err:
 609            py_jama_rest_client_logger.error(err)
 610            raise APIException(str(err))
 611        JamaClient.__handle_response_status(response)
 612        return response.json()['data']
 613
 614    def get_abstract_items(self,
 615                           project=None,
 616                           item_type=None,
 617                           document_key=None,
 618                           release=None,
 619                           created_date=None,
 620                           modified_date=None,
 621                           last_activity_date=None,
 622                           contains=None,
 623                           sort_by=None):
 624        """
 625        This method will return all items that match the query parameters entered.
 626
 627        Args:
 628            project:            Array[integer]
 629            item_type:          Array[integer]
 630            document_key:       Array[string]
 631            release:            Array[integer]
 632            created_date:       Array[string]
 633            modified_date:      Array[string]
 634            last_activity_date: Array[string]
 635            contains:           Array[string]
 636            sort_by:            Array[string]
 637
 638        Returns:
 639            A JSON Array of items.
 640
 641        """
 642        resource_path = 'abstractitems'
 643
 644        # Add each parameter that is not null to the request.
 645        params = {}
 646
 647        if project is not None:
 648            params['project'] = project
 649
 650        if item_type is not None:
 651            params['itemType'] = item_type
 652
 653        if document_key is not None:
 654            params['documentKey'] = document_key
 655
 656        if release is not None:
 657            params['release'] = release
 658
 659        if created_date is not None:
 660            params['createdDate'] = created_date
 661
 662        if modified_date is not None:
 663            params['modifiedDate'] = modified_date
 664
 665        if last_activity_date is not None:
 666            params['lastActivityDate'] = last_activity_date
 667
 668        if contains is not None:
 669            params['contains'] = contains
 670
 671        if sort_by is not None:
 672            params['sortBy'] = sort_by
 673
 674        abstract_items = self.__get_all(resource_path, params=params)
 675        return abstract_items
 676
 677    def get_abstract_item(self, item_id):
 678        """
 679        This method will return an item, test plan, test cycle, test run, or attachment with the specified ID
 680        Args:
 681            item_id: the item id of the item to fetch
 682
 683        Returns: a dictonary object representing the abstract item
 684
 685        """
 686        resource_path = 'abstractitems/' + str(item_id)
 687        try:
 688            response = self.__core.get(resource_path)
 689        except CoreException as err:
 690            py_jama_rest_client_logger.error(err)
 691            raise APIException(str(err))
 692        JamaClient.__handle_response_status(response)
 693        return response.json()['data']
 694
 695    def get_abstract_item_versions(self, item_id):
 696        """
 697        Get all versions for the item with the specified ID
 698
 699        Args:
 700            item_id: the item id of the item to fetch
 701
 702        Returns: JSON array with all versions for the item
 703        """
 704        resource_path = 'abstractitems/' + str(item_id) + '/versions'
 705        versions = self.__get_all(resource_path)
 706        return versions
 707
 708    def get_abtract_item_version(self, item_id, version_num):
 709        """
 710        Get the numbered version for the item with the specified ID
 711
 712        Args:
 713            item_id: the item id of the item to fetch
 714            version_num: the version number for the item
 715
 716        Returns: a dictionary object representing the numbered version
 717        """
 718        resource_path = 'abstractitems/' + str(item_id) + '/versions/' + str(version_num)
 719        try:
 720            response = self.__core.get(resource_path)
 721        except CoreException as err:
 722            py_jama_rest_client_logger.error(err)
 723            raise APIException(str(err))
 724        JamaClient.__handle_response_status(response)
 725        return response.json()['data']
 726
 727    def get_abstract_versioned_item(self, item_id, version_num):
 728        """
 729        Get the snapshot of the item at the specified version
 730
 731        Args:
 732            item_id: the item id of the item to fetch
 733            version_num: the version number for the item
 734
 735        Returns: a dictionary object representing the versioned item
 736        """
 737        resource_path = 'abstractitems/' + str(item_id) + '/versions/' + str(version_num) + '/versioneditem'
 738        try:
 739            response = self.__core.get(resource_path)
 740        except CoreException as err:
 741            py_jama_rest_client_logger.error(err)
 742            raise APIException(str(err))
 743        JamaClient.__handle_response_status(response)
 744        return response.json()['data']
 745
 746
 747    def get_item_children(self, item_id, allowed_results_per_page=__allowed_results_per_page):
 748        """
 749        This method will return list of the child items of the item passed to the function.
 750        Args:
 751            item_id: (int) The id of the item for which children items should be fetched
 752            allowed_results_per_page: Number of results per page
 753
 754        Returns: a List of Objects that represent the children of the item passed in.
 755        """
 756        resource_path = 'items/' + str(item_id) + '/children'
 757        child_items = self.__get_all(resource_path,  allowed_results_per_page=allowed_results_per_page)
 758        return child_items
 759
 760    def get_testruns(self, test_cycle_id, allowed_results_per_page=__allowed_results_per_page):
 761        """This method will return all test runs associated with the specified test cycle.  Test runs will be returned
 762        as a list of json objects."""
 763        resource_path = 'testcycles/' + str(test_cycle_id) + '/testruns'
 764        testrun_data = self.__get_all(resource_path,  allowed_results_per_page=allowed_results_per_page)
 765        return testrun_data
 766
 767    def get_items_upstream_relationships(self, item_id, allowed_results_per_page=__allowed_results_per_page):
 768        """
 769        Returns a list of all the upstream relationships for the item with the specified ID.
 770        Args:
 771            item_id: the api id of the item
 772            allowed_results_per_page: number of results per page
 773
 774        Returns: an array of dictionary objects that represent the upstream relationships for the item.
 775
 776        """
 777        resource_path = 'items/' + str(item_id) + '/upstreamrelationships'
 778        return self.__get_all(resource_path,  allowed_results_per_page=allowed_results_per_page)
 779
 780    def get_items_downstream_related(self, item_id, allowed_results_per_page=__allowed_results_per_page):
 781        """
 782        Returns a list of all the downstream related items for the item with the specified ID.
 783
 784        Args:
 785            item_id: the api id of the item to fetch downstream items for
 786            allowed_results_per_page: number of results per page
 787
 788        Returns: an array of dictionary objects that represent the downstream related items for the specified item.
 789
 790        """
 791        resource_path = 'items/' + str(item_id) + '/downstreamrelated'
 792        return self.__get_all(resource_path,  allowed_results_per_page=allowed_results_per_page)
 793
 794    def get_items_downstream_relationships(self, item_id, allowed_results_per_page=__allowed_results_per_page):
 795        """
 796        Returns a list of all the downstream relationships for the item with the specified ID.
 797
 798        Args:
 799            item_id: the api id of the item
 800
 801        Returns: an array of dictionary objects that represent the downstream relationships for the item.
 802
 803        """
 804        resource_path = 'items/' + str(item_id) + '/downstreamrelationships'
 805        return self.__get_all(resource_path, allowed_results_per_page=allowed_results_per_page)
 806
 807    def get_items_upstream_related(self, item_id):
 808        """
 809        Returns a list of all the upstream related items for the item with the specified ID.
 810
 811        Args:
 812            item_id: the api id of the item to fetch upstream items for
 813
 814        Returns: an array of dictionary objects that represent the upstream related items for the specified item.
 815
 816         """
 817        resource_path = 'items/' + str(item_id) + '/upstreamrelated'
 818        return self.__get_all(resource_path)
 819
 820    def get_item_workflow_transitions(self, item_id):
 821        """
 822        Get all valid workflow transitions that can be made with the specified id
 823
 824        Args:
 825            item_id: the api id of the item
 826            allowed_results_per_page: number of results per page
 827
 828        Returns: an array of dictionary objects that represent the workflow transitions for the item.
 829
 830        """
 831        resource_path = 'items/' + str(item_id) + '/workflowtransitionoptions'
 832        return self.__get_all(resource_path)
 833
 834    def get_tags(self, project, allowed_results_per_page=__allowed_results_per_page):
 835        """
 836        Get all tags for the project with the specified id
 837        Args:
 838            project: The API ID of the project to fetch tags for.
 839            allowed_results_per_page: Number of results per page
 840
 841        Returns: A Json Array that contains all the tag data for the specified project.
 842
 843        """
 844        resource_path = 'tags'
 845        params = {'project': project}
 846        tag_data = self.__get_all(resource_path, params=params, allowed_results_per_page=allowed_results_per_page)
 847        return tag_data
 848
 849    def get_tagged_items(self, tag_id, allowed_results_per_page=__allowed_results_per_page):
 850        """
 851        Get all items tagged with the specified ID
 852
 853        Args:
 854            tag_id: The ID of the tag to fetch the results for.
 855            allowed_results_per_page: Number of results per page
 856
 857        Returns:
 858            A List of items that match the tag.
 859
 860        """
 861        resource_path = 'tags/' + str(tag_id) + '/items'
 862        params = None
 863        tag_results = self.__get_all(resource_path, params=params, allowed_results_per_page=allowed_results_per_page)
 864        return tag_results
 865
 866    def get_users(self, allowed_results_per_page=__allowed_results_per_page):
 867        """
 868        Gets a list of all active users visible to the current user
 869
 870        Args:
 871            allowed_results_per_page: Number of results per page
 872
 873        Returns: JSON array
 874
 875        """
 876        resource_path = 'users/'
 877        users = self.__get_all(resource_path,  allowed_results_per_page=allowed_results_per_page)
 878        return users
 879
 880    def get_user(self, user_id):
 881        """
 882        Gets a single speificed user
 883
 884        Args:
 885            user_id: user api ID
 886
 887        Returns: JSON obect
 888
 889        """
 890        resource_path = 'users/' + str(user_id)
 891        try:
 892            response = self.__core.get(resource_path)
 893        except CoreException as err:
 894            py_jama_rest_client_logger.error(err)
 895            raise APIException(str(err))
 896        return response.json()['data']
 897
 898    def get_current_user(self):
 899        """
 900        Gets a current user
 901
 902        Returns: JSON obect
 903
 904        """
 905        resource_path = 'users/current'
 906        try:
 907            response = self.__core.get(resource_path)
 908        except CoreException as err:
 909            py_jama_rest_client_logger.error(err)
 910            raise APIException(str(err))
 911        return response.json()['data']
 912
 913    def get_test_cycle(self, test_cycle_id):
 914        """
 915        This method will return JSON data about the test cycle specified by the test cycle id.
 916
 917        Args:
 918            test_cycle_id: the api id of the test cycle to fetch
 919
 920        Returns: a dictionary object that represents the test cycle
 921
 922        """
 923        resource_path = 'testcycles/' + str(test_cycle_id)
 924        try:
 925            response = self.__core.get(resource_path)
 926        except CoreException as err:
 927            py_jama_rest_client_logger.error(err)
 928            raise APIException(str(err))
 929        JamaClient.__handle_response_status(response)
 930        return response.json()['data']
 931
 932    def delete_item(self, item_id):
 933        """
 934        This method will delete an item in Jama Connect.
 935
 936        Args:
 937            item_id: The jama connect API ID of the item to be deleted
 938
 939        Returns: The success status code.
 940        """
 941        resource_path = 'items/' + str(item_id)
 942        try:
 943            response = self.__core.delete(resource_path)
 944        except CoreException as err:
 945            py_jama_rest_client_logger.error(err)
 946            raise APIException(str(err))
 947        JamaClient.__handle_response_status(response)
 948        return response.status_code
 949
 950    def delete_relationships(self, relationship_id):
 951        """
 952        Deletes a relationship with the specified relationship ID
 953
 954        Args:
 955            relationship_id: the api project id of a relationship
 956
 957        Returns: The success status code.
 958
 959        """
 960        resource_path = 'relationships/' + str(relationship_id)
 961        try:
 962            response = self.__core.delete(resource_path)
 963        except CoreException as err:
 964            py_jama_rest_client_logger.error(err)
 965            raise APIException(str(err))
 966        JamaClient.__handle_response_status(response)
 967        return response.status_code
 968
 969    def patch_item(self, item_id, patches):
 970        """
 971        This method will patch an item.
 972        Args:
 973            item_id: the API ID of the item that is to be patched
 974            patches: An array of dicts, that represent patch operations each dict should have the following entries
 975             [
 976                {
 977                    "op": string,
 978                    "path": string,
 979                    "value": {}
 980                }
 981            ]
 982
 983        Returns: The response status code
 984
 985        """
 986        resource_path = 'items/' + str(item_id)
 987        headers = {'Content-Type': 'application/json',
 988                   'Accept': 'application/json'
 989                   }
 990        data = json.dumps(patches)
 991
 992        # Make the API Call
 993        try:
 994            response = self.__core.patch(resource_path, data=data, headers=headers)
 995        except CoreException as err:
 996            py_jama_rest_client_logger.error(err)
 997            raise APIException(str(err))
 998
 999        # validate response
1000        JamaClient.__handle_response_status(response)
1001        return response.json()['meta']['status']
1002
1003    def post_user(self, username, password, first_name, last_name, email, license_type, phone=None, title=None,
1004                  location=None):
1005        """
1006        Creates a new user
1007
1008        Args:
1009            username: str
1010            password: str
1011            first_name: str
1012            last_name: str
1013            email: str
1014            phone: str - optional
1015            title: str - optional
1016            location: str - optional
1017            licenseType: enum [ NAMED, FLOATING, STAKEHOLDER, FLOATING_COLLABORATOR, RESERVED_COLLABORATOR, FLOATING_REVIEWER, RESERVED_REVIEWER, NAMED_REVIEWER, TEST_RUNNER, EXPIRING_TRIAL, INACTIVE ]
1018
1019        Returns: int of newly created user api ID
1020
1021        """
1022
1023        body = {
1024            'username': username,
1025            'password': password,
1026            'firstName': first_name,
1027            'lastName': last_name,
1028            'email': email,
1029            'phone': phone,
1030            'title': title,
1031            'location': location,
1032            'licenseType': license_type
1033        }
1034        resource_path = 'users/'
1035        headers = {'content-type': 'application/json'}
1036        try:
1037            response = self.__core.post(resource_path, data=json.dumps(body), headers=headers)
1038        except CoreException as err:
1039            py_jama_rest_client_logger.error(err)
1040            raise APIException(str(err))
1041        JamaClient.__handle_response_status(response)
1042        return response.json()['meta']['id']
1043
1044    def post_tag(self, name: str, project: int):
1045        """
1046        Create a new tag in the project with the specified ID
1047        Args:
1048            name: The display name for the tag
1049            project: The project to create the new tag in
1050
1051        Returns: The integer API ID fr the newly created Tag.
1052        """
1053        resource_path = 'tags'
1054        body = {
1055            'name': name,
1056            'project': project
1057        }
1058        headers = {'content-type': 'application/json'}
1059        try:
1060            response = self.__core.post(resource_path, data=json.dumps(body), headers=headers)
1061        except CoreException as err:
1062            py_jama_rest_client_logger.error(err)
1063            raise APIException(str(err))
1064        JamaClient.__handle_response_status(response)
1065        return response.json()['meta']['id']
1066
1067    def post_testplans_testcycles(self, testplan_id, testcycle_name, start_date, end_date, testgroups_to_include=None,
1068                                  testrun_status_to_include=None):
1069        """
1070        This method will create a new Test Cycle.
1071
1072        Args:
1073            testplan_id (int): The API_ID of the testplan to create the test cycle from.
1074            testcycle_name (str): The name you would like to set for the new Test Cycle
1075            start_date (str): Start date in 'yyyy-mm-dd' Format
1076            end_date (str): End date in 'yyyy-mm-dd' Format
1077            testgroups_to_include (int[]):  This array of integers specify the test groups to be included.
1078            testrun_status_to_include (str[]): Only valid after generating the first Test Cycle, you may choose to only
1079                generate Test Runs that were a specified status in the previous cycle. Do not specify anything to
1080                include all statuses
1081
1082        Returns:
1083            (int): Returns the integer id for the newly created testcycle, or None if something went terribly wrong.
1084        """
1085        resource_path = 'testplans/' + str(testplan_id) + '/testcycles'
1086        headers = {'content-type': 'application/json'}
1087        fields = {
1088            'name': testcycle_name,
1089            'startDate': start_date,
1090            'endDate': end_date
1091        }
1092        test_run_gen_config = {}
1093        if testgroups_to_include is not None:
1094            test_run_gen_config['testGroupsToInclude'] = testgroups_to_include
1095        if testrun_status_to_include is not None:
1096            test_run_gen_config['testRunStatusesToInclude'] = testrun_status_to_include
1097        body = {
1098            'fields': fields,
1099            'testRunGenerationConfig': test_run_gen_config
1100        }
1101
1102        # Make the API Call
1103        try:
1104            response = self.__core.post(resource_path, data=json.dumps(body), headers=headers)
1105        except CoreException as err:
1106            py_jama_rest_client_logger.error(err)
1107            raise APIException(str(err))
1108
1109        # Validate response
1110        JamaClient.__handle_response_status(response)
1111        return response.json()['meta']['id']
1112
1113    def post_item(self, project, item_type_id, child_item_type_id, location, fields, global_id=None):
1114        """ This method will post a new item to Jama Connect.
1115        :param global_id: optional param to post the item with a custom global id
1116        :param project integer representing the project to which this item is to be posted
1117        :param item_type_id integer ID of an Item Type.
1118        :param child_item_type_id integer ID of an Item Type.
1119        :param location dictionary with integer ID of the parent item or project.
1120        :param fields dictionary item field data.
1121        :return integer ID of the successfully posted item or None if there was an error."""
1122
1123        body = {
1124            "project": project,
1125            "itemType": item_type_id,
1126            "childItemType": child_item_type_id,
1127            "location": {
1128                "parent": location
1129            },
1130            "fields": fields
1131        }
1132        resource_path = 'items/'
1133        params = {}
1134
1135        # we setting a global ID?
1136        if global_id is not None:
1137            body['globalId'] = global_id
1138            params['setGlobalIdManually'] = True
1139
1140        headers = {'content-type': 'application/json'}
1141        try:
1142            response = self.__core.post(resource_path, data=json.dumps(body), headers=headers, params=params)
1143        except CoreException as err:
1144            py_jama_rest_client_logger.error(err)
1145            raise APIException(str(err))
1146        JamaClient.__handle_response_status(response)
1147        return response.json()['meta']['id']
1148
1149    def post_item_tag(self, item_id, tag_id):
1150        """
1151        Add an existing tag to the item with the specified ID
1152        Args:
1153            item_id: The API ID of the item to add a tag.
1154            tag_id: The API ID of the tag to add to the item.
1155
1156        Returns: 201 if successful
1157
1158        """
1159        body = {
1160            "tag": tag_id
1161        }
1162        resource_path = 'items/' + str(item_id) + '/tags'
1163        headers = {'content-type': 'application/json'}
1164        try:
1165            response = self.__core.post(resource_path, data=json.dumps(body), headers=headers)
1166        except CoreException as err:
1167            py_jama_rest_client_logger.error(err)
1168            raise APIException(str(err))
1169        JamaClient.__handle_response_status(response)
1170        return response.status_code
1171
1172    def post_item_sync(self, source_item: int, pool_item: int):
1173        """
1174        add an item to an existing pool of global ids
1175        Args:
1176            source_item: integer API ID of the source item, this item will adopt the global id of the
1177                         pool_item.
1178            pool_item: integer API ID of the item in the target global ID pool.
1179
1180        Returns: the integer ID of the modified source item.
1181        """
1182        body = {
1183            'item': source_item
1184        }
1185
1186        resource_path = 'items/' + str(pool_item) + '/synceditems'
1187        headers = {'content-type': 'application/json'}
1188        try:
1189            response = self.__core.post(resource_path, data=json.dumps(body), headers=headers)
1190        except CoreException as err:
1191            py_jama_rest_client_logger.error(err)
1192            raise APIException(str(err))
1193        JamaClient.__handle_response_status(response)
1194        return response.json()['meta']['id']
1195
1196    def post_relationship(self, from_item: int, to_item: int, relationship_type=None):
1197        """
1198
1199        Args:
1200            from_item: integer API id of the source item
1201            to_item: integer API id of the target item
1202            relationship_type: Optional integer API id of the relationship type to create
1203
1204        Returns: The integer ID of the newly created relationship.
1205
1206        """
1207        body = {
1208            "fromItem": from_item,
1209            "toItem": to_item,
1210        }
1211        if relationship_type is not None:
1212            body['relationshipType'] = relationship_type
1213        resource_path = 'relationships/'
1214        headers = {'content-type': 'application/json'}
1215        try:
1216            response = self.__core.post(resource_path, data=json.dumps(body), headers=headers)
1217        except CoreException as err:
1218            py_jama_rest_client_logger.error(err)
1219            raise APIException(str(err))
1220        JamaClient.__handle_response_status(response)
1221        return response.json()['meta']['id']
1222
1223    def put_relationship(self, relationship_id: int, from_item: int, to_item: int, relationship_type: int = None):
1224        """
1225
1226            Args:
1227                relationship_id: integer API id of the relationship
1228                from_item: integer API id of the source item
1229                to_item: integer API id of the target item
1230                relationship_type: Optional integer API id of the relationship type to create
1231
1232        """
1233        body = {
1234            "fromItem": from_item,
1235            "toItem": to_item
1236        }
1237        if relationship_type is not None:
1238            body['relationshipType'] = relationship_type
1239        resource_path = 'relationships/{}'.format(relationship_id)
1240        headers = {'content-type': 'application/json'}
1241        try:
1242            response = self.__core.put(resource_path, data=json.dumps(body), headers=headers)
1243        except CoreException as err:
1244            py_jama_rest_client_logger.error(err)
1245            raise APIException(str(err))
1246        JamaClient.__handle_response_status(response)
1247
1248    def post_item_attachment(self, item_id, attachment_id):
1249        """
1250        Add an existing attachment to the item with the specified ID
1251        :param item_id: this is the ID of the item
1252        :param attachment_id: The ID of the attachment
1253        :return: 201 if successful / the response status of the post operation
1254        """
1255        body = {"attachment": attachment_id}
1256        resource_path = 'items/' + str(item_id) + '/attachments'
1257        headers = {'content-type': 'application/json'}
1258        try:
1259            response = self.__core.post(resource_path, data=json.dumps(body), headers=headers)
1260        except CoreException as err:
1261            py_jama_rest_client_logger.error(err)
1262            raise APIException(str(err))
1263        JamaClient.__handle_response_status(response)
1264        return response.status_code
1265
1266    def post_project_attachment(self, project_id, name, description):
1267        """
1268        This Method will make a new attachment object in the specified project
1269        :param project_id: The integer project ID to create the attachment in.
1270        :param name:  The name of the attachment
1271        :param description: The description of the attachment
1272        :return: Returns the ID of the newly created attachment object.
1273        """
1274        body = {
1275            "fields": {
1276                "name": name,
1277                "description": description
1278            }
1279        }
1280
1281        resource_path = 'projects/' + str(project_id) + '/attachments'
1282        headers = {'content-type': 'application/json'}
1283        try:
1284            response = self.__core.post(resource_path, data=json.dumps(body), headers=headers)
1285        except CoreException as err:
1286            py_jama_rest_client_logger.error(err)
1287            raise APIException(str(err))
1288        JamaClient.__handle_response_status(response)
1289        return response.json()['meta']['id']
1290
1291    def put_item(self, project, item_id, item_type_id, child_item_type_id, location, fields):
1292        """ This method wil
1293         PUT a new item to Jama Connect.
1294        :param project integer representing the project to which this item is to be posted
1295        :param item_id integer representing the item which is to be updated
1296        :param item_type_id integer ID of an Item Type.
1297        :param child_item_type_id integer ID of an Item Type.
1298        :param location dictionary  with a key of 'item' or 'project' and an value with the ID of the parent
1299        :param fields dictionary item field data.
1300        :return integer ID of the successfully posted item or None if there was an error."""
1301
1302        body = {
1303            "project": project,
1304            "itemType": item_type_id,
1305            "childItemType": child_item_type_id,
1306            "location": {
1307                "parent": location
1308            },
1309            "fields": fields
1310        }
1311        resource_path = 'items/' + str(item_id)
1312        headers = {'content-type': 'application/json'}
1313        try:
1314            response = self.__core.put(resource_path, data=json.dumps(body), headers=headers)
1315        except CoreException as err:
1316            py_jama_rest_client_logger.error(err)
1317            raise APIException(str(err))
1318        return self.__handle_response_status(response)
1319
1320    def put_attachments_file(self, attachment_id, file_path):
1321        """
1322        Upload a file to a jama attachment
1323        :param attachment_id: the integer ID of the attachment item to which we are uploading the file
1324        :param file_path: the file path of the file to be uploaded
1325        :return: returns the status code of the call
1326        """
1327        resource_path = 'attachments/' + str(attachment_id) + '/file'
1328        with open(file_path, 'rb') as f:
1329            files = {'file': f}
1330            try:
1331                response = self.__core.put(resource_path, files=files)
1332            except CoreException as err:
1333                py_jama_rest_client_logger.error(err)
1334                raise APIException(str(err))
1335        self.__handle_response_status(response)
1336        return response.status_code
1337
1338    def put_user(self, user_id, username, password, first_name, last_name, email, phone=None, title=None,
1339                 location=None):
1340        """
1341        updates an existing user
1342
1343        Args:
1344            username: str
1345            password: str
1346            first_name: str
1347            last_name: str
1348            email: str
1349            phone: str - optional
1350            title: str - optional
1351            location: str - optional
1352
1353        Returns: api status code
1354
1355        """
1356
1357        body = {
1358            'username': username,
1359            'password': password,
1360            'firstName': first_name,
1361            'lastName': last_name,
1362            'email': email,
1363            'phone': phone,
1364            'title': title,
1365            'location': location
1366        }
1367        resource_path = 'users/' + str(user_id)
1368        headers = {'content-type': 'application/json'}
1369        try:
1370            response = self.__core.put(resource_path, data=json.dumps(body), headers=headers)
1371        except CoreException as err:
1372            py_jama_rest_client_logger.error(err)
1373            raise APIException(str(err))
1374            raise APIException
1375        return self.__handle_response_status(response)
1376
1377    def put_user_active(self, user_id, is_active):
1378        """
1379        updates an existing users active status
1380
1381        Args:
1382            is_active: boolean
1383
1384        Returns: api status code
1385
1386        """
1387        body = {
1388            'active': is_active
1389        }
1390        resource_path = 'users/' + str(user_id) + '/active'
1391        headers = {'content-type': 'application/json'}
1392        try:
1393            response = self.__core.put(resource_path, data=json.dumps(body), headers=headers)
1394        except CoreException as err:
1395            py_jama_rest_client_logger.error(err)
1396            raise APIException(str(err))
1397        return self.__handle_response_status(response)
1398
1399    def put_test_run(self, test_run_id, data=None):
1400        """ This method will post a test run to Jama through the API"""
1401        resource_path = 'testruns/' + str(test_run_id)
1402        headers = {'content-type': 'application/json'}
1403        try:
1404            response = self.__core.put(resource_path, data=data, headers=headers)
1405        except CoreException as err:
1406            py_jama_rest_client_logger.error(err)
1407            raise APIException(str(err))
1408        return self.__handle_response_status(response)
1409
1410    def __get_all(self, resource, params=None, allowed_results_per_page=__allowed_results_per_page, **kwargs):
1411        """This method will get all of the resources specified by the resource parameter, if an id or some other
1412        parameter is required for the resource, include it in the params parameter.
1413        Returns a single JSON array with all of the retrieved items."""
1414
1415        if allowed_results_per_page < 1 or allowed_results_per_page > 50:
1416            raise ValueError("Allowed results per page must be between 1 and 50")
1417
1418        start_index = 0
1419        allowed_results_per_page = 20
1420        total_results = float("inf")
1421
1422        data = []
1423
1424        while len(data) < total_results:
1425            page_response = self.__get_page(resource, start_index, params=params, **kwargs)
1426            page_json = page_response.json()
1427
1428            page_info = page_json['meta']['pageInfo']
1429            start_index = page_info['startIndex'] + allowed_results_per_page
1430            total_results = page_info.get('totalResults')
1431            page_data = page_json.get('data')
1432            data.extend(page_data)
1433
1434        return data
1435
1436    def __get_page(self, resource, start_at, params=None,  allowed_results_per_page=__allowed_results_per_page,  **kwargs):
1437        """This method will return one page of results from the specified resource type.
1438        Pass any needed parameters along
1439        The response object will be returned"""
1440        parameters = {
1441            'startAt': start_at,
1442            'maxResults': allowed_results_per_page
1443        }
1444
1445        if params is not None:
1446            for k, v in params.items():
1447                parameters[k] = v
1448
1449        try:
1450            response = self.__core.get(resource, params=parameters, **kwargs)
1451        except CoreException as err:
1452            py_jama_rest_client_logger.error(err)
1453            raise APIException(str(err))
1454        JamaClient.__handle_response_status(response)
1455        return response
1456
1457    @staticmethod
1458    def __handle_response_status(response):
1459        """ Utility method for checking http status codes.
1460        If the response code is not in the 200 range, An exception will be thrown."""
1461
1462        status = response.status_code
1463
1464        if status in range(200, 300):
1465            return status
1466
1467        if status in range(400, 500):
1468            """These are client errors. It is likely that something is wrong with the request."""
1469
1470            response_message = 'No Response'
1471
1472            try:
1473                response_json = json.loads(response.text)
1474                response_message = response_json.get('meta').get('message')
1475
1476            except json.JSONDecodeError:
1477                pass
1478
1479            # Log the error
1480            py_jama_rest_client_logger.error('API Client Error. Status: {} Message: {}'.format(status,
1481                                                                                               response_message))
1482
1483            if response_message is not None and "already exists" in response_message:
1484                raise AlreadyExistsException("Entity already exists.",
1485                                             status_code=status,
1486                                             reason=response_message)
1487
1488            if status == 401:
1489                raise UnauthorizedException("Unauthorized: check credentials and permissions.  "
1490                                            "API response message {}".format(response_message),
1491                                            status_code=status,
1492                                            reason=response_message)
1493
1494            if status == 404:
1495                raise ResourceNotFoundException("Resource not found. check host url.",
1496                                                status_code=status,
1497                                                reason=response_message)
1498
1499            if status == 429:
1500                raise TooManyRequestsException("Too many requests.  API throttling limit reached, or system under "
1501                                               "maintenance.",
1502                                               status_code=status,
1503                                               reason=response_message)
1504
1505            raise APIClientException("{} {} Client Error.  Bad Request.  "
1506                                     "API response message: {}".format(status, response.reason, response_message),
1507                                     status_code=status,
1508                                     reason=response_message)
1509
1510        if status in range(500, 600):
1511            """These are server errors and network errors."""
1512
1513            # Log The Error
1514            py_jama_rest_client_logger.error('{} Server error. {}'.format(status, response.reason))
1515            raise APIServerException("{} Server Error.".format(status),
1516                                     status_code=status,
1517                                     reason=response.reason)
1518
1519        # Catch anything unexpected
1520        py_jama_rest_client_logger.error('{} error. {}'.format(status, response.reason))
1521        raise APIException("{} error".format(status),
1522                           status_code=status,
1523                           reason=response.reason)
1524
1525    def set_allowed_results_per_page(self, allowed_results_per_page):
1526        self.__allowed_results_per_page = allowed_results_per_page
1527
1528    def get_allowed_results_per_page(self):
1529        return self.__allowed_results_per_page
class APIException(builtins.Exception):
11class APIException(Exception):
12    """This is the base class for all exceptions raised by the JamaClient"""
13
14    def __init__(self, message, status_code=None, reason=None):
15        super(APIException, self).__init__(message)
16        self.status_code = status_code
17        self.reason = reason

This is the base class for all exceptions raised by the JamaClient

APIException(message, status_code=None, reason=None)
14    def __init__(self, message, status_code=None, reason=None):
15        super(APIException, self).__init__(message)
16        self.status_code = status_code
17        self.reason = reason
Inherited Members
builtins.BaseException
with_traceback
class UnauthorizedException(APIException):
20class UnauthorizedException(APIException):
21    """This exception is thrown whenever the api returns a 401 unauthorized response."""
22    pass

This exception is thrown whenever the api returns a 401 unauthorized response.

Inherited Members
APIException
APIException
builtins.BaseException
with_traceback
class TooManyRequestsException(APIException):
25class TooManyRequestsException(APIException):
26    """This exception is thrown whenever the api returns a 429 too many requests response."""
27    pass

This exception is thrown whenever the api returns a 429 too many requests response.

Inherited Members
APIException
APIException
builtins.BaseException
with_traceback
class ResourceNotFoundException(APIException):
30class ResourceNotFoundException(APIException):
31    """This exception is raised whenever the api returns a 404 not found response."""
32    pass

This exception is raised whenever the api returns a 404 not found response.

Inherited Members
APIException
APIException
builtins.BaseException
with_traceback
class AlreadyExistsException(APIException):
35class AlreadyExistsException(APIException):
36    """This exception is thrown when the API returns a 400 response with a message that the resource already exists."""
37    pass

This exception is thrown when the API returns a 400 response with a message that the resource already exists.

Inherited Members
APIException
APIException
builtins.BaseException
with_traceback
class APIClientException(APIException):
40class APIClientException(APIException):
41    """This exception is thrown whenever a unknown 400 error is encountered."""
42    pass

This exception is thrown whenever a unknown 400 error is encountered.

Inherited Members
APIException
APIException
builtins.BaseException
with_traceback
class APIServerException(APIException):
45class APIServerException(APIException):
46    """This exception is thrown whenever an unknown 500 response is encountered."""
47    pass

This exception is thrown whenever an unknown 500 response is encountered.

Inherited Members
APIException
APIException
builtins.BaseException
with_traceback
class JamaClient:
  50class JamaClient:
  51    """A class to abstract communication with the Jama Connect API"""
  52
  53    __allowed_results_per_page = 20  # Default is 20, Max is 50. if set to greater than 50, only 50 will items return.
  54
  55    def __init__(self, host_domain,
  56                 credentials=('username|clientID', 'password|clientSecret'),
  57                 api_version='/rest/v1/',
  58                 oauth=False,
  59                 verify=True,
  60                 allowed_results_per_page=20):
  61        """Jama Client initializer
  62        :rtype: JamaClient
  63        :param host_domain: String The domain associated with the Jama Connect host
  64        :param credentials: the user name and password as a tuple or client id and client secret if using Oauth.
  65        :param api_version: valid args are '/rest/[v1|latest|labs]/'
  66        :param verify: Defaults to True, Setting this to False will skip SSL Certificate verification"""
  67        self.__credentials = credentials
  68        self.__allowed_results_per_page = allowed_results_per_page
  69        try:
  70            self.__core = Core(host_domain, credentials, api_version=api_version, oauth=oauth, verify=verify)
  71        except CoreException as err:
  72            py_jama_rest_client_logger.error(err)
  73            raise APIException(str(err))
  74
  75        # Log client creation
  76        py_jama_rest_client_logger.info('Created a new JamaClient instance. Domain: {} '
  77                                        'Connecting via Oauth: {}'.format(host_domain, oauth))
  78
  79    def get_available_endpoints(self):
  80        """
  81        Returns a list of all the available endpoints.
  82
  83        Returns: an array of available endpoints for this API
  84
  85        """
  86        try:
  87            response = self.__core.get('')
  88        except CoreException as err:
  89            py_jama_rest_client_logger.error(err)
  90            raise APIException(str(err))
  91        JamaClient.__handle_response_status(response)
  92        return response.json()['data']
  93
  94    def get_baselines(self, project_id, allowed_results_per_page=__allowed_results_per_page):
  95        """
  96        Returns a list of Baseline objects
  97        Args:
  98            project_id:  the Id of the project to fetch baselines for
  99            allowed_results_per_page: number of results per page
 100
 101        Returns: a list of Baseline objects
 102        """
 103        resource_path = 'baselines'
 104        params = {'project': project_id}
 105        baseline_data = self.__get_all(resource_path, params=params, allowed_results_per_page=allowed_results_per_page)
 106        return baseline_data
 107
 108    def get_baseline(self, baseline_id):
 109        """
 110        This method will return a baseline
 111        Args:
 112            baseline_id: the id of the baseline to fetch
 113
 114        Returns: a dictionary object representing the baseline
 115
 116        """
 117        resource_path = 'baselines/' + str(baseline_id)
 118        try:
 119            response = self.__core.get(resource_path)
 120        except CoreException as err:
 121            py_jama_rest_client_logger.error(err)
 122            raise APIException(str(err))
 123        JamaClient.__handle_response_status(response)
 124        return response.json()['data']
 125
 126    def get_baselines_versioneditems(self, baseline_id, allowed_results_per_page=__allowed_results_per_page):
 127        """
 128        Get all baseline items in a baseline with the specified ID
 129        Args:
 130            baseline_id:  The id of the baseline to fetch items for.
 131            allowed_results_per_page: Number of results per page
 132        Returns: A list of versioned items belonging to the baseline
 133        """
 134        resource_path = 'baselines/' + str(baseline_id) + '/versioneditems'
 135        baseline_items = self.__get_all(resource_path,  allowed_results_per_page=allowed_results_per_page)
 136        return baseline_items
 137
 138    def get_projects(self, allowed_results_per_page=__allowed_results_per_page):
 139        """This method will return all projects as JSON object
 140        :return: JSON Array of Item Objects.
 141        """
 142        resource_path = 'projects'
 143        project_data = self.__get_all(resource_path,  allowed_results_per_page=allowed_results_per_page)
 144        return project_data
 145
 146    def get_filter_results(self, filter_id, project_id=None, allowed_results_per_page=__allowed_results_per_page):
 147        """
 148        Get all results items for the filter with the specified ID
 149
 150        Args:
 151            filter_id: The ID of the filter to fetch the results for.
 152            project_id: Use this only for filters that run on any project, where projectScope is CURRENT
 153            allowed_results_per_page: Number of results per page
 154
 155        Returns:
 156            A List of items that match the filter.
 157
 158        """
 159        resource_path = 'filters/' + str(filter_id) + '/results'
 160        params = None
 161        if project_id is not None:
 162            params = {'project': str(project_id)}
 163        filter_results = self.__get_all(resource_path, params=params, allowed_results_per_page=allowed_results_per_page)
 164        return filter_results
 165
 166    def get_items(self, project_id, allowed_results_per_page=__allowed_results_per_page):
 167        """
 168        This method will return all items in the specified project.
 169        Args:
 170            project_id: the project ID
 171            allowed_results_per_page: number of results per page
 172
 173        Returns: a Json array of item objects
 174
 175        """
 176        resource_path = 'items'
 177        params = {'project': project_id}
 178        item_data = self.__get_all(resource_path, params=params, allowed_results_per_page=allowed_results_per_page)
 179        return item_data
 180
 181    def get_item(self, item_id):
 182        """
 183        This method will return a singular item of a specified item id
 184        Args:
 185            item_id: the item id of the item to fetch
 186
 187        Returns: a dictonary object representing the item
 188
 189        """
 190        resource_path = 'items/' + str(item_id)
 191        try:
 192            response = self.__core.get(resource_path)
 193        except CoreException as err:
 194            py_jama_rest_client_logger.error(err)
 195            raise APIException(str(err))
 196        JamaClient.__handle_response_status(response)
 197        return response.json()['data']
 198
 199    def get_item_lock(self, item_id):
 200        """
 201        Get the locked state, last locked date, and last locked by user for the item with the specified ID
 202        Args:
 203            item_id: The API ID of the item to get the lock info for.
 204
 205        Returns:
 206            A JSON object with the lock information for the item with the specified ID.
 207
 208        """
 209        resource_path = 'items/' + str(item_id) + '/lock'
 210        try:
 211            response = self.__core.get(resource_path)
 212        except CoreException as err:
 213            py_jama_rest_client_logger.error(err)
 214            raise APIException(str(err))
 215        JamaClient.__handle_response_status(response)
 216        return response.json()['data']
 217
 218    def put_item_lock(self, item_id, locked):
 219        """
 220        Update the locked state of the item with the specified ID
 221        Args:
 222            item_id: the API id of the item to be updated
 223            locked: boolean lock state to apply to this item
 224
 225        Returns:
 226            response status 200
 227
 228        """
 229        body = {
 230            "locked": locked,
 231        }
 232        resource_path = 'items/' + str(item_id) + '/lock'
 233        headers = {'content-type': 'application/json'}
 234        try:
 235            response = self.__core.put(resource_path, data=json.dumps(body), headers=headers)
 236        except CoreException as err:
 237            py_jama_rest_client_logger.error(err)
 238            raise APIException(str(err))
 239        return self.__handle_response_status(response)
 240
 241    def get_item_tags(self, item_id, allowed_results_per_page=__allowed_results_per_page):
 242        """
 243        Return all tags for the item with the specified ID
 244
 245        Args:
 246            item_id: the item id of the item to fetch
 247            allowed_results_per_page: number of results
 248
 249        Returns: a dictionary object representing the item's tags
 250
 251        """
 252        resource_path = 'items/' + str(item_id) + '/tags'
 253        item_tags = self.__get_all(resource_path,  allowed_results_per_page=allowed_results_per_page)
 254        return item_tags
 255
 256    def get_attachment(self, attachment_id):
 257        """
 258        This method will return a singular attachment of a specified attachment id
 259        Args:
 260            attachment_id: the attachment id of the attachment to fetch
 261
 262        Returns: a dictonary object representing the attachment
 263
 264        """
 265        resource_path = 'attachments/' + str(attachment_id)
 266        try:
 267            response = self.__core.get(resource_path)
 268        except CoreException as err:
 269            py_jama_rest_client_logger.error(err)
 270            raise APIException(str(err))
 271        JamaClient.__handle_response_status(response)
 272        return response.json()['data']
 273
 274    def get_abstract_items_from_doc_key(self, doc_key_list, allowed_results_per_page=__allowed_results_per_page):
 275        """ DEPRECATED INSTEAD USE get_abstract_items below.
 276        This method will take in a list of document keys and return an array of JSON Objects associated with the
 277        document keys."""
 278        resource_path = 'abstractitems'
 279        params = {'documentKey': doc_key_list}
 280        abstract_items = self.__get_all(resource_path, params=params, allowed_results_per_page=allowed_results_per_page)
 281        return abstract_items
 282
 283    def get_relationship_rule_sets(self):
 284        """
 285        This method will return all relationship rule sets across all projects of the Jama Connect instance.
 286
 287        Returns: An array of dictionary objects representing a rule set and its associated rules
 288
 289        """
 290        resource_path = 'relationshiprulesets/'
 291        rule_sets = self.__get_all(resource_path)
 292        return rule_sets
 293
 294    def get_relationship_rule_set(self, id):
 295        """
 296        This method will return the relationship rule sets by id.
 297
 298        Returns: A dictionary object representing a rule set and its associated rules
 299
 300        """
 301        resource_path = 'relationshiprulesets/' + str(id)
 302        response = self.__core.get(resource_path)
 303        JamaClient.__handle_response_status(response)
 304        return response.json()['data']
 305
 306    def get_relationship_rule_set_projects(self, id):
 307        """
 308        This method will return the projects that have a given relationship rule set defined.
 309
 310        Returns: An array of the dictionary objects representing the projects with a given rule set assigned
 311
 312        """
 313        resource_path = 'relationshiprulesets/' + str(id) + '/projects'
 314        projects = self.__get_all(resource_path)
 315        return projects
 316
 317    def get_relationship_types(self, allowed_results_per_page=__allowed_results_per_page):
 318        """
 319        This method will return all relationship types of the across all projects of the Jama Connect instance.
 320
 321        Args:
 322            allowed_results_per_page: Number of results per page
 323
 324        Returns: An array of dictionary objects
 325
 326        """
 327        resource_path = 'relationshiptypes/'
 328        item_types = self.__get_all(resource_path,  allowed_results_per_page=allowed_results_per_page)
 329        return item_types
 330
 331    def get_relationship_type(self, relationship_type_id):
 332        """
 333        Gets relationship type information for a specific relationship type id.
 334
 335        Args:
 336            relationship_type_id: The api id of the item type to fetch
 337
 338        Returns: JSON object
 339
 340        """
 341        resource_path = 'relationshiptypes/' + str(relationship_type_id)
 342        try:
 343            response = self.__core.get(resource_path)
 344        except CoreException as err:
 345            py_jama_rest_client_logger.error(err)
 346            raise APIException(str(err))
 347        JamaClient.__handle_response_status(response)
 348        return response.json()['data']
 349
 350    def get_item_types(self, allowed_results_per_page=__allowed_results_per_page):
 351        """
 352        This method will return all item types of the across all projects of the Jama Connect instance.
 353
 354        Args:
 355            allowed_results_per_page: Number of results per page
 356
 357        Returns: An array of dictionary objects
 358
 359        """
 360        resource_path = 'itemtypes/'
 361        item_types = self.__get_all(resource_path,  allowed_results_per_page=allowed_results_per_page)
 362        return item_types
 363
 364    def get_item_type(self, item_type_id):
 365        """
 366        Gets item type information for a specific item type id.
 367
 368        Args:
 369            item_type_id: The api id of the item type to fetch
 370
 371        Returns: JSON object
 372
 373        """
 374        resource_path = 'itemtypes/' + str(item_type_id)
 375        try:
 376            response = self.__core.get(resource_path)
 377        except CoreException as err:
 378            py_jama_rest_client_logger.error(err)
 379            raise APIException(str(err))
 380        JamaClient.__handle_response_status(response)
 381        return response.json()['data']
 382
 383    def get_items_synceditems(self, item_id, allowed_results_per_page=__allowed_results_per_page):
 384        """
 385        Get all synchronized items for the item with the specified ID
 386
 387        Args:
 388            item_id: The API id of the item being
 389            allowed_results_per_page: Number of results per page
 390
 391        Returns: A list of JSON Objects representing the items that are in the same synchronization group as the
 392        specified item.
 393
 394        """
 395        resource_path = 'items/' + str(item_id) + '/synceditems'
 396        synced_items = self.__get_all(resource_path,  allowed_results_per_page=allowed_results_per_page)
 397        return synced_items
 398
 399    def get_items_synceditems_status(self, item_id, synced_item_id):
 400        """
 401        Get the sync status for the synced item with the specified ID
 402
 403        Args:
 404            item_id: The id of the item to compare against
 405            synced_item_id: the id of the item to check if it is in sync
 406
 407        Returns: The response JSON from the API which contains a single field 'inSync' with a boolean value.
 408
 409        """
 410        resource_path = 'items/' + str(item_id) + '/synceditems/' + str(synced_item_id) + '/syncstatus'
 411        try:
 412            response = self.__core.get(resource_path)
 413        except CoreException as err:
 414            py_jama_rest_client_logger.error(err)
 415            raise APIException(str(err))
 416        JamaClient.__handle_response_status(response)
 417        return response.json()['data']
 418
 419    def get_item_versions(self, item_id):
 420        """
 421        Get all versions for the item with the specified ID
 422
 423        Args:
 424            item_id: the item id of the item to fetch
 425
 426        Returns: JSON array with all versions for the item
 427        """
 428        resource_path = 'items/' + str(item_id) + '/versions'
 429        versions = self.__get_all(resource_path)
 430        return versions
 431
 432    def get_item_version(self, item_id, version_num):
 433        """
 434        Get the numbered version for the item with the specified ID
 435
 436        Args:
 437            item_id: the item id of the item to fetch
 438            version_num: the version number for the item
 439
 440        Returns: a dictionary object representing the numbered version
 441        """
 442        resource_path = 'items/' + str(item_id) + '/versions/' + str(version_num)
 443        try:
 444            response = self.__core.get(resource_path)
 445        except CoreException as err:
 446            py_jama_rest_client_logger.error(err)
 447            raise APIException(str(err))
 448        JamaClient.__handle_response_status(response)
 449        return response.json()['data']
 450
 451    def get_versioned_item(self, item_id, version_num):
 452        """
 453        Get the snapshot of the item at the specified version
 454
 455        Args:
 456            item_id: the item id of the item to fetch
 457            version_num: the version number for the item
 458
 459        Returns: a dictionary object representing the versioned item
 460        """
 461        resource_path = 'items/' + str(item_id) + '/versions/' + str(version_num) + '/versioneditem'
 462        try:
 463            response = self.__core.get(resource_path)
 464        except CoreException as err:
 465            py_jama_rest_client_logger.error(err)
 466            raise APIException(str(err))
 467        JamaClient.__handle_response_status(response)
 468        return response.json()['data']
 469
 470    def get_item_versions(self, item_id, allowed_results_per_page=__allowed_results_per_page):
 471        """
 472        Get all versions for the item with the specified ID
 473
 474        Args:
 475            item_id: the item id of the item to fetch
 476            allowed_results_per_page: number of results per page
 477
 478        Returns: JSON array with all versions for the item
 479        """
 480        resource_path = 'items/' + str(item_id) + '/versions'
 481        versions = self.__get_all(resource_path,  allowed_results_per_page=allowed_results_per_page)
 482        return versions
 483
 484    def get_item_version(self, item_id, version_num):
 485        """
 486        Get the numbered version for the item with the specified ID
 487
 488        Args:
 489            item_id: the item id of the item to fetch
 490            version_num: the version number for the item
 491
 492        Returns: a dictionary object representing the numbered version
 493        """
 494        resource_path = 'items/' + str(item_id) + '/versions/' + str(version_num)
 495        response = self.__core.get(resource_path)
 496        JamaClient.__handle_response_status(response)
 497        return response.json()['data']
 498
 499    def get_versioned_item(self, item_id, version_num):
 500        """
 501        Get the snapshot of the item at the specified version
 502
 503        Args:
 504            item_id: the item id of the item to fetch
 505            version_num: the version number for the item
 506
 507        Returns: a dictionary object representing the versioned item
 508        """
 509        resource_path = 'items/' + str(item_id) + '/versions/' + str(version_num) + '/versioneditem'
 510        response = self.__core.get(resource_path)
 511        JamaClient.__handle_response_status(response)
 512        return response.json()['data']
 513
 514    def get_pick_lists(self, allowed_results_per_page=__allowed_results_per_page):
 515        """
 516        Returns a list of all the pick lists
 517
 518        Args:
 519            allowed_results_per_page: number of results per page
 520
 521        Returns: an array of dictionary objects
 522
 523        """
 524        resource_path = 'picklists/'
 525        pick_lists = self.__get_all(resource_path,  allowed_results_per_page=allowed_results_per_page)
 526        return pick_lists
 527
 528    def get_pick_list(self, pick_list_id):
 529        """
 530        Gets all a singular picklist
 531
 532        Args:
 533            pick_list_id: The API id of the pick list to fetch
 534
 535        Returns: a dictionary object representing the picklist.
 536
 537        """
 538        resource_path = 'picklists/' + str(pick_list_id)
 539        try:
 540            response = self.__core.get(resource_path)
 541        except CoreException as err:
 542            py_jama_rest_client_logger.error(err)
 543            raise APIException(str(err))
 544        JamaClient.__handle_response_status(response)
 545        return response.json()['data']
 546
 547    def get_pick_list_options(self, pick_list_id, allowed_results_per_page=__allowed_results_per_page):
 548        """
 549        Gets all all the picklist options for a single picklist
 550        Args:
 551            pick_list_id: the api id of the picklist to fetch options for.
 552            allowed_results_per_page: number of results per page
 553
 554        Returns: an array of dictionary objects that represent the picklist options.
 555
 556        """
 557        resource_path = 'picklists/' + str(pick_list_id) + '/options'
 558        pick_list_options = self.__get_all(resource_path,  allowed_results_per_page=allowed_results_per_page)
 559        return pick_list_options
 560
 561    def get_pick_list_option(self, pick_list_option_id):
 562        """
 563        Fetches a single picklist option from the API
 564        Args:
 565            pick_list_option_id: The API ID of the picklist option to fetch
 566
 567        Returns: A dictonary object representing the picklist option.
 568
 569        """
 570        resource_path = 'picklistoptions/' + str(pick_list_option_id)
 571        try:
 572            response = self.__core.get(resource_path)
 573        except CoreException as err:
 574            py_jama_rest_client_logger.error(err)
 575            raise APIException(str(err))
 576        JamaClient.__handle_response_status(response)
 577        return response.json()['data']
 578
 579    def get_relationships(self, project_id, allowed_results_per_page=__allowed_results_per_page):
 580        """
 581        Returns a list of all relationships of a specified project
 582
 583        Args:
 584            project_id: the api project id of a project
 585            allowed_results_per_page: number of results per page
 586
 587        Returns: a list of dictionary objects that represents a relationships
 588
 589        """
 590        resource_path = 'relationships'
 591        params = {'project': project_id}
 592        relationship_data = self.__get_all(resource_path, params=params,
 593                                           allowed_results_per_page=allowed_results_per_page)
 594        return relationship_data
 595
 596    def get_relationship(self, relationship_id):
 597        """
 598        Returns a specific relationship object of a specified relationship ID
 599
 600        Args:
 601            relationship_id: the api project id of a relationship
 602
 603        Returns: a dictionary object that represents a relationship
 604
 605        """
 606        resource_path = 'relationships/' + str(relationship_id)
 607        try:
 608            response = self.__core.get(resource_path)
 609        except CoreException as err:
 610            py_jama_rest_client_logger.error(err)
 611            raise APIException(str(err))
 612        JamaClient.__handle_response_status(response)
 613        return response.json()['data']
 614
 615    def get_abstract_items(self,
 616                           project=None,
 617                           item_type=None,
 618                           document_key=None,
 619                           release=None,
 620                           created_date=None,
 621                           modified_date=None,
 622                           last_activity_date=None,
 623                           contains=None,
 624                           sort_by=None):
 625        """
 626        This method will return all items that match the query parameters entered.
 627
 628        Args:
 629            project:            Array[integer]
 630            item_type:          Array[integer]
 631            document_key:       Array[string]
 632            release:            Array[integer]
 633            created_date:       Array[string]
 634            modified_date:      Array[string]
 635            last_activity_date: Array[string]
 636            contains:           Array[string]
 637            sort_by:            Array[string]
 638
 639        Returns:
 640            A JSON Array of items.
 641
 642        """
 643        resource_path = 'abstractitems'
 644
 645        # Add each parameter that is not null to the request.
 646        params = {}
 647
 648        if project is not None:
 649            params['project'] = project
 650
 651        if item_type is not None:
 652            params['itemType'] = item_type
 653
 654        if document_key is not None:
 655            params['documentKey'] = document_key
 656
 657        if release is not None:
 658            params['release'] = release
 659
 660        if created_date is not None:
 661            params['createdDate'] = created_date
 662
 663        if modified_date is not None:
 664            params['modifiedDate'] = modified_date
 665
 666        if last_activity_date is not None:
 667            params['lastActivityDate'] = last_activity_date
 668
 669        if contains is not None:
 670            params['contains'] = contains
 671
 672        if sort_by is not None:
 673            params['sortBy'] = sort_by
 674
 675        abstract_items = self.__get_all(resource_path, params=params)
 676        return abstract_items
 677
 678    def get_abstract_item(self, item_id):
 679        """
 680        This method will return an item, test plan, test cycle, test run, or attachment with the specified ID
 681        Args:
 682            item_id: the item id of the item to fetch
 683
 684        Returns: a dictonary object representing the abstract item
 685
 686        """
 687        resource_path = 'abstractitems/' + str(item_id)
 688        try:
 689            response = self.__core.get(resource_path)
 690        except CoreException as err:
 691            py_jama_rest_client_logger.error(err)
 692            raise APIException(str(err))
 693        JamaClient.__handle_response_status(response)
 694        return response.json()['data']
 695
 696    def get_abstract_item_versions(self, item_id):
 697        """
 698        Get all versions for the item with the specified ID
 699
 700        Args:
 701            item_id: the item id of the item to fetch
 702
 703        Returns: JSON array with all versions for the item
 704        """
 705        resource_path = 'abstractitems/' + str(item_id) + '/versions'
 706        versions = self.__get_all(resource_path)
 707        return versions
 708
 709    def get_abtract_item_version(self, item_id, version_num):
 710        """
 711        Get the numbered version for the item with the specified ID
 712
 713        Args:
 714            item_id: the item id of the item to fetch
 715            version_num: the version number for the item
 716
 717        Returns: a dictionary object representing the numbered version
 718        """
 719        resource_path = 'abstractitems/' + str(item_id) + '/versions/' + str(version_num)
 720        try:
 721            response = self.__core.get(resource_path)
 722        except CoreException as err:
 723            py_jama_rest_client_logger.error(err)
 724            raise APIException(str(err))
 725        JamaClient.__handle_response_status(response)
 726        return response.json()['data']
 727
 728    def get_abstract_versioned_item(self, item_id, version_num):
 729        """
 730        Get the snapshot of the item at the specified version
 731
 732        Args:
 733            item_id: the item id of the item to fetch
 734            version_num: the version number for the item
 735
 736        Returns: a dictionary object representing the versioned item
 737        """
 738        resource_path = 'abstractitems/' + str(item_id) + '/versions/' + str(version_num) + '/versioneditem'
 739        try:
 740            response = self.__core.get(resource_path)
 741        except CoreException as err:
 742            py_jama_rest_client_logger.error(err)
 743            raise APIException(str(err))
 744        JamaClient.__handle_response_status(response)
 745        return response.json()['data']
 746
 747
 748    def get_item_children(self, item_id, allowed_results_per_page=__allowed_results_per_page):
 749        """
 750        This method will return list of the child items of the item passed to the function.
 751        Args:
 752            item_id: (int) The id of the item for which children items should be fetched
 753            allowed_results_per_page: Number of results per page
 754
 755        Returns: a List of Objects that represent the children of the item passed in.
 756        """
 757        resource_path = 'items/' + str(item_id) + '/children'
 758        child_items = self.__get_all(resource_path,  allowed_results_per_page=allowed_results_per_page)
 759        return child_items
 760
 761    def get_testruns(self, test_cycle_id, allowed_results_per_page=__allowed_results_per_page):
 762        """This method will return all test runs associated with the specified test cycle.  Test runs will be returned
 763        as a list of json objects."""
 764        resource_path = 'testcycles/' + str(test_cycle_id) + '/testruns'
 765        testrun_data = self.__get_all(resource_path,  allowed_results_per_page=allowed_results_per_page)
 766        return testrun_data
 767
 768    def get_items_upstream_relationships(self, item_id, allowed_results_per_page=__allowed_results_per_page):
 769        """
 770        Returns a list of all the upstream relationships for the item with the specified ID.
 771        Args:
 772            item_id: the api id of the item
 773            allowed_results_per_page: number of results per page
 774
 775        Returns: an array of dictionary objects that represent the upstream relationships for the item.
 776
 777        """
 778        resource_path = 'items/' + str(item_id) + '/upstreamrelationships'
 779        return self.__get_all(resource_path,  allowed_results_per_page=allowed_results_per_page)
 780
 781    def get_items_downstream_related(self, item_id, allowed_results_per_page=__allowed_results_per_page):
 782        """
 783        Returns a list of all the downstream related items for the item with the specified ID.
 784
 785        Args:
 786            item_id: the api id of the item to fetch downstream items for
 787            allowed_results_per_page: number of results per page
 788
 789        Returns: an array of dictionary objects that represent the downstream related items for the specified item.
 790
 791        """
 792        resource_path = 'items/' + str(item_id) + '/downstreamrelated'
 793        return self.__get_all(resource_path,  allowed_results_per_page=allowed_results_per_page)
 794
 795    def get_items_downstream_relationships(self, item_id, allowed_results_per_page=__allowed_results_per_page):
 796        """
 797        Returns a list of all the downstream relationships for the item with the specified ID.
 798
 799        Args:
 800            item_id: the api id of the item
 801
 802        Returns: an array of dictionary objects that represent the downstream relationships for the item.
 803
 804        """
 805        resource_path = 'items/' + str(item_id) + '/downstreamrelationships'
 806        return self.__get_all(resource_path, allowed_results_per_page=allowed_results_per_page)
 807
 808    def get_items_upstream_related(self, item_id):
 809        """
 810        Returns a list of all the upstream related items for the item with the specified ID.
 811
 812        Args:
 813            item_id: the api id of the item to fetch upstream items for
 814
 815        Returns: an array of dictionary objects that represent the upstream related items for the specified item.
 816
 817         """
 818        resource_path = 'items/' + str(item_id) + '/upstreamrelated'
 819        return self.__get_all(resource_path)
 820
 821    def get_item_workflow_transitions(self, item_id):
 822        """
 823        Get all valid workflow transitions that can be made with the specified id
 824
 825        Args:
 826            item_id: the api id of the item
 827            allowed_results_per_page: number of results per page
 828
 829        Returns: an array of dictionary objects that represent the workflow transitions for the item.
 830
 831        """
 832        resource_path = 'items/' + str(item_id) + '/workflowtransitionoptions'
 833        return self.__get_all(resource_path)
 834
 835    def get_tags(self, project, allowed_results_per_page=__allowed_results_per_page):
 836        """
 837        Get all tags for the project with the specified id
 838        Args:
 839            project: The API ID of the project to fetch tags for.
 840            allowed_results_per_page: Number of results per page
 841
 842        Returns: A Json Array that contains all the tag data for the specified project.
 843
 844        """
 845        resource_path = 'tags'
 846        params = {'project': project}
 847        tag_data = self.__get_all(resource_path, params=params, allowed_results_per_page=allowed_results_per_page)
 848        return tag_data
 849
 850    def get_tagged_items(self, tag_id, allowed_results_per_page=__allowed_results_per_page):
 851        """
 852        Get all items tagged with the specified ID
 853
 854        Args:
 855            tag_id: The ID of the tag to fetch the results for.
 856            allowed_results_per_page: Number of results per page
 857
 858        Returns:
 859            A List of items that match the tag.
 860
 861        """
 862        resource_path = 'tags/' + str(tag_id) + '/items'
 863        params = None
 864        tag_results = self.__get_all(resource_path, params=params, allowed_results_per_page=allowed_results_per_page)
 865        return tag_results
 866
 867    def get_users(self, allowed_results_per_page=__allowed_results_per_page):
 868        """
 869        Gets a list of all active users visible to the current user
 870
 871        Args:
 872            allowed_results_per_page: Number of results per page
 873
 874        Returns: JSON array
 875
 876        """
 877        resource_path = 'users/'
 878        users = self.__get_all(resource_path,  allowed_results_per_page=allowed_results_per_page)
 879        return users
 880
 881    def get_user(self, user_id):
 882        """
 883        Gets a single speificed user
 884
 885        Args:
 886            user_id: user api ID
 887
 888        Returns: JSON obect
 889
 890        """
 891        resource_path = 'users/' + str(user_id)
 892        try:
 893            response = self.__core.get(resource_path)
 894        except CoreException as err:
 895            py_jama_rest_client_logger.error(err)
 896            raise APIException(str(err))
 897        return response.json()['data']
 898
 899    def get_current_user(self):
 900        """
 901        Gets a current user
 902
 903        Returns: JSON obect
 904
 905        """
 906        resource_path = 'users/current'
 907        try:
 908            response = self.__core.get(resource_path)
 909        except CoreException as err:
 910            py_jama_rest_client_logger.error(err)
 911            raise APIException(str(err))
 912        return response.json()['data']
 913
 914    def get_test_cycle(self, test_cycle_id):
 915        """
 916        This method will return JSON data about the test cycle specified by the test cycle id.
 917
 918        Args:
 919            test_cycle_id: the api id of the test cycle to fetch
 920
 921        Returns: a dictionary object that represents the test cycle
 922
 923        """
 924        resource_path = 'testcycles/' + str(test_cycle_id)
 925        try:
 926            response = self.__core.get(resource_path)
 927        except CoreException as err:
 928            py_jama_rest_client_logger.error(err)
 929            raise APIException(str(err))
 930        JamaClient.__handle_response_status(response)
 931        return response.json()['data']
 932
 933    def delete_item(self, item_id):
 934        """
 935        This method will delete an item in Jama Connect.
 936
 937        Args:
 938            item_id: The jama connect API ID of the item to be deleted
 939
 940        Returns: The success status code.
 941        """
 942        resource_path = 'items/' + str(item_id)
 943        try:
 944            response = self.__core.delete(resource_path)
 945        except CoreException as err:
 946            py_jama_rest_client_logger.error(err)
 947            raise APIException(str(err))
 948        JamaClient.__handle_response_status(response)
 949        return response.status_code
 950
 951    def delete_relationships(self, relationship_id):
 952        """
 953        Deletes a relationship with the specified relationship ID
 954
 955        Args:
 956            relationship_id: the api project id of a relationship
 957
 958        Returns: The success status code.
 959
 960        """
 961        resource_path = 'relationships/' + str(relationship_id)
 962        try:
 963            response = self.__core.delete(resource_path)
 964        except CoreException as err:
 965            py_jama_rest_client_logger.error(err)
 966            raise APIException(str(err))
 967        JamaClient.__handle_response_status(response)
 968        return response.status_code
 969
 970    def patch_item(self, item_id, patches):
 971        """
 972        This method will patch an item.
 973        Args:
 974            item_id: the API ID of the item that is to be patched
 975            patches: An array of dicts, that represent patch operations each dict should have the following entries
 976             [
 977                {
 978                    "op": string,
 979                    "path": string,
 980                    "value": {}
 981                }
 982            ]
 983
 984        Returns: The response status code
 985
 986        """
 987        resource_path = 'items/' + str(item_id)
 988        headers = {'Content-Type': 'application/json',
 989                   'Accept': 'application/json'
 990                   }
 991        data = json.dumps(patches)
 992
 993        # Make the API Call
 994        try:
 995            response = self.__core.patch(resource_path, data=data, headers=headers)
 996        except CoreException as err:
 997            py_jama_rest_client_logger.error(err)
 998            raise APIException(str(err))
 999
1000        # validate response
1001        JamaClient.__handle_response_status(response)
1002        return response.json()['meta']['status']
1003
1004    def post_user(self, username, password, first_name, last_name, email, license_type, phone=None, title=None,
1005                  location=None):
1006        """
1007        Creates a new user
1008
1009        Args:
1010            username: str
1011            password: str
1012            first_name: str
1013            last_name: str
1014            email: str
1015            phone: str - optional
1016            title: str - optional
1017            location: str - optional
1018            licenseType: enum [ NAMED, FLOATING, STAKEHOLDER, FLOATING_COLLABORATOR, RESERVED_COLLABORATOR, FLOATING_REVIEWER, RESERVED_REVIEWER, NAMED_REVIEWER, TEST_RUNNER, EXPIRING_TRIAL, INACTIVE ]
1019
1020        Returns: int of newly created user api ID
1021
1022        """
1023
1024        body = {
1025            'username': username,
1026            'password': password,
1027            'firstName': first_name,
1028            'lastName': last_name,
1029            'email': email,
1030            'phone': phone,
1031            'title': title,
1032            'location': location,
1033            'licenseType': license_type
1034        }
1035        resource_path = 'users/'
1036        headers = {'content-type': 'application/json'}
1037        try:
1038            response = self.__core.post(resource_path, data=json.dumps(body), headers=headers)
1039        except CoreException as err:
1040            py_jama_rest_client_logger.error(err)
1041            raise APIException(str(err))
1042        JamaClient.__handle_response_status(response)
1043        return response.json()['meta']['id']
1044
1045    def post_tag(self, name: str, project: int):
1046        """
1047        Create a new tag in the project with the specified ID
1048        Args:
1049            name: The display name for the tag
1050            project: The project to create the new tag in
1051
1052        Returns: The integer API ID fr the newly created Tag.
1053        """
1054        resource_path = 'tags'
1055        body = {
1056            'name': name,
1057            'project': project
1058        }
1059        headers = {'content-type': 'application/json'}
1060        try:
1061            response = self.__core.post(resource_path, data=json.dumps(body), headers=headers)
1062        except CoreException as err:
1063            py_jama_rest_client_logger.error(err)
1064            raise APIException(str(err))
1065        JamaClient.__handle_response_status(response)
1066        return response.json()['meta']['id']
1067
1068    def post_testplans_testcycles(self, testplan_id, testcycle_name, start_date, end_date, testgroups_to_include=None,
1069                                  testrun_status_to_include=None):
1070        """
1071        This method will create a new Test Cycle.
1072
1073        Args:
1074            testplan_id (int): The API_ID of the testplan to create the test cycle from.
1075            testcycle_name (str): The name you would like to set for the new Test Cycle
1076            start_date (str): Start date in 'yyyy-mm-dd' Format
1077            end_date (str): End date in 'yyyy-mm-dd' Format
1078            testgroups_to_include (int[]):  This array of integers specify the test groups to be included.
1079            testrun_status_to_include (str[]): Only valid after generating the first Test Cycle, you may choose to only
1080                generate Test Runs that were a specified status in the previous cycle. Do not specify anything to
1081                include all statuses
1082
1083        Returns:
1084            (int): Returns the integer id for the newly created testcycle, or None if something went terribly wrong.
1085        """
1086        resource_path = 'testplans/' + str(testplan_id) + '/testcycles'
1087        headers = {'content-type': 'application/json'}
1088        fields = {
1089            'name': testcycle_name,
1090            'startDate': start_date,
1091            'endDate': end_date
1092        }
1093        test_run_gen_config = {}
1094        if testgroups_to_include is not None:
1095            test_run_gen_config['testGroupsToInclude'] = testgroups_to_include
1096        if testrun_status_to_include is not None:
1097            test_run_gen_config['testRunStatusesToInclude'] = testrun_status_to_include
1098        body = {
1099            'fields': fields,
1100            'testRunGenerationConfig': test_run_gen_config
1101        }
1102
1103        # Make the API Call
1104        try:
1105            response = self.__core.post(resource_path, data=json.dumps(body), headers=headers)
1106        except CoreException as err:
1107            py_jama_rest_client_logger.error(err)
1108            raise APIException(str(err))
1109
1110        # Validate response
1111        JamaClient.__handle_response_status(response)
1112        return response.json()['meta']['id']
1113
1114    def post_item(self, project, item_type_id, child_item_type_id, location, fields, global_id=None):
1115        """ This method will post a new item to Jama Connect.
1116        :param global_id: optional param to post the item with a custom global id
1117        :param project integer representing the project to which this item is to be posted
1118        :param item_type_id integer ID of an Item Type.
1119        :param child_item_type_id integer ID of an Item Type.
1120        :param location dictionary with integer ID of the parent item or project.
1121        :param fields dictionary item field data.
1122        :return integer ID of the successfully posted item or None if there was an error."""
1123
1124        body = {
1125            "project": project,
1126            "itemType": item_type_id,
1127            "childItemType": child_item_type_id,
1128            "location": {
1129                "parent": location
1130            },
1131            "fields": fields
1132        }
1133        resource_path = 'items/'
1134        params = {}
1135
1136        # we setting a global ID?
1137        if global_id is not None:
1138            body['globalId'] = global_id
1139            params['setGlobalIdManually'] = True
1140
1141        headers = {'content-type': 'application/json'}
1142        try:
1143            response = self.__core.post(resource_path, data=json.dumps(body), headers=headers, params=params)
1144        except CoreException as err:
1145            py_jama_rest_client_logger.error(err)
1146            raise APIException(str(err))
1147        JamaClient.__handle_response_status(response)
1148        return response.json()['meta']['id']
1149
1150    def post_item_tag(self, item_id, tag_id):
1151        """
1152        Add an existing tag to the item with the specified ID
1153        Args:
1154            item_id: The API ID of the item to add a tag.
1155            tag_id: The API ID of the tag to add to the item.
1156
1157        Returns: 201 if successful
1158
1159        """
1160        body = {
1161            "tag": tag_id
1162        }
1163        resource_path = 'items/' + str(item_id) + '/tags'
1164        headers = {'content-type': 'application/json'}
1165        try:
1166            response = self.__core.post(resource_path, data=json.dumps(body), headers=headers)
1167        except CoreException as err:
1168            py_jama_rest_client_logger.error(err)
1169            raise APIException(str(err))
1170        JamaClient.__handle_response_status(response)
1171        return response.status_code
1172
1173    def post_item_sync(self, source_item: int, pool_item: int):
1174        """
1175        add an item to an existing pool of global ids
1176        Args:
1177            source_item: integer API ID of the source item, this item will adopt the global id of the
1178                         pool_item.
1179            pool_item: integer API ID of the item in the target global ID pool.
1180
1181        Returns: the integer ID of the modified source item.
1182        """
1183        body = {
1184            'item': source_item
1185        }
1186
1187        resource_path = 'items/' + str(pool_item) + '/synceditems'
1188        headers = {'content-type': 'application/json'}
1189        try:
1190            response = self.__core.post(resource_path, data=json.dumps(body), headers=headers)
1191        except CoreException as err:
1192            py_jama_rest_client_logger.error(err)
1193            raise APIException(str(err))
1194        JamaClient.__handle_response_status(response)
1195        return response.json()['meta']['id']
1196
1197    def post_relationship(self, from_item: int, to_item: int, relationship_type=None):
1198        """
1199
1200        Args:
1201            from_item: integer API id of the source item
1202            to_item: integer API id of the target item
1203            relationship_type: Optional integer API id of the relationship type to create
1204
1205        Returns: The integer ID of the newly created relationship.
1206
1207        """
1208        body = {
1209            "fromItem": from_item,
1210            "toItem": to_item,
1211        }
1212        if relationship_type is not None:
1213            body['relationshipType'] = relationship_type
1214        resource_path = 'relationships/'
1215        headers = {'content-type': 'application/json'}
1216        try:
1217            response = self.__core.post(resource_path, data=json.dumps(body), headers=headers)
1218        except CoreException as err:
1219            py_jama_rest_client_logger.error(err)
1220            raise APIException(str(err))
1221        JamaClient.__handle_response_status(response)
1222        return response.json()['meta']['id']
1223
1224    def put_relationship(self, relationship_id: int, from_item: int, to_item: int, relationship_type: int = None):
1225        """
1226
1227            Args:
1228                relationship_id: integer API id of the relationship
1229                from_item: integer API id of the source item
1230                to_item: integer API id of the target item
1231                relationship_type: Optional integer API id of the relationship type to create
1232
1233        """
1234        body = {
1235            "fromItem": from_item,
1236            "toItem": to_item
1237        }
1238        if relationship_type is not None:
1239            body['relationshipType'] = relationship_type
1240        resource_path = 'relationships/{}'.format(relationship_id)
1241        headers = {'content-type': 'application/json'}
1242        try:
1243            response = self.__core.put(resource_path, data=json.dumps(body), headers=headers)
1244        except CoreException as err:
1245            py_jama_rest_client_logger.error(err)
1246            raise APIException(str(err))
1247        JamaClient.__handle_response_status(response)
1248
1249    def post_item_attachment(self, item_id, attachment_id):
1250        """
1251        Add an existing attachment to the item with the specified ID
1252        :param item_id: this is the ID of the item
1253        :param attachment_id: The ID of the attachment
1254        :return: 201 if successful / the response status of the post operation
1255        """
1256        body = {"attachment": attachment_id}
1257        resource_path = 'items/' + str(item_id) + '/attachments'
1258        headers = {'content-type': 'application/json'}
1259        try:
1260            response = self.__core.post(resource_path, data=json.dumps(body), headers=headers)
1261        except CoreException as err:
1262            py_jama_rest_client_logger.error(err)
1263            raise APIException(str(err))
1264        JamaClient.__handle_response_status(response)
1265        return response.status_code
1266
1267    def post_project_attachment(self, project_id, name, description):
1268        """
1269        This Method will make a new attachment object in the specified project
1270        :param project_id: The integer project ID to create the attachment in.
1271        :param name:  The name of the attachment
1272        :param description: The description of the attachment
1273        :return: Returns the ID of the newly created attachment object.
1274        """
1275        body = {
1276            "fields": {
1277                "name": name,
1278                "description": description
1279            }
1280        }
1281
1282        resource_path = 'projects/' + str(project_id) + '/attachments'
1283        headers = {'content-type': 'application/json'}
1284        try:
1285            response = self.__core.post(resource_path, data=json.dumps(body), headers=headers)
1286        except CoreException as err:
1287            py_jama_rest_client_logger.error(err)
1288            raise APIException(str(err))
1289        JamaClient.__handle_response_status(response)
1290        return response.json()['meta']['id']
1291
1292    def put_item(self, project, item_id, item_type_id, child_item_type_id, location, fields):
1293        """ This method wil
1294         PUT a new item to Jama Connect.
1295        :param project integer representing the project to which this item is to be posted
1296        :param item_id integer representing the item which is to be updated
1297        :param item_type_id integer ID of an Item Type.
1298        :param child_item_type_id integer ID of an Item Type.
1299        :param location dictionary  with a key of 'item' or 'project' and an value with the ID of the parent
1300        :param fields dictionary item field data.
1301        :return integer ID of the successfully posted item or None if there was an error."""
1302
1303        body = {
1304            "project": project,
1305            "itemType": item_type_id,
1306            "childItemType": child_item_type_id,
1307            "location": {
1308                "parent": location
1309            },
1310            "fields": fields
1311        }
1312        resource_path = 'items/' + str(item_id)
1313        headers = {'content-type': 'application/json'}
1314        try:
1315            response = self.__core.put(resource_path, data=json.dumps(body), headers=headers)
1316        except CoreException as err:
1317            py_jama_rest_client_logger.error(err)
1318            raise APIException(str(err))
1319        return self.__handle_response_status(response)
1320
1321    def put_attachments_file(self, attachment_id, file_path):
1322        """
1323        Upload a file to a jama attachment
1324        :param attachment_id: the integer ID of the attachment item to which we are uploading the file
1325        :param file_path: the file path of the file to be uploaded
1326        :return: returns the status code of the call
1327        """
1328        resource_path = 'attachments/' + str(attachment_id) + '/file'
1329        with open(file_path, 'rb') as f:
1330            files = {'file': f}
1331            try:
1332                response = self.__core.put(resource_path, files=files)
1333            except CoreException as err:
1334                py_jama_rest_client_logger.error(err)
1335                raise APIException(str(err))
1336        self.__handle_response_status(response)
1337        return response.status_code
1338
1339    def put_user(self, user_id, username, password, first_name, last_name, email, phone=None, title=None,
1340                 location=None):
1341        """
1342        updates an existing user
1343
1344        Args:
1345            username: str
1346            password: str
1347            first_name: str
1348            last_name: str
1349            email: str
1350            phone: str - optional
1351            title: str - optional
1352            location: str - optional
1353
1354        Returns: api status code
1355
1356        """
1357
1358        body = {
1359            'username': username,
1360            'password': password,
1361            'firstName': first_name,
1362            'lastName': last_name,
1363            'email': email,
1364            'phone': phone,
1365            'title': title,
1366            'location': location
1367        }
1368        resource_path = 'users/' + str(user_id)
1369        headers = {'content-type': 'application/json'}
1370        try:
1371            response = self.__core.put(resource_path, data=json.dumps(body), headers=headers)
1372        except CoreException as err:
1373            py_jama_rest_client_logger.error(err)
1374            raise APIException(str(err))
1375            raise APIException
1376        return self.__handle_response_status(response)
1377
1378    def put_user_active(self, user_id, is_active):
1379        """
1380        updates an existing users active status
1381
1382        Args:
1383            is_active: boolean
1384
1385        Returns: api status code
1386
1387        """
1388        body = {
1389            'active': is_active
1390        }
1391        resource_path = 'users/' + str(user_id) + '/active'
1392        headers = {'content-type': 'application/json'}
1393        try:
1394            response = self.__core.put(resource_path, data=json.dumps(body), headers=headers)
1395        except CoreException as err:
1396            py_jama_rest_client_logger.error(err)
1397            raise APIException(str(err))
1398        return self.__handle_response_status(response)
1399
1400    def put_test_run(self, test_run_id, data=None):
1401        """ This method will post a test run to Jama through the API"""
1402        resource_path = 'testruns/' + str(test_run_id)
1403        headers = {'content-type': 'application/json'}
1404        try:
1405            response = self.__core.put(resource_path, data=data, headers=headers)
1406        except CoreException as err:
1407            py_jama_rest_client_logger.error(err)
1408            raise APIException(str(err))
1409        return self.__handle_response_status(response)
1410
1411    def __get_all(self, resource, params=None, allowed_results_per_page=__allowed_results_per_page, **kwargs):
1412        """This method will get all of the resources specified by the resource parameter, if an id or some other
1413        parameter is required for the resource, include it in the params parameter.
1414        Returns a single JSON array with all of the retrieved items."""
1415
1416        if allowed_results_per_page < 1 or allowed_results_per_page > 50:
1417            raise ValueError("Allowed results per page must be between 1 and 50")
1418
1419        start_index = 0
1420        allowed_results_per_page = 20
1421        total_results = float("inf")
1422
1423        data = []
1424
1425        while len(data) < total_results:
1426            page_response = self.__get_page(resource, start_index, params=params, **kwargs)
1427            page_json = page_response.json()
1428
1429            page_info = page_json['meta']['pageInfo']
1430            start_index = page_info['startIndex'] + allowed_results_per_page
1431            total_results = page_info.get('totalResults')
1432            page_data = page_json.get('data')
1433            data.extend(page_data)
1434
1435        return data
1436
1437    def __get_page(self, resource, start_at, params=None,  allowed_results_per_page=__allowed_results_per_page,  **kwargs):
1438        """This method will return one page of results from the specified resource type.
1439        Pass any needed parameters along
1440        The response object will be returned"""
1441        parameters = {
1442            'startAt': start_at,
1443            'maxResults': allowed_results_per_page
1444        }
1445
1446        if params is not None:
1447            for k, v in params.items():
1448                parameters[k] = v
1449
1450        try:
1451            response = self.__core.get(resource, params=parameters, **kwargs)
1452        except CoreException as err:
1453            py_jama_rest_client_logger.error(err)
1454            raise APIException(str(err))
1455        JamaClient.__handle_response_status(response)
1456        return response
1457
1458    @staticmethod
1459    def __handle_response_status(response):
1460        """ Utility method for checking http status codes.
1461        If the response code is not in the 200 range, An exception will be thrown."""
1462
1463        status = response.status_code
1464
1465        if status in range(200, 300):
1466            return status
1467
1468        if status in range(400, 500):
1469            """These are client errors. It is likely that something is wrong with the request."""
1470
1471            response_message = 'No Response'
1472
1473            try:
1474                response_json = json.loads(response.text)
1475                response_message = response_json.get('meta').get('message')
1476
1477            except json.JSONDecodeError:
1478                pass
1479
1480            # Log the error
1481            py_jama_rest_client_logger.error('API Client Error. Status: {} Message: {}'.format(status,
1482                                                                                               response_message))
1483
1484            if response_message is not None and "already exists" in response_message:
1485                raise AlreadyExistsException("Entity already exists.",
1486                                             status_code=status,
1487                                             reason=response_message)
1488
1489            if status == 401:
1490                raise UnauthorizedException("Unauthorized: check credentials and permissions.  "
1491                                            "API response message {}".format(response_message),
1492                                            status_code=status,
1493                                            reason=response_message)
1494
1495            if status == 404:
1496                raise ResourceNotFoundException("Resource not found. check host url.",
1497                                                status_code=status,
1498                                                reason=response_message)
1499
1500            if status == 429:
1501                raise TooManyRequestsException("Too many requests.  API throttling limit reached, or system under "
1502                                               "maintenance.",
1503                                               status_code=status,
1504                                               reason=response_message)
1505
1506            raise APIClientException("{} {} Client Error.  Bad Request.  "
1507                                     "API response message: {}".format(status, response.reason, response_message),
1508                                     status_code=status,
1509                                     reason=response_message)
1510
1511        if status in range(500, 600):
1512            """These are server errors and network errors."""
1513
1514            # Log The Error
1515            py_jama_rest_client_logger.error('{} Server error. {}'.format(status, response.reason))
1516            raise APIServerException("{} Server Error.".format(status),
1517                                     status_code=status,
1518                                     reason=response.reason)
1519
1520        # Catch anything unexpected
1521        py_jama_rest_client_logger.error('{} error. {}'.format(status, response.reason))
1522        raise APIException("{} error".format(status),
1523                           status_code=status,
1524                           reason=response.reason)
1525
1526    def set_allowed_results_per_page(self, allowed_results_per_page):
1527        self.__allowed_results_per_page = allowed_results_per_page
1528
1529    def get_allowed_results_per_page(self):
1530        return self.__allowed_results_per_page

A class to abstract communication with the Jama Connect API

JamaClient( host_domain, credentials=('username|clientID', 'password|clientSecret'), api_version='/rest/v1/', oauth=False, verify=True, allowed_results_per_page=20)
55    def __init__(self, host_domain,
56                 credentials=('username|clientID', 'password|clientSecret'),
57                 api_version='/rest/v1/',
58                 oauth=False,
59                 verify=True,
60                 allowed_results_per_page=20):
61        """Jama Client initializer
62        :rtype: JamaClient
63        :param host_domain: String The domain associated with the Jama Connect host
64        :param credentials: the user name and password as a tuple or client id and client secret if using Oauth.
65        :param api_version: valid args are '/rest/[v1|latest|labs]/'
66        :param verify: Defaults to True, Setting this to False will skip SSL Certificate verification"""
67        self.__credentials = credentials
68        self.__allowed_results_per_page = allowed_results_per_page
69        try:
70            self.__core = Core(host_domain, credentials, api_version=api_version, oauth=oauth, verify=verify)
71        except CoreException as err:
72            py_jama_rest_client_logger.error(err)
73            raise APIException(str(err))
74
75        # Log client creation
76        py_jama_rest_client_logger.info('Created a new JamaClient instance. Domain: {} '
77                                        'Connecting via Oauth: {}'.format(host_domain, oauth))

Jama Client initializer

Parameters
  • host_domain: String The domain associated with the Jama Connect host
  • credentials: the user name and password as a tuple or client id and client secret if using Oauth.
  • api_version: valid args are '/rest/[v1|latest|labs]/'
  • verify: Defaults to True, Setting this to False will skip SSL Certificate verification
def get_available_endpoints(self):
79    def get_available_endpoints(self):
80        """
81        Returns a list of all the available endpoints.
82
83        Returns: an array of available endpoints for this API
84
85        """
86        try:
87            response = self.__core.get('')
88        except CoreException as err:
89            py_jama_rest_client_logger.error(err)
90            raise APIException(str(err))
91        JamaClient.__handle_response_status(response)
92        return response.json()['data']

Returns a list of all the available endpoints.

Returns: an array of available endpoints for this API

def get_baselines(self, project_id, allowed_results_per_page=20):
 94    def get_baselines(self, project_id, allowed_results_per_page=__allowed_results_per_page):
 95        """
 96        Returns a list of Baseline objects
 97        Args:
 98            project_id:  the Id of the project to fetch baselines for
 99            allowed_results_per_page: number of results per page
100
101        Returns: a list of Baseline objects
102        """
103        resource_path = 'baselines'
104        params = {'project': project_id}
105        baseline_data = self.__get_all(resource_path, params=params, allowed_results_per_page=allowed_results_per_page)
106        return baseline_data

Returns a list of Baseline objects Args: project_id: the Id of the project to fetch baselines for allowed_results_per_page: number of results per page

Returns: a list of Baseline objects

def get_baseline(self, baseline_id):
108    def get_baseline(self, baseline_id):
109        """
110        This method will return a baseline
111        Args:
112            baseline_id: the id of the baseline to fetch
113
114        Returns: a dictionary object representing the baseline
115
116        """
117        resource_path = 'baselines/' + str(baseline_id)
118        try:
119            response = self.__core.get(resource_path)
120        except CoreException as err:
121            py_jama_rest_client_logger.error(err)
122            raise APIException(str(err))
123        JamaClient.__handle_response_status(response)
124        return response.json()['data']

This method will return a baseline Args: baseline_id: the id of the baseline to fetch

Returns: a dictionary object representing the baseline

def get_baselines_versioneditems(self, baseline_id, allowed_results_per_page=20):
126    def get_baselines_versioneditems(self, baseline_id, allowed_results_per_page=__allowed_results_per_page):
127        """
128        Get all baseline items in a baseline with the specified ID
129        Args:
130            baseline_id:  The id of the baseline to fetch items for.
131            allowed_results_per_page: Number of results per page
132        Returns: A list of versioned items belonging to the baseline
133        """
134        resource_path = 'baselines/' + str(baseline_id) + '/versioneditems'
135        baseline_items = self.__get_all(resource_path,  allowed_results_per_page=allowed_results_per_page)
136        return baseline_items

Get all baseline items in a baseline with the specified ID Args: baseline_id: The id of the baseline to fetch items for. allowed_results_per_page: Number of results per page Returns: A list of versioned items belonging to the baseline

def get_projects(self, allowed_results_per_page=20):
138    def get_projects(self, allowed_results_per_page=__allowed_results_per_page):
139        """This method will return all projects as JSON object
140        :return: JSON Array of Item Objects.
141        """
142        resource_path = 'projects'
143        project_data = self.__get_all(resource_path,  allowed_results_per_page=allowed_results_per_page)
144        return project_data

This method will return all projects as JSON object

Returns

JSON Array of Item Objects.

def get_filter_results(self, filter_id, project_id=None, allowed_results_per_page=20):
146    def get_filter_results(self, filter_id, project_id=None, allowed_results_per_page=__allowed_results_per_page):
147        """
148        Get all results items for the filter with the specified ID
149
150        Args:
151            filter_id: The ID of the filter to fetch the results for.
152            project_id: Use this only for filters that run on any project, where projectScope is CURRENT
153            allowed_results_per_page: Number of results per page
154
155        Returns:
156            A List of items that match the filter.
157
158        """
159        resource_path = 'filters/' + str(filter_id) + '/results'
160        params = None
161        if project_id is not None:
162            params = {'project': str(project_id)}
163        filter_results = self.__get_all(resource_path, params=params, allowed_results_per_page=allowed_results_per_page)
164        return filter_results

Get all results items for the filter with the specified ID

Args: filter_id: The ID of the filter to fetch the results for. project_id: Use this only for filters that run on any project, where projectScope is CURRENT allowed_results_per_page: Number of results per page

Returns: A List of items that match the filter.

def get_items(self, project_id, allowed_results_per_page=20):
166    def get_items(self, project_id, allowed_results_per_page=__allowed_results_per_page):
167        """
168        This method will return all items in the specified project.
169        Args:
170            project_id: the project ID
171            allowed_results_per_page: number of results per page
172
173        Returns: a Json array of item objects
174
175        """
176        resource_path = 'items'
177        params = {'project': project_id}
178        item_data = self.__get_all(resource_path, params=params, allowed_results_per_page=allowed_results_per_page)
179        return item_data

This method will return all items in the specified project. Args: project_id: the project ID allowed_results_per_page: number of results per page

Returns: a Json array of item objects

def get_item(self, item_id):
181    def get_item(self, item_id):
182        """
183        This method will return a singular item of a specified item id
184        Args:
185            item_id: the item id of the item to fetch
186
187        Returns: a dictonary object representing the item
188
189        """
190        resource_path = 'items/' + str(item_id)
191        try:
192            response = self.__core.get(resource_path)
193        except CoreException as err:
194            py_jama_rest_client_logger.error(err)
195            raise APIException(str(err))
196        JamaClient.__handle_response_status(response)
197        return response.json()['data']

This method will return a singular item of a specified item id Args: item_id: the item id of the item to fetch

Returns: a dictonary object representing the item

def get_item_lock(self, item_id):
199    def get_item_lock(self, item_id):
200        """
201        Get the locked state, last locked date, and last locked by user for the item with the specified ID
202        Args:
203            item_id: The API ID of the item to get the lock info for.
204
205        Returns:
206            A JSON object with the lock information for the item with the specified ID.
207
208        """
209        resource_path = 'items/' + str(item_id) + '/lock'
210        try:
211            response = self.__core.get(resource_path)
212        except CoreException as err:
213            py_jama_rest_client_logger.error(err)
214            raise APIException(str(err))
215        JamaClient.__handle_response_status(response)
216        return response.json()['data']

Get the locked state, last locked date, and last locked by user for the item with the specified ID Args: item_id: The API ID of the item to get the lock info for.

Returns: A JSON object with the lock information for the item with the specified ID.

def put_item_lock(self, item_id, locked):
218    def put_item_lock(self, item_id, locked):
219        """
220        Update the locked state of the item with the specified ID
221        Args:
222            item_id: the API id of the item to be updated
223            locked: boolean lock state to apply to this item
224
225        Returns:
226            response status 200
227
228        """
229        body = {
230            "locked": locked,
231        }
232        resource_path = 'items/' + str(item_id) + '/lock'
233        headers = {'content-type': 'application/json'}
234        try:
235            response = self.__core.put(resource_path, data=json.dumps(body), headers=headers)
236        except CoreException as err:
237            py_jama_rest_client_logger.error(err)
238            raise APIException(str(err))
239        return self.__handle_response_status(response)

Update the locked state of the item with the specified ID Args: item_id: the API id of the item to be updated locked: boolean lock state to apply to this item

Returns: response status 200

def get_item_tags(self, item_id, allowed_results_per_page=20):
241    def get_item_tags(self, item_id, allowed_results_per_page=__allowed_results_per_page):
242        """
243        Return all tags for the item with the specified ID
244
245        Args:
246            item_id: the item id of the item to fetch
247            allowed_results_per_page: number of results
248
249        Returns: a dictionary object representing the item's tags
250
251        """
252        resource_path = 'items/' + str(item_id) + '/tags'
253        item_tags = self.__get_all(resource_path,  allowed_results_per_page=allowed_results_per_page)
254        return item_tags

Return all tags for the item with the specified ID

Args: item_id: the item id of the item to fetch allowed_results_per_page: number of results

Returns: a dictionary object representing the item's tags

def get_attachment(self, attachment_id):
256    def get_attachment(self, attachment_id):
257        """
258        This method will return a singular attachment of a specified attachment id
259        Args:
260            attachment_id: the attachment id of the attachment to fetch
261
262        Returns: a dictonary object representing the attachment
263
264        """
265        resource_path = 'attachments/' + str(attachment_id)
266        try:
267            response = self.__core.get(resource_path)
268        except CoreException as err:
269            py_jama_rest_client_logger.error(err)
270            raise APIException(str(err))
271        JamaClient.__handle_response_status(response)
272        return response.json()['data']

This method will return a singular attachment of a specified attachment id Args: attachment_id: the attachment id of the attachment to fetch

Returns: a dictonary object representing the attachment

def get_abstract_items_from_doc_key(self, doc_key_list, allowed_results_per_page=20):
274    def get_abstract_items_from_doc_key(self, doc_key_list, allowed_results_per_page=__allowed_results_per_page):
275        """ DEPRECATED INSTEAD USE get_abstract_items below.
276        This method will take in a list of document keys and return an array of JSON Objects associated with the
277        document keys."""
278        resource_path = 'abstractitems'
279        params = {'documentKey': doc_key_list}
280        abstract_items = self.__get_all(resource_path, params=params, allowed_results_per_page=allowed_results_per_page)
281        return abstract_items

DEPRECATED INSTEAD USE get_abstract_items below. This method will take in a list of document keys and return an array of JSON Objects associated with the document keys.

def get_relationship_rule_sets(self):
283    def get_relationship_rule_sets(self):
284        """
285        This method will return all relationship rule sets across all projects of the Jama Connect instance.
286
287        Returns: An array of dictionary objects representing a rule set and its associated rules
288
289        """
290        resource_path = 'relationshiprulesets/'
291        rule_sets = self.__get_all(resource_path)
292        return rule_sets

This method will return all relationship rule sets across all projects of the Jama Connect instance.

Returns: An array of dictionary objects representing a rule set and its associated rules

def get_relationship_rule_set(self, id):
294    def get_relationship_rule_set(self, id):
295        """
296        This method will return the relationship rule sets by id.
297
298        Returns: A dictionary object representing a rule set and its associated rules
299
300        """
301        resource_path = 'relationshiprulesets/' + str(id)
302        response = self.__core.get(resource_path)
303        JamaClient.__handle_response_status(response)
304        return response.json()['data']

This method will return the relationship rule sets by id.

Returns: A dictionary object representing a rule set and its associated rules

def get_relationship_rule_set_projects(self, id):
306    def get_relationship_rule_set_projects(self, id):
307        """
308        This method will return the projects that have a given relationship rule set defined.
309
310        Returns: An array of the dictionary objects representing the projects with a given rule set assigned
311
312        """
313        resource_path = 'relationshiprulesets/' + str(id) + '/projects'
314        projects = self.__get_all(resource_path)
315        return projects

This method will return the projects that have a given relationship rule set defined.

Returns: An array of the dictionary objects representing the projects with a given rule set assigned

def get_relationship_types(self, allowed_results_per_page=20):
317    def get_relationship_types(self, allowed_results_per_page=__allowed_results_per_page):
318        """
319        This method will return all relationship types of the across all projects of the Jama Connect instance.
320
321        Args:
322            allowed_results_per_page: Number of results per page
323
324        Returns: An array of dictionary objects
325
326        """
327        resource_path = 'relationshiptypes/'
328        item_types = self.__get_all(resource_path,  allowed_results_per_page=allowed_results_per_page)
329        return item_types

This method will return all relationship types of the across all projects of the Jama Connect instance.

Args: allowed_results_per_page: Number of results per page

Returns: An array of dictionary objects

def get_relationship_type(self, relationship_type_id):
331    def get_relationship_type(self, relationship_type_id):
332        """
333        Gets relationship type information for a specific relationship type id.
334
335        Args:
336            relationship_type_id: The api id of the item type to fetch
337
338        Returns: JSON object
339
340        """
341        resource_path = 'relationshiptypes/' + str(relationship_type_id)
342        try:
343            response = self.__core.get(resource_path)
344        except CoreException as err:
345            py_jama_rest_client_logger.error(err)
346            raise APIException(str(err))
347        JamaClient.__handle_response_status(response)
348        return response.json()['data']

Gets relationship type information for a specific relationship type id.

Args: relationship_type_id: The api id of the item type to fetch

Returns: JSON object

def get_item_types(self, allowed_results_per_page=20):
350    def get_item_types(self, allowed_results_per_page=__allowed_results_per_page):
351        """
352        This method will return all item types of the across all projects of the Jama Connect instance.
353
354        Args:
355            allowed_results_per_page: Number of results per page
356
357        Returns: An array of dictionary objects
358
359        """
360        resource_path = 'itemtypes/'
361        item_types = self.__get_all(resource_path,  allowed_results_per_page=allowed_results_per_page)
362        return item_types

This method will return all item types of the across all projects of the Jama Connect instance.

Args: allowed_results_per_page: Number of results per page

Returns: An array of dictionary objects

def get_item_type(self, item_type_id):
364    def get_item_type(self, item_type_id):
365        """
366        Gets item type information for a specific item type id.
367
368        Args:
369            item_type_id: The api id of the item type to fetch
370
371        Returns: JSON object
372
373        """
374        resource_path = 'itemtypes/' + str(item_type_id)
375        try:
376            response = self.__core.get(resource_path)
377        except CoreException as err:
378            py_jama_rest_client_logger.error(err)
379            raise APIException(str(err))
380        JamaClient.__handle_response_status(response)
381        return response.json()['data']

Gets item type information for a specific item type id.

Args: item_type_id: The api id of the item type to fetch

Returns: JSON object

def get_items_synceditems(self, item_id, allowed_results_per_page=20):
383    def get_items_synceditems(self, item_id, allowed_results_per_page=__allowed_results_per_page):
384        """
385        Get all synchronized items for the item with the specified ID
386
387        Args:
388            item_id: The API id of the item being
389            allowed_results_per_page: Number of results per page
390
391        Returns: A list of JSON Objects representing the items that are in the same synchronization group as the
392        specified item.
393
394        """
395        resource_path = 'items/' + str(item_id) + '/synceditems'
396        synced_items = self.__get_all(resource_path,  allowed_results_per_page=allowed_results_per_page)
397        return synced_items

Get all synchronized items for the item with the specified ID

Args: item_id: The API id of the item being allowed_results_per_page: Number of results per page

Returns: A list of JSON Objects representing the items that are in the same synchronization group as the specified item.

def get_items_synceditems_status(self, item_id, synced_item_id):
399    def get_items_synceditems_status(self, item_id, synced_item_id):
400        """
401        Get the sync status for the synced item with the specified ID
402
403        Args:
404            item_id: The id of the item to compare against
405            synced_item_id: the id of the item to check if it is in sync
406
407        Returns: The response JSON from the API which contains a single field 'inSync' with a boolean value.
408
409        """
410        resource_path = 'items/' + str(item_id) + '/synceditems/' + str(synced_item_id) + '/syncstatus'
411        try:
412            response = self.__core.get(resource_path)
413        except CoreException as err:
414            py_jama_rest_client_logger.error(err)
415            raise APIException(str(err))
416        JamaClient.__handle_response_status(response)
417        return response.json()['data']

Get the sync status for the synced item with the specified ID

Args: item_id: The id of the item to compare against synced_item_id: the id of the item to check if it is in sync

Returns: The response JSON from the API which contains a single field 'inSync' with a boolean value.

def get_item_versions(self, item_id, allowed_results_per_page=20):
470    def get_item_versions(self, item_id, allowed_results_per_page=__allowed_results_per_page):
471        """
472        Get all versions for the item with the specified ID
473
474        Args:
475            item_id: the item id of the item to fetch
476            allowed_results_per_page: number of results per page
477
478        Returns: JSON array with all versions for the item
479        """
480        resource_path = 'items/' + str(item_id) + '/versions'
481        versions = self.__get_all(resource_path,  allowed_results_per_page=allowed_results_per_page)
482        return versions

Get all versions for the item with the specified ID

Args: item_id: the item id of the item to fetch allowed_results_per_page: number of results per page

Returns: JSON array with all versions for the item

def get_item_version(self, item_id, version_num):
484    def get_item_version(self, item_id, version_num):
485        """
486        Get the numbered version for the item with the specified ID
487
488        Args:
489            item_id: the item id of the item to fetch
490            version_num: the version number for the item
491
492        Returns: a dictionary object representing the numbered version
493        """
494        resource_path = 'items/' + str(item_id) + '/versions/' + str(version_num)
495        response = self.__core.get(resource_path)
496        JamaClient.__handle_response_status(response)
497        return response.json()['data']

Get the numbered version for the item with the specified ID

Args: item_id: the item id of the item to fetch version_num: the version number for the item

Returns: a dictionary object representing the numbered version

def get_versioned_item(self, item_id, version_num):
499    def get_versioned_item(self, item_id, version_num):
500        """
501        Get the snapshot of the item at the specified version
502
503        Args:
504            item_id: the item id of the item to fetch
505            version_num: the version number for the item
506
507        Returns: a dictionary object representing the versioned item
508        """
509        resource_path = 'items/' + str(item_id) + '/versions/' + str(version_num) + '/versioneditem'
510        response = self.__core.get(resource_path)
511        JamaClient.__handle_response_status(response)
512        return response.json()['data']

Get the snapshot of the item at the specified version

Args: item_id: the item id of the item to fetch version_num: the version number for the item

Returns: a dictionary object representing the versioned item

def get_pick_lists(self, allowed_results_per_page=20):
514    def get_pick_lists(self, allowed_results_per_page=__allowed_results_per_page):
515        """
516        Returns a list of all the pick lists
517
518        Args:
519            allowed_results_per_page: number of results per page
520
521        Returns: an array of dictionary objects
522
523        """
524        resource_path = 'picklists/'
525        pick_lists = self.__get_all(resource_path,  allowed_results_per_page=allowed_results_per_page)
526        return pick_lists

Returns a list of all the pick lists

Args: allowed_results_per_page: number of results per page

Returns: an array of dictionary objects

def get_pick_list(self, pick_list_id):
528    def get_pick_list(self, pick_list_id):
529        """
530        Gets all a singular picklist
531
532        Args:
533            pick_list_id: The API id of the pick list to fetch
534
535        Returns: a dictionary object representing the picklist.
536
537        """
538        resource_path = 'picklists/' + str(pick_list_id)
539        try:
540            response = self.__core.get(resource_path)
541        except CoreException as err:
542            py_jama_rest_client_logger.error(err)
543            raise APIException(str(err))
544        JamaClient.__handle_response_status(response)
545        return response.json()['data']

Gets all a singular picklist

Args: pick_list_id: The API id of the pick list to fetch

Returns: a dictionary object representing the picklist.

def get_pick_list_options(self, pick_list_id, allowed_results_per_page=20):
547    def get_pick_list_options(self, pick_list_id, allowed_results_per_page=__allowed_results_per_page):
548        """
549        Gets all all the picklist options for a single picklist
550        Args:
551            pick_list_id: the api id of the picklist to fetch options for.
552            allowed_results_per_page: number of results per page
553
554        Returns: an array of dictionary objects that represent the picklist options.
555
556        """
557        resource_path = 'picklists/' + str(pick_list_id) + '/options'
558        pick_list_options = self.__get_all(resource_path,  allowed_results_per_page=allowed_results_per_page)
559        return pick_list_options

Gets all all the picklist options for a single picklist Args: pick_list_id: the api id of the picklist to fetch options for. allowed_results_per_page: number of results per page

Returns: an array of dictionary objects that represent the picklist options.

def get_pick_list_option(self, pick_list_option_id):
561    def get_pick_list_option(self, pick_list_option_id):
562        """
563        Fetches a single picklist option from the API
564        Args:
565            pick_list_option_id: The API ID of the picklist option to fetch
566
567        Returns: A dictonary object representing the picklist option.
568
569        """
570        resource_path = 'picklistoptions/' + str(pick_list_option_id)
571        try:
572            response = self.__core.get(resource_path)
573        except CoreException as err:
574            py_jama_rest_client_logger.error(err)
575            raise APIException(str(err))
576        JamaClient.__handle_response_status(response)
577        return response.json()['data']

Fetches a single picklist option from the API Args: pick_list_option_id: The API ID of the picklist option to fetch

Returns: A dictonary object representing the picklist option.

def get_relationships(self, project_id, allowed_results_per_page=20):
579    def get_relationships(self, project_id, allowed_results_per_page=__allowed_results_per_page):
580        """
581        Returns a list of all relationships of a specified project
582
583        Args:
584            project_id: the api project id of a project
585            allowed_results_per_page: number of results per page
586
587        Returns: a list of dictionary objects that represents a relationships
588
589        """
590        resource_path = 'relationships'
591        params = {'project': project_id}
592        relationship_data = self.__get_all(resource_path, params=params,
593                                           allowed_results_per_page=allowed_results_per_page)
594        return relationship_data

Returns a list of all relationships of a specified project

Args: project_id: the api project id of a project allowed_results_per_page: number of results per page

Returns: a list of dictionary objects that represents a relationships

def get_relationship(self, relationship_id):
596    def get_relationship(self, relationship_id):
597        """
598        Returns a specific relationship object of a specified relationship ID
599
600        Args:
601            relationship_id: the api project id of a relationship
602
603        Returns: a dictionary object that represents a relationship
604
605        """
606        resource_path = 'relationships/' + str(relationship_id)
607        try:
608            response = self.__core.get(resource_path)
609        except CoreException as err:
610            py_jama_rest_client_logger.error(err)
611            raise APIException(str(err))
612        JamaClient.__handle_response_status(response)
613        return response.json()['data']

Returns a specific relationship object of a specified relationship ID

Args: relationship_id: the api project id of a relationship

Returns: a dictionary object that represents a relationship

def get_abstract_items( self, project=None, item_type=None, document_key=None, release=None, created_date=None, modified_date=None, last_activity_date=None, contains=None, sort_by=None):
615    def get_abstract_items(self,
616                           project=None,
617                           item_type=None,
618                           document_key=None,
619                           release=None,
620                           created_date=None,
621                           modified_date=None,
622                           last_activity_date=None,
623                           contains=None,
624                           sort_by=None):
625        """
626        This method will return all items that match the query parameters entered.
627
628        Args:
629            project:            Array[integer]
630            item_type:          Array[integer]
631            document_key:       Array[string]
632            release:            Array[integer]
633            created_date:       Array[string]
634            modified_date:      Array[string]
635            last_activity_date: Array[string]
636            contains:           Array[string]
637            sort_by:            Array[string]
638
639        Returns:
640            A JSON Array of items.
641
642        """
643        resource_path = 'abstractitems'
644
645        # Add each parameter that is not null to the request.
646        params = {}
647
648        if project is not None:
649            params['project'] = project
650
651        if item_type is not None:
652            params['itemType'] = item_type
653
654        if document_key is not None:
655            params['documentKey'] = document_key
656
657        if release is not None:
658            params['release'] = release
659
660        if created_date is not None:
661            params['createdDate'] = created_date
662
663        if modified_date is not None:
664            params['modifiedDate'] = modified_date
665
666        if last_activity_date is not None:
667            params['lastActivityDate'] = last_activity_date
668
669        if contains is not None:
670            params['contains'] = contains
671
672        if sort_by is not None:
673            params['sortBy'] = sort_by
674
675        abstract_items = self.__get_all(resource_path, params=params)
676        return abstract_items

This method will return all items that match the query parameters entered.

Args: project: Array[integer] item_type: Array[integer] document_key: Array[string] release: Array[integer] created_date: Array[string] modified_date: Array[string] last_activity_date: Array[string] contains: Array[string] sort_by: Array[string]

Returns: A JSON Array of items.

def get_abstract_item(self, item_id):
678    def get_abstract_item(self, item_id):
679        """
680        This method will return an item, test plan, test cycle, test run, or attachment with the specified ID
681        Args:
682            item_id: the item id of the item to fetch
683
684        Returns: a dictonary object representing the abstract item
685
686        """
687        resource_path = 'abstractitems/' + str(item_id)
688        try:
689            response = self.__core.get(resource_path)
690        except CoreException as err:
691            py_jama_rest_client_logger.error(err)
692            raise APIException(str(err))
693        JamaClient.__handle_response_status(response)
694        return response.json()['data']

This method will return an item, test plan, test cycle, test run, or attachment with the specified ID Args: item_id: the item id of the item to fetch

Returns: a dictonary object representing the abstract item

def get_abstract_item_versions(self, item_id):
696    def get_abstract_item_versions(self, item_id):
697        """
698        Get all versions for the item with the specified ID
699
700        Args:
701            item_id: the item id of the item to fetch
702
703        Returns: JSON array with all versions for the item
704        """
705        resource_path = 'abstractitems/' + str(item_id) + '/versions'
706        versions = self.__get_all(resource_path)
707        return versions

Get all versions for the item with the specified ID

Args: item_id: the item id of the item to fetch

Returns: JSON array with all versions for the item

def get_abtract_item_version(self, item_id, version_num):
709    def get_abtract_item_version(self, item_id, version_num):
710        """
711        Get the numbered version for the item with the specified ID
712
713        Args:
714            item_id: the item id of the item to fetch
715            version_num: the version number for the item
716
717        Returns: a dictionary object representing the numbered version
718        """
719        resource_path = 'abstractitems/' + str(item_id) + '/versions/' + str(version_num)
720        try:
721            response = self.__core.get(resource_path)
722        except CoreException as err:
723            py_jama_rest_client_logger.error(err)
724            raise APIException(str(err))
725        JamaClient.__handle_response_status(response)
726        return response.json()['data']

Get the numbered version for the item with the specified ID

Args: item_id: the item id of the item to fetch version_num: the version number for the item

Returns: a dictionary object representing the numbered version

def get_abstract_versioned_item(self, item_id, version_num):
728    def get_abstract_versioned_item(self, item_id, version_num):
729        """
730        Get the snapshot of the item at the specified version
731
732        Args:
733            item_id: the item id of the item to fetch
734            version_num: the version number for the item
735
736        Returns: a dictionary object representing the versioned item
737        """
738        resource_path = 'abstractitems/' + str(item_id) + '/versions/' + str(version_num) + '/versioneditem'
739        try:
740            response = self.__core.get(resource_path)
741        except CoreException as err:
742            py_jama_rest_client_logger.error(err)
743            raise APIException(str(err))
744        JamaClient.__handle_response_status(response)
745        return response.json()['data']

Get the snapshot of the item at the specified version

Args: item_id: the item id of the item to fetch version_num: the version number for the item

Returns: a dictionary object representing the versioned item

def get_item_children(self, item_id, allowed_results_per_page=20):
748    def get_item_children(self, item_id, allowed_results_per_page=__allowed_results_per_page):
749        """
750        This method will return list of the child items of the item passed to the function.
751        Args:
752            item_id: (int) The id of the item for which children items should be fetched
753            allowed_results_per_page: Number of results per page
754
755        Returns: a List of Objects that represent the children of the item passed in.
756        """
757        resource_path = 'items/' + str(item_id) + '/children'
758        child_items = self.__get_all(resource_path,  allowed_results_per_page=allowed_results_per_page)
759        return child_items

This method will return list of the child items of the item passed to the function. Args: item_id: (int) The id of the item for which children items should be fetched allowed_results_per_page: Number of results per page

Returns: a List of Objects that represent the children of the item passed in.

def get_testruns(self, test_cycle_id, allowed_results_per_page=20):
761    def get_testruns(self, test_cycle_id, allowed_results_per_page=__allowed_results_per_page):
762        """This method will return all test runs associated with the specified test cycle.  Test runs will be returned
763        as a list of json objects."""
764        resource_path = 'testcycles/' + str(test_cycle_id) + '/testruns'
765        testrun_data = self.__get_all(resource_path,  allowed_results_per_page=allowed_results_per_page)
766        return testrun_data

This method will return all test runs associated with the specified test cycle. Test runs will be returned as a list of json objects.

def get_items_upstream_relationships(self, item_id, allowed_results_per_page=20):
768    def get_items_upstream_relationships(self, item_id, allowed_results_per_page=__allowed_results_per_page):
769        """
770        Returns a list of all the upstream relationships for the item with the specified ID.
771        Args:
772            item_id: the api id of the item
773            allowed_results_per_page: number of results per page
774
775        Returns: an array of dictionary objects that represent the upstream relationships for the item.
776
777        """
778        resource_path = 'items/' + str(item_id) + '/upstreamrelationships'
779        return self.__get_all(resource_path,  allowed_results_per_page=allowed_results_per_page)

Returns a list of all the upstream relationships for the item with the specified ID. Args: item_id: the api id of the item allowed_results_per_page: number of results per page

Returns: an array of dictionary objects that represent the upstream relationships for the item.

def get_items_downstream_relationships(self, item_id, allowed_results_per_page=20):
795    def get_items_downstream_relationships(self, item_id, allowed_results_per_page=__allowed_results_per_page):
796        """
797        Returns a list of all the downstream relationships for the item with the specified ID.
798
799        Args:
800            item_id: the api id of the item
801
802        Returns: an array of dictionary objects that represent the downstream relationships for the item.
803
804        """
805        resource_path = 'items/' + str(item_id) + '/downstreamrelationships'
806        return self.__get_all(resource_path, allowed_results_per_page=allowed_results_per_page)

Returns a list of all the downstream relationships for the item with the specified ID.

Args: item_id: the api id of the item

Returns: an array of dictionary objects that represent the downstream relationships for the item.

def get_item_workflow_transitions(self, item_id):
821    def get_item_workflow_transitions(self, item_id):
822        """
823        Get all valid workflow transitions that can be made with the specified id
824
825        Args:
826            item_id: the api id of the item
827            allowed_results_per_page: number of results per page
828
829        Returns: an array of dictionary objects that represent the workflow transitions for the item.
830
831        """
832        resource_path = 'items/' + str(item_id) + '/workflowtransitionoptions'
833        return self.__get_all(resource_path)

Get all valid workflow transitions that can be made with the specified id

Args: item_id: the api id of the item allowed_results_per_page: number of results per page

Returns: an array of dictionary objects that represent the workflow transitions for the item.

def get_tags(self, project, allowed_results_per_page=20):
835    def get_tags(self, project, allowed_results_per_page=__allowed_results_per_page):
836        """
837        Get all tags for the project with the specified id
838        Args:
839            project: The API ID of the project to fetch tags for.
840            allowed_results_per_page: Number of results per page
841
842        Returns: A Json Array that contains all the tag data for the specified project.
843
844        """
845        resource_path = 'tags'
846        params = {'project': project}
847        tag_data = self.__get_all(resource_path, params=params, allowed_results_per_page=allowed_results_per_page)
848        return tag_data

Get all tags for the project with the specified id Args: project: The API ID of the project to fetch tags for. allowed_results_per_page: Number of results per page

Returns: A Json Array that contains all the tag data for the specified project.

def get_tagged_items(self, tag_id, allowed_results_per_page=20):
850    def get_tagged_items(self, tag_id, allowed_results_per_page=__allowed_results_per_page):
851        """
852        Get all items tagged with the specified ID
853
854        Args:
855            tag_id: The ID of the tag to fetch the results for.
856            allowed_results_per_page: Number of results per page
857
858        Returns:
859            A List of items that match the tag.
860
861        """
862        resource_path = 'tags/' + str(tag_id) + '/items'
863        params = None
864        tag_results = self.__get_all(resource_path, params=params, allowed_results_per_page=allowed_results_per_page)
865        return tag_results

Get all items tagged with the specified ID

Args: tag_id: The ID of the tag to fetch the results for. allowed_results_per_page: Number of results per page

Returns: A List of items that match the tag.

def get_users(self, allowed_results_per_page=20):
867    def get_users(self, allowed_results_per_page=__allowed_results_per_page):
868        """
869        Gets a list of all active users visible to the current user
870
871        Args:
872            allowed_results_per_page: Number of results per page
873
874        Returns: JSON array
875
876        """
877        resource_path = 'users/'
878        users = self.__get_all(resource_path,  allowed_results_per_page=allowed_results_per_page)
879        return users

Gets a list of all active users visible to the current user

Args: allowed_results_per_page: Number of results per page

Returns: JSON array

def get_user(self, user_id):
881    def get_user(self, user_id):
882        """
883        Gets a single speificed user
884
885        Args:
886            user_id: user api ID
887
888        Returns: JSON obect
889
890        """
891        resource_path = 'users/' + str(user_id)
892        try:
893            response = self.__core.get(resource_path)
894        except CoreException as err:
895            py_jama_rest_client_logger.error(err)
896            raise APIException(str(err))
897        return response.json()['data']

Gets a single speificed user

Args: user_id: user api ID

Returns: JSON obect

def get_current_user(self):
899    def get_current_user(self):
900        """
901        Gets a current user
902
903        Returns: JSON obect
904
905        """
906        resource_path = 'users/current'
907        try:
908            response = self.__core.get(resource_path)
909        except CoreException as err:
910            py_jama_rest_client_logger.error(err)
911            raise APIException(str(err))
912        return response.json()['data']

Gets a current user

Returns: JSON obect

def get_test_cycle(self, test_cycle_id):
914    def get_test_cycle(self, test_cycle_id):
915        """
916        This method will return JSON data about the test cycle specified by the test cycle id.
917
918        Args:
919            test_cycle_id: the api id of the test cycle to fetch
920
921        Returns: a dictionary object that represents the test cycle
922
923        """
924        resource_path = 'testcycles/' + str(test_cycle_id)
925        try:
926            response = self.__core.get(resource_path)
927        except CoreException as err:
928            py_jama_rest_client_logger.error(err)
929            raise APIException(str(err))
930        JamaClient.__handle_response_status(response)
931        return response.json()['data']

This method will return JSON data about the test cycle specified by the test cycle id.

Args: test_cycle_id: the api id of the test cycle to fetch

Returns: a dictionary object that represents the test cycle

def delete_item(self, item_id):
933    def delete_item(self, item_id):
934        """
935        This method will delete an item in Jama Connect.
936
937        Args:
938            item_id: The jama connect API ID of the item to be deleted
939
940        Returns: The success status code.
941        """
942        resource_path = 'items/' + str(item_id)
943        try:
944            response = self.__core.delete(resource_path)
945        except CoreException as err:
946            py_jama_rest_client_logger.error(err)
947            raise APIException(str(err))
948        JamaClient.__handle_response_status(response)
949        return response.status_code

This method will delete an item in Jama Connect.

Args: item_id: The jama connect API ID of the item to be deleted

Returns: The success status code.

def delete_relationships(self, relationship_id):
951    def delete_relationships(self, relationship_id):
952        """
953        Deletes a relationship with the specified relationship ID
954
955        Args:
956            relationship_id: the api project id of a relationship
957
958        Returns: The success status code.
959
960        """
961        resource_path = 'relationships/' + str(relationship_id)
962        try:
963            response = self.__core.delete(resource_path)
964        except CoreException as err:
965            py_jama_rest_client_logger.error(err)
966            raise APIException(str(err))
967        JamaClient.__handle_response_status(response)
968        return response.status_code

Deletes a relationship with the specified relationship ID

Args: relationship_id: the api project id of a relationship

Returns: The success status code.

def patch_item(self, item_id, patches):
 970    def patch_item(self, item_id, patches):
 971        """
 972        This method will patch an item.
 973        Args:
 974            item_id: the API ID of the item that is to be patched
 975            patches: An array of dicts, that represent patch operations each dict should have the following entries
 976             [
 977                {
 978                    "op": string,
 979                    "path": string,
 980                    "value": {}
 981                }
 982            ]
 983
 984        Returns: The response status code
 985
 986        """
 987        resource_path = 'items/' + str(item_id)
 988        headers = {'Content-Type': 'application/json',
 989                   'Accept': 'application/json'
 990                   }
 991        data = json.dumps(patches)
 992
 993        # Make the API Call
 994        try:
 995            response = self.__core.patch(resource_path, data=data, headers=headers)
 996        except CoreException as err:
 997            py_jama_rest_client_logger.error(err)
 998            raise APIException(str(err))
 999
1000        # validate response
1001        JamaClient.__handle_response_status(response)
1002        return response.json()['meta']['status']

This method will patch an item. Args: item_id: the API ID of the item that is to be patched patches: An array of dicts, that represent patch operations each dict should have the following entries [ { "op": string, "path": string, "value": {} } ]

Returns: The response status code

def post_user( self, username, password, first_name, last_name, email, license_type, phone=None, title=None, location=None):
1004    def post_user(self, username, password, first_name, last_name, email, license_type, phone=None, title=None,
1005                  location=None):
1006        """
1007        Creates a new user
1008
1009        Args:
1010            username: str
1011            password: str
1012            first_name: str
1013            last_name: str
1014            email: str
1015            phone: str - optional
1016            title: str - optional
1017            location: str - optional
1018            licenseType: enum [ NAMED, FLOATING, STAKEHOLDER, FLOATING_COLLABORATOR, RESERVED_COLLABORATOR, FLOATING_REVIEWER, RESERVED_REVIEWER, NAMED_REVIEWER, TEST_RUNNER, EXPIRING_TRIAL, INACTIVE ]
1019
1020        Returns: int of newly created user api ID
1021
1022        """
1023
1024        body = {
1025            'username': username,
1026            'password': password,
1027            'firstName': first_name,
1028            'lastName': last_name,
1029            'email': email,
1030            'phone': phone,
1031            'title': title,
1032            'location': location,
1033            'licenseType': license_type
1034        }
1035        resource_path = 'users/'
1036        headers = {'content-type': 'application/json'}
1037        try:
1038            response = self.__core.post(resource_path, data=json.dumps(body), headers=headers)
1039        except CoreException as err:
1040            py_jama_rest_client_logger.error(err)
1041            raise APIException(str(err))
1042        JamaClient.__handle_response_status(response)
1043        return response.json()['meta']['id']

Creates a new user

Args: username: str password: str first_name: str last_name: str email: str phone: str - optional title: str - optional location: str - optional licenseType: enum [ NAMED, FLOATING, STAKEHOLDER, FLOATING_COLLABORATOR, RESERVED_COLLABORATOR, FLOATING_REVIEWER, RESERVED_REVIEWER, NAMED_REVIEWER, TEST_RUNNER, EXPIRING_TRIAL, INACTIVE ]

Returns: int of newly created user api ID

def post_tag(self, name: str, project: int):
1045    def post_tag(self, name: str, project: int):
1046        """
1047        Create a new tag in the project with the specified ID
1048        Args:
1049            name: The display name for the tag
1050            project: The project to create the new tag in
1051
1052        Returns: The integer API ID fr the newly created Tag.
1053        """
1054        resource_path = 'tags'
1055        body = {
1056            'name': name,
1057            'project': project
1058        }
1059        headers = {'content-type': 'application/json'}
1060        try:
1061            response = self.__core.post(resource_path, data=json.dumps(body), headers=headers)
1062        except CoreException as err:
1063            py_jama_rest_client_logger.error(err)
1064            raise APIException(str(err))
1065        JamaClient.__handle_response_status(response)
1066        return response.json()['meta']['id']

Create a new tag in the project with the specified ID Args: name: The display name for the tag project: The project to create the new tag in

Returns: The integer API ID fr the newly created Tag.

def post_testplans_testcycles( self, testplan_id, testcycle_name, start_date, end_date, testgroups_to_include=None, testrun_status_to_include=None):
1068    def post_testplans_testcycles(self, testplan_id, testcycle_name, start_date, end_date, testgroups_to_include=None,
1069                                  testrun_status_to_include=None):
1070        """
1071        This method will create a new Test Cycle.
1072
1073        Args:
1074            testplan_id (int): The API_ID of the testplan to create the test cycle from.
1075            testcycle_name (str): The name you would like to set for the new Test Cycle
1076            start_date (str): Start date in 'yyyy-mm-dd' Format
1077            end_date (str): End date in 'yyyy-mm-dd' Format
1078            testgroups_to_include (int[]):  This array of integers specify the test groups to be included.
1079            testrun_status_to_include (str[]): Only valid after generating the first Test Cycle, you may choose to only
1080                generate Test Runs that were a specified status in the previous cycle. Do not specify anything to
1081                include all statuses
1082
1083        Returns:
1084            (int): Returns the integer id for the newly created testcycle, or None if something went terribly wrong.
1085        """
1086        resource_path = 'testplans/' + str(testplan_id) + '/testcycles'
1087        headers = {'content-type': 'application/json'}
1088        fields = {
1089            'name': testcycle_name,
1090            'startDate': start_date,
1091            'endDate': end_date
1092        }
1093        test_run_gen_config = {}
1094        if testgroups_to_include is not None:
1095            test_run_gen_config['testGroupsToInclude'] = testgroups_to_include
1096        if testrun_status_to_include is not None:
1097            test_run_gen_config['testRunStatusesToInclude'] = testrun_status_to_include
1098        body = {
1099            'fields': fields,
1100            'testRunGenerationConfig': test_run_gen_config
1101        }
1102
1103        # Make the API Call
1104        try:
1105            response = self.__core.post(resource_path, data=json.dumps(body), headers=headers)
1106        except CoreException as err:
1107            py_jama_rest_client_logger.error(err)
1108            raise APIException(str(err))
1109
1110        # Validate response
1111        JamaClient.__handle_response_status(response)
1112        return response.json()['meta']['id']

This method will create a new Test Cycle.

Args: testplan_id (int): The API_ID of the testplan to create the test cycle from. testcycle_name (str): The name you would like to set for the new Test Cycle start_date (str): Start date in 'yyyy-mm-dd' Format end_date (str): End date in 'yyyy-mm-dd' Format testgroups_to_include (int[]): This array of integers specify the test groups to be included. testrun_status_to_include (str[]): Only valid after generating the first Test Cycle, you may choose to only generate Test Runs that were a specified status in the previous cycle. Do not specify anything to include all statuses

Returns: (int): Returns the integer id for the newly created testcycle, or None if something went terribly wrong.

def post_item( self, project, item_type_id, child_item_type_id, location, fields, global_id=None):
1114    def post_item(self, project, item_type_id, child_item_type_id, location, fields, global_id=None):
1115        """ This method will post a new item to Jama Connect.
1116        :param global_id: optional param to post the item with a custom global id
1117        :param project integer representing the project to which this item is to be posted
1118        :param item_type_id integer ID of an Item Type.
1119        :param child_item_type_id integer ID of an Item Type.
1120        :param location dictionary with integer ID of the parent item or project.
1121        :param fields dictionary item field data.
1122        :return integer ID of the successfully posted item or None if there was an error."""
1123
1124        body = {
1125            "project": project,
1126            "itemType": item_type_id,
1127            "childItemType": child_item_type_id,
1128            "location": {
1129                "parent": location
1130            },
1131            "fields": fields
1132        }
1133        resource_path = 'items/'
1134        params = {}
1135
1136        # we setting a global ID?
1137        if global_id is not None:
1138            body['globalId'] = global_id
1139            params['setGlobalIdManually'] = True
1140
1141        headers = {'content-type': 'application/json'}
1142        try:
1143            response = self.__core.post(resource_path, data=json.dumps(body), headers=headers, params=params)
1144        except CoreException as err:
1145            py_jama_rest_client_logger.error(err)
1146            raise APIException(str(err))
1147        JamaClient.__handle_response_status(response)
1148        return response.json()['meta']['id']

This method will post a new item to Jama Connect.

Parameters
  • global_id: optional param to post the item with a custom global id :param project integer representing the project to which this item is to be posted :param item_type_id integer ID of an Item Type. :param child_item_type_id integer ID of an Item Type. :param location dictionary with integer ID of the parent item or project. :param fields dictionary item field data. :return integer ID of the successfully posted item or None if there was an error.
def post_item_tag(self, item_id, tag_id):
1150    def post_item_tag(self, item_id, tag_id):
1151        """
1152        Add an existing tag to the item with the specified ID
1153        Args:
1154            item_id: The API ID of the item to add a tag.
1155            tag_id: The API ID of the tag to add to the item.
1156
1157        Returns: 201 if successful
1158
1159        """
1160        body = {
1161            "tag": tag_id
1162        }
1163        resource_path = 'items/' + str(item_id) + '/tags'
1164        headers = {'content-type': 'application/json'}
1165        try:
1166            response = self.__core.post(resource_path, data=json.dumps(body), headers=headers)
1167        except CoreException as err:
1168            py_jama_rest_client_logger.error(err)
1169            raise APIException(str(err))
1170        JamaClient.__handle_response_status(response)
1171        return response.status_code

Add an existing tag to the item with the specified ID Args: item_id: The API ID of the item to add a tag. tag_id: The API ID of the tag to add to the item.

Returns: 201 if successful

def post_item_sync(self, source_item: int, pool_item: int):
1173    def post_item_sync(self, source_item: int, pool_item: int):
1174        """
1175        add an item to an existing pool of global ids
1176        Args:
1177            source_item: integer API ID of the source item, this item will adopt the global id of the
1178                         pool_item.
1179            pool_item: integer API ID of the item in the target global ID pool.
1180
1181        Returns: the integer ID of the modified source item.
1182        """
1183        body = {
1184            'item': source_item
1185        }
1186
1187        resource_path = 'items/' + str(pool_item) + '/synceditems'
1188        headers = {'content-type': 'application/json'}
1189        try:
1190            response = self.__core.post(resource_path, data=json.dumps(body), headers=headers)
1191        except CoreException as err:
1192            py_jama_rest_client_logger.error(err)
1193            raise APIException(str(err))
1194        JamaClient.__handle_response_status(response)
1195        return response.json()['meta']['id']

add an item to an existing pool of global ids Args: source_item: integer API ID of the source item, this item will adopt the global id of the pool_item. pool_item: integer API ID of the item in the target global ID pool.

Returns: the integer ID of the modified source item.

def post_relationship(self, from_item: int, to_item: int, relationship_type=None):
1197    def post_relationship(self, from_item: int, to_item: int, relationship_type=None):
1198        """
1199
1200        Args:
1201            from_item: integer API id of the source item
1202            to_item: integer API id of the target item
1203            relationship_type: Optional integer API id of the relationship type to create
1204
1205        Returns: The integer ID of the newly created relationship.
1206
1207        """
1208        body = {
1209            "fromItem": from_item,
1210            "toItem": to_item,
1211        }
1212        if relationship_type is not None:
1213            body['relationshipType'] = relationship_type
1214        resource_path = 'relationships/'
1215        headers = {'content-type': 'application/json'}
1216        try:
1217            response = self.__core.post(resource_path, data=json.dumps(body), headers=headers)
1218        except CoreException as err:
1219            py_jama_rest_client_logger.error(err)
1220            raise APIException(str(err))
1221        JamaClient.__handle_response_status(response)
1222        return response.json()['meta']['id']

Args: from_item: integer API id of the source item to_item: integer API id of the target item relationship_type: Optional integer API id of the relationship type to create

Returns: The integer ID of the newly created relationship.

def put_relationship( self, relationship_id: int, from_item: int, to_item: int, relationship_type: int = None):
1224    def put_relationship(self, relationship_id: int, from_item: int, to_item: int, relationship_type: int = None):
1225        """
1226
1227            Args:
1228                relationship_id: integer API id of the relationship
1229                from_item: integer API id of the source item
1230                to_item: integer API id of the target item
1231                relationship_type: Optional integer API id of the relationship type to create
1232
1233        """
1234        body = {
1235            "fromItem": from_item,
1236            "toItem": to_item
1237        }
1238        if relationship_type is not None:
1239            body['relationshipType'] = relationship_type
1240        resource_path = 'relationships/{}'.format(relationship_id)
1241        headers = {'content-type': 'application/json'}
1242        try:
1243            response = self.__core.put(resource_path, data=json.dumps(body), headers=headers)
1244        except CoreException as err:
1245            py_jama_rest_client_logger.error(err)
1246            raise APIException(str(err))
1247        JamaClient.__handle_response_status(response)

Args: relationship_id: integer API id of the relationship from_item: integer API id of the source item to_item: integer API id of the target item relationship_type: Optional integer API id of the relationship type to create

def post_item_attachment(self, item_id, attachment_id):
1249    def post_item_attachment(self, item_id, attachment_id):
1250        """
1251        Add an existing attachment to the item with the specified ID
1252        :param item_id: this is the ID of the item
1253        :param attachment_id: The ID of the attachment
1254        :return: 201 if successful / the response status of the post operation
1255        """
1256        body = {"attachment": attachment_id}
1257        resource_path = 'items/' + str(item_id) + '/attachments'
1258        headers = {'content-type': 'application/json'}
1259        try:
1260            response = self.__core.post(resource_path, data=json.dumps(body), headers=headers)
1261        except CoreException as err:
1262            py_jama_rest_client_logger.error(err)
1263            raise APIException(str(err))
1264        JamaClient.__handle_response_status(response)
1265        return response.status_code

Add an existing attachment to the item with the specified ID

Parameters
  • item_id: this is the ID of the item
  • attachment_id: The ID of the attachment
Returns

201 if successful / the response status of the post operation

def post_project_attachment(self, project_id, name, description):
1267    def post_project_attachment(self, project_id, name, description):
1268        """
1269        This Method will make a new attachment object in the specified project
1270        :param project_id: The integer project ID to create the attachment in.
1271        :param name:  The name of the attachment
1272        :param description: The description of the attachment
1273        :return: Returns the ID of the newly created attachment object.
1274        """
1275        body = {
1276            "fields": {
1277                "name": name,
1278                "description": description
1279            }
1280        }
1281
1282        resource_path = 'projects/' + str(project_id) + '/attachments'
1283        headers = {'content-type': 'application/json'}
1284        try:
1285            response = self.__core.post(resource_path, data=json.dumps(body), headers=headers)
1286        except CoreException as err:
1287            py_jama_rest_client_logger.error(err)
1288            raise APIException(str(err))
1289        JamaClient.__handle_response_status(response)
1290        return response.json()['meta']['id']

This Method will make a new attachment object in the specified project

Parameters
  • project_id: The integer project ID to create the attachment in.
  • name: The name of the attachment
  • description: The description of the attachment
Returns

Returns the ID of the newly created attachment object.

def put_item( self, project, item_id, item_type_id, child_item_type_id, location, fields):
1292    def put_item(self, project, item_id, item_type_id, child_item_type_id, location, fields):
1293        """ This method wil
1294         PUT a new item to Jama Connect.
1295        :param project integer representing the project to which this item is to be posted
1296        :param item_id integer representing the item which is to be updated
1297        :param item_type_id integer ID of an Item Type.
1298        :param child_item_type_id integer ID of an Item Type.
1299        :param location dictionary  with a key of 'item' or 'project' and an value with the ID of the parent
1300        :param fields dictionary item field data.
1301        :return integer ID of the successfully posted item or None if there was an error."""
1302
1303        body = {
1304            "project": project,
1305            "itemType": item_type_id,
1306            "childItemType": child_item_type_id,
1307            "location": {
1308                "parent": location
1309            },
1310            "fields": fields
1311        }
1312        resource_path = 'items/' + str(item_id)
1313        headers = {'content-type': 'application/json'}
1314        try:
1315            response = self.__core.put(resource_path, data=json.dumps(body), headers=headers)
1316        except CoreException as err:
1317            py_jama_rest_client_logger.error(err)
1318            raise APIException(str(err))
1319        return self.__handle_response_status(response)

This method wil PUT a new item to Jama Connect. :param project integer representing the project to which this item is to be posted :param item_id integer representing the item which is to be updated :param item_type_id integer ID of an Item Type. :param child_item_type_id integer ID of an Item Type. :param location dictionary with a key of 'item' or 'project' and an value with the ID of the parent :param fields dictionary item field data. :return integer ID of the successfully posted item or None if there was an error.

def put_attachments_file(self, attachment_id, file_path):
1321    def put_attachments_file(self, attachment_id, file_path):
1322        """
1323        Upload a file to a jama attachment
1324        :param attachment_id: the integer ID of the attachment item to which we are uploading the file
1325        :param file_path: the file path of the file to be uploaded
1326        :return: returns the status code of the call
1327        """
1328        resource_path = 'attachments/' + str(attachment_id) + '/file'
1329        with open(file_path, 'rb') as f:
1330            files = {'file': f}
1331            try:
1332                response = self.__core.put(resource_path, files=files)
1333            except CoreException as err:
1334                py_jama_rest_client_logger.error(err)
1335                raise APIException(str(err))
1336        self.__handle_response_status(response)
1337        return response.status_code

Upload a file to a jama attachment

Parameters
  • attachment_id: the integer ID of the attachment item to which we are uploading the file
  • file_path: the file path of the file to be uploaded
Returns

returns the status code of the call

def put_user( self, user_id, username, password, first_name, last_name, email, phone=None, title=None, location=None):
1339    def put_user(self, user_id, username, password, first_name, last_name, email, phone=None, title=None,
1340                 location=None):
1341        """
1342        updates an existing user
1343
1344        Args:
1345            username: str
1346            password: str
1347            first_name: str
1348            last_name: str
1349            email: str
1350            phone: str - optional
1351            title: str - optional
1352            location: str - optional
1353
1354        Returns: api status code
1355
1356        """
1357
1358        body = {
1359            'username': username,
1360            'password': password,
1361            'firstName': first_name,
1362            'lastName': last_name,
1363            'email': email,
1364            'phone': phone,
1365            'title': title,
1366            'location': location
1367        }
1368        resource_path = 'users/' + str(user_id)
1369        headers = {'content-type': 'application/json'}
1370        try:
1371            response = self.__core.put(resource_path, data=json.dumps(body), headers=headers)
1372        except CoreException as err:
1373            py_jama_rest_client_logger.error(err)
1374            raise APIException(str(err))
1375            raise APIException
1376        return self.__handle_response_status(response)

updates an existing user

Args: username: str password: str first_name: str last_name: str email: str phone: str - optional title: str - optional location: str - optional

Returns: api status code

def put_user_active(self, user_id, is_active):
1378    def put_user_active(self, user_id, is_active):
1379        """
1380        updates an existing users active status
1381
1382        Args:
1383            is_active: boolean
1384
1385        Returns: api status code
1386
1387        """
1388        body = {
1389            'active': is_active
1390        }
1391        resource_path = 'users/' + str(user_id) + '/active'
1392        headers = {'content-type': 'application/json'}
1393        try:
1394            response = self.__core.put(resource_path, data=json.dumps(body), headers=headers)
1395        except CoreException as err:
1396            py_jama_rest_client_logger.error(err)
1397            raise APIException(str(err))
1398        return self.__handle_response_status(response)

updates an existing users active status

Args: is_active: boolean

Returns: api status code

def put_test_run(self, test_run_id, data=None):
1400    def put_test_run(self, test_run_id, data=None):
1401        """ This method will post a test run to Jama through the API"""
1402        resource_path = 'testruns/' + str(test_run_id)
1403        headers = {'content-type': 'application/json'}
1404        try:
1405            response = self.__core.put(resource_path, data=data, headers=headers)
1406        except CoreException as err:
1407            py_jama_rest_client_logger.error(err)
1408            raise APIException(str(err))
1409        return self.__handle_response_status(response)

This method will post a test run to Jama through the API

def set_allowed_results_per_page(self, allowed_results_per_page):
1526    def set_allowed_results_per_page(self, allowed_results_per_page):
1527        self.__allowed_results_per_page = allowed_results_per_page
def get_allowed_results_per_page(self):
1529    def get_allowed_results_per_page(self):
1530        return self.__allowed_results_per_page