.. toctree:: :maxdepth: 2
This documents the jira-python
package (version |release|), a Python library designed to ease the use of the
JIRA REST API. Some basic support for the GreenHopper REST API also exists.
The source is stored at https://github.com/pycontribs/jira.
The easiest (and best) way to install jira-python is through pip:
$ pip install jira
This will handle the client itself as well as the requirements.
If you're going to run the client standalone, we strongly recommend using a virtualenv, which pip can also set up for you:
$ pip -E jira_python install jira $ workon jira_python
Doing this creates a private Python "installation" that you can freely upgrade, degrade or break without putting the critical components of your system at risk.
Source packages are also available at PyPI:
http://pypi.python.org/pypi/jira-python/
Python 2.7 and Python 3.x are both supported.
Kenneth Reitz's indispensable python-requests library handles the HTTP business. Usually, the latest version available at time of release is the minimum version required; at this writing, that version is 1.2.0, but any version >= 1.0.0 should work.
Used to implement OAuth. The latest version as of this writing is 0.3.3.
The IPython enhanced Python interpreter provides the fancy chrome used by :ref:`jirashell-label`. As with Requests, the latest version available at release time is required; at this writing, that's 0.13.
This library handles content-type autodetection for things like image uploads. This will only work on a system that
provides libmagic; Mac and Unix will almost always have it preinstalled, but Windows users will have to use Cygwin
or compile it natively. If your system doesn't have libmagic, you'll have to manually specify the contentType
parameter on methods that take an image object, such as project and user avater creation.
This is a TLS implementation that handles key signing. It's used to help implement the OAuth handshaking.
This is required for the RSA-SHA1 used by OAuth. Please note that it's not installed automatically, since it's
a fairly cumbersome process in Windows. On Linux and OS X, a pip install pycrypto
should do it.
Installing through pip takes care of these dependencies for you.
Here's a quick usage example:
.. literalinclude:: ../examples/basic_use.py
Another example shows how to authenticate with your JIRA username and password:
.. literalinclude:: ../examples/basic_auth.py
This example shows how to work with GreenHopper:
.. literalinclude:: ../examples/greenhopper.py
Everything goes through the JIRA object, so make one:
from jira import JIRA jira = JIRA()
This connects to a JIRA started on your local machine at http://localhost:2990/jira, which not coincidentally is the default address for a JIRA instance started from the Atlassian Plugin SDK.
You can manually set the JIRA server to use:
jac = JIRA('https://jira.atlassian.com')
At initialization time, jira-python can optionally create an HTTP BASIC or use OAuth 1.0a access tokens for user authentication. These sessions will apply to all subsequent calls to the JIRA object.
The library is able to load the credentials from inside the ~/.netrc file, so put them there instead of keeping them in your source code.
Pass a tuple of (username, password) to the basic_auth
constructor argument:
authed_jira = JIRA(basic_auth=('username', 'password'))
Pass a dict of OAuth properties to the oauth
constructor argument:
# all values are samples and won't work in your code! key_cert_data = None with open(key_cert, 'r') as key_cert_file: key_cert_data = key_cert_file.read() oauth_dict = { 'access_token': 'd87f3hajglkjh89a97f8', 'access_token_secret': 'a9f8ag0ehaljkhgeds90', 'consumer_key': 'jira-oauth-consumer', 'key_cert': key_cert_data } authed_jira = JIRA(oauth=oauth_dict)
Note
The OAuth access tokens must be obtained and authorized ahead of time through the standard OAuth dance. For
interactive use, jirashell
can perform the dance with you if you don't already have valid tokens.
Note
OAuth in Jira uses RSA-SHA1 which requires the PyCrypto library. PyCrypto is not installed automatically when installing jira-python. See also the Dependencies. section above.
- The access token and token secret uniquely identify the user.
- The consumer key must match the OAuth provider configured on the JIRA server.
- The key cert data must be the private key that matches the public key configured on the JIRA server's OAuth provider.
See https://confluence.atlassian.com/display/JIRA/Configuring+OAuth+Authentication+for+an+Application+Link for details on configuring an OAuth provider for JIRA.
Issues are objects. You get hold of them through the JIRA object:
issue = jira.issue('JRA-1330')
Issue JSON is marshaled automatically and used to augment the returned Issue object, so you can get direct access to fields:
summary = issue.fields.summary # 'Field level security permissions' votes = issue.fields.votes.votes # 440 (at least)
If you only want a few specific fields, save time by asking for them explicitly:
issue = jira.issue('JRA-1330', fields='summary,comment')
Reassign an issue:
# requires issue assign permission, which is different from issue editing permission! jira.assign_issue(issue, 'newassignee')
Creating issues is easy:
new_issue = jira.create_issue(project='PROJ_key_or_id', summary='New issue from jira-python', description='Look into this one', issuetype={'name': 'Bug'})
Or you can use a dict:
issue_dict = { 'project': {'id': 123}, 'summary': 'New issue from jira-python', 'description': 'Look into this one', 'issuetype': {'name': 'Bug'}, } new_issue = jira.create_issue(fields=issue_dict)
Note
Project, summary, description and issue type are always required when creating issues. Your JIRA may require
additional fields for creating issues; see the jira.createmeta
method for getting access to that information.
You can also update an issue's fields with keyword arguments:
issue.update(summary='new summary', description='A new summary was added') issue.update(assignee={'name': 'new_user'}) # reassigning in update requires issue edit permission
or with a dict of new field values:
issue.update(fields={'summary': 'new summary', 'description': 'A new summary was added'})
and when you're done with an issue, you can send it to the great hard drive in the sky:
issue.delete()
Updating components:
existingComponents = [] for component in issue.fields.components: existingComponents.append({"name" : component.name}) issue.update(fields={"components": existingComponents})
issue.fields.worklogs # list of Worklog objects issue.fields.worklogs[0].author issue.fields.worklogs[0].comment issue.fields.worklogs[0].created issue.fields.worklogs[0].id issue.fields.worklogs[0].self issue.fields.worklogs[0].started issue.fields.worklogs[0].timeSpent issue.fields.worklogs[0].timeSpentSeconds issue.fields.worklogs[0].updateAuthor # dictionary issue.fields.worklogs[0].updated
issue.fields.timetracking.remainingEstimate # may be NULL or string ("0m", "2h"...) issue.fields.timetracking.remainingEstimateSeconds # may be NULL or integer issue.fields.timetracking.timeSpent # may be NULL or string issue.fields.timetracking.timeSpentSeconds # may be NULL or integer
Leverage the power of JQL to quickly find the issues you want:
issues_in_proj = jira.search_issues('project=PROJ') all_proj_issues_but_mine = jira.search_issues('project=PROJ and assignee != currentUser()') # my top 5 issues due by the end of the week, ordered by priority oh_crap = jira.search_issues('assignee = currentUser() and due < endOfWeek() order by priority desc', maxResults=5) # Summaries of my last 3 reported issues print [issue.fields.summary for issue in jira.search_issues('reporter = currentUser() order by created desc', maxResults=3)]
Comments, like issues, are objects. Get at issue comments through the parent Issue object or the JIRA object's dedicated method:
comments_a = issue.fields.comment.comments comments_b = jira.comments(issue) # comments_b == comments_a
Get an individual comment if you know its ID:
comment = jira.comment('JRA-1330', '10234')
Adding, editing and deleting comments is similarly straightforward:
comment = jira.add_comment('JRA-1330', 'new comment') # no Issue object required comment = jira.add_comment(issue, 'new comment', visibility={'type': 'role', 'value': 'Administrators'}) # for admins only comment.update(body = 'updated comment body') comment.delete()
Learn what transitions are available on an issue:
issue = jira.issue('PROJ-1') transitions = jira.transitions(issue) [(t['id'], t['name']) for t in transitions] # [(u'5', u'Resolve Issue'), (u'2', u'Close Issue')]
Note
Only the transitions available to the currently authenticated user will be returned!
Then perform a transition on an issue:
# Resolve the issue and assign it to 'pm_user' in one step jira.transition_issue(issue, '5', assignee={'name': 'pm_user'}, resolution={'id': '3'}) # The above line is equivalent to: jira.transition_issue(issue, '5', fields: {'assignee':{'name': 'pm_user'}, 'resolution':{'id': '3'}})
Projects are objects, just like issues:
projects = jira.projects()
Also, just like issue objects, project objects are augmented with their fields:
jra = jira.project('JRA') print jra.name # 'JIRA' print jira.lead.displayName # 'Paul Slade [Atlassian]'
It's no trouble to get the components, versions or roles either (assuming you have permission):
components = jira.project_components(jra) [c.name for c in components] # 'Accessibility', 'Activity Stream', 'Administration', etc. jira.project_roles(jra) # 'Administrators', 'Developers', etc. versions = jira.project_versions(jra) [v.name for v in reversed(versions)] # '5.1.1', '5.1', '5.0.7', '5.0.6', etc.
There is no substitute for play. The only way to really know a service, an API or a package is to explore it, poke at
it, and bang your elbows -- trial and error. A REST design is especially well-suited to active exploration, and the
jirashell
script (installed automatically when you use pip) is designed to help you do exactly that.
Run it from the command line:
$ jirashell -s http://jira.atlassian.com <JIRA Shell (http://jira.atlassian.com)> *** JIRA shell active; client is in 'jira'. Press Ctrl-D to exit. In [1]:
This is a specialized Python interpreter (built on IPython) that lets you explore JIRA as a service. Any legal
Python code is acceptable input. The shell builds a JIRA client object for you (based on the launch parameters) and
stores it in the jira
object.
Try getting an issue:
In [1]: issue = jira.issue('JRA-1330')
issue
now contains a reference to an issue Resource
. To see the available properties and methods, hit the TAB
key:
In [2]: issue. issue.delete issue.fields issue.id issue.raw issue.update issue.expand issue.find issue.key issue.self In [2]: issue.fields. issue.fields.aggregateprogress issue.fields.customfield_11531 issue.fields.aggregatetimeestimate issue.fields.customfield_11631 issue.fields.aggregatetimeoriginalestimate issue.fields.customfield_11930 issue.fields.aggregatetimespent issue.fields.customfield_12130 issue.fields.assignee issue.fields.customfield_12131 issue.fields.attachment issue.fields.description issue.fields.comment issue.fields.environment issue.fields.components issue.fields.fixVersions issue.fields.created issue.fields.issuelinks issue.fields.customfield_10150 issue.fields.issuetype issue.fields.customfield_10160 issue.fields.labels issue.fields.customfield_10161 issue.fields.mro issue.fields.customfield_10180 issue.fields.progress issue.fields.customfield_10230 issue.fields.project issue.fields.customfield_10575 issue.fields.reporter issue.fields.customfield_10610 issue.fields.resolution issue.fields.customfield_10650 issue.fields.resolutiondate issue.fields.customfield_10651 issue.fields.status issue.fields.customfield_10680 issue.fields.subtasks issue.fields.customfield_10723 issue.fields.summary issue.fields.customfield_11130 issue.fields.timeestimate issue.fields.customfield_11230 issue.fields.timeoriginalestimate issue.fields.customfield_11431 issue.fields.timespent issue.fields.customfield_11433 issue.fields.updated issue.fields.customfield_11434 issue.fields.versions issue.fields.customfield_11435 issue.fields.votes issue.fields.customfield_11436 issue.fields.watches issue.fields.customfield_11437 issue.fields.workratio
Since the Resource class maps the server's JSON response directly into a Python object with attribute access, you can see exactly what's in your resources.
The library distinguishes between two kinds of data in the JIRA REST API: resources and properties.
A resource is a REST entity that represents the current state of something that the server owns; for example,
the issue called "ABC-123" is a concept managed by JIRA which can be viewed as a resource obtainable at the URL
http://jira-server/rest/api/2/issue/ABC-123. All resources have a self link: a root-level property called self
which contains the URL the resource originated from. In jira-python, resources are instances of the Resource object
(or one of its subclasses) and can only be obtained from the server using the find()
method. Resources may be
connected to other resources: the issue Resource is connected to a user Resource through the assignee
and
reporter
fields, while the project Resource is connected to a project lead through another user Resource.
Important
A resource is connected to other resources, and the client preserves this connection. In the above example,
the object inside the issue
object at issue.fields.assignee
is not just a dict -- it is a full-fledged
user Resource object. Whenever a resource contains other resources, the client will attempt to convert them
to the proper subclass of Resource.
A properties object is a collection of values returned by JIRA in response to some query from the REST API. Their structure is freeform and modeled as a Python dict. Client methods return this structure for calls that do not produce resources. For example, the properties returned from the URL http://jira-server/rest/api/2/issue/createmeta are designed to inform users what fields (and what values for those fields) are required to successfully create issues in the server's projects. Since these properties are determined by JIRA's configuration, they are not resources.
The JIRA client's methods document whether they will return a Resource or a properties object.
The client is an open source project under the BSD license. Contributions of any kind are welcome!
https://github.com/pycontribs/jira/
If you find a bug or have an idea for a useful feature, file it at that bitbucket project. Extra points for source code patches -- fork and send a pull request.
We encourage all who wish to discuss by using https://answers.atlassian.com/questions/topics/754366/jira-python
Keep in mind to use the jira-python tag when you add a new question. This will assure that the project mantainers will get notified about your question.
.. automodule:: jira :members: JIRA, Priority, Comment, Worklog, Watchers, JIRAError :undoc-members: :show-inheritance: