bobcarroll / jira-client

A simple JIRA REST client for Java
Other
475 stars 380 forks source link

Exception on self._resource format with Board.find(id) #252

Closed steveteske closed 5 years ago

steveteske commented 5 years ago

The following fails with an exception. I can extract issues and sprints without a problem with this connection and the JIRA client. Only the board query fails.


        def test_board_query_with_parameters(self):
            connection = Connection()
            server = JIRA(server='https://my.url.removed.com',
                          basic_auth=[connection.user, connection.password],
                          options={'agile_rest_path': 'agile'})

            boards = server.boards(name="My Scrum Board")
            sprint_board = boards[0]

            issues = sprint_board.find(sprint_board.id)
Error
Traceback (most recent call last):
  File "/opt/python-3.6/lib/python3.6/unittest/case.py", line 59, in testPartExecutor
    yield
  File "/opt/python-3.6/lib/python3.6/unittest/case.py", line 605, in run
    testMethod()
  File "/home/user/src/mgv_stats/tests/mgv_stats/test_jira_library_capabilities.py", line 62, in test_board_query_with_parameters
    issues = sprint_board.find(sprint_board.id)
  File "/home/user/src/mgv_stats/ve/lib/python3.6/site-packages/jira/resources.py", line 199, in find
    path = self._resource.format(id)
KeyError: 'id'

I think I found the offending lines of code.

The self._resource variable is set in the constructor to board/{id} as shown below in resource.py

class Board(GreenHopperResource):
    """A GreenHopper board."""

    def __init__(self, options, session, raw=None):
        path = 'rapidview/{0}' if options['agile_rest_path'] == self.GREENHOPPER_REST_PATH else 'board/{id}'
        GreenHopperResource.__init__(self, path, options, session, raw)

Path is passed to GreenHopperResource and then to Rource which ultimately sent the self._resource variable.

class GreenHopperResource(Resource):
    ...
    def __init__(self, path, options, session, raw):
        self.self = None
        Resource.__init__(self, path, options, session, self.AGILE_BASE_URL)
        ...
class Resource(object):
   ...
    def __init__(self, resource, options, session, base_url=JIRA_BASE_URL):
        self._resource = resource
        self._options = options
        self._session = session
        self._base_url = base_url
        ...

Then in class Resource the following code breaks because the format command is looking for a named parameter called id.

    def find(self, id, params=None):

        if params is None:
            params = {}

        if isinstance(id, tuple):
            path = self._resource.format(*id)
        else:
            path = self._resource.format(id)
        url = self._get_url(path)
        self._load(url, params=params)

There are two options to fix this.

  1. change the constructor and replace board{id} with board{0}
  2. change the find method to use path = self._resource.format(id=*id) for the tuple case and path = self._resource.format(id=ed for non-tuple case.

I'd like to make this change and submit. Can I do that. Expeditiously?

Here is a setup of test cases that provide evidence of my findings.

import unittest

class TestFormatFailure(unittest.TestCase):

    def test_format_parameter_working(self):
        resource = 'board/{0}'

        def find(id):
            return resource.format(id)

        find(22)

    def test_format_parameter_working_internal_named_parameter(self):
        resource = 'board/{id}'

        def find(id):
            return resource.format(id=id)

        find(22)

    @unittest.expectedFailure
    def test_format_parameter_failing(self):
        resource = 'board/{id}'

        def find(id):
            return resource.format(id)

        find(22)

    @unittest.expectedFailure
    def test_format_parameter_failing_named_parameter(self):
        resource = 'board/{id}'

        def find(id):
            return resource.format(id)

        find(id='24')
steveteske commented 5 years ago

I posted into Java client and I need to post into the Python client github. Sorry