Skip to main content

Python Redmine Web Services Library

Project description

Python Redmine Web Services Library

This python library facilitates creating, reading, updating and deleting content from a Redmine installation through the REST API.

Communications are performed via HTTP/S, freeing up the need for the Python script to run on the same machine as the Redmine installation.

This library was originally published at



The easiest way to install. The module is available on the Python Package Index (PyPI) and is available for the easy_install or pip commands. easy_install is available by default on OSX, either command may be available for whatever flavor of Unix you are using, and must be installed on Windows.

> easy_install pyredmine
> pip install pyredmine


To get the latest code updates or to get a different version of the library, you can clone this Github repository and run the setup script manually.

> git clone
> cd pyredminews
> python

How to use it

Set up Redmine

Within Redmine, you must enable the REST web service before most of the library operations will work. In the Administration -> Settings page on the Authentication tab, check the box for “Enable REST web service” and click the Save button. If the REST interface is not enabled, the users will not see an “API key” in their user information page. Many of the read-only actions provided by this library will still work, but the write/create operations will fail.


The library, like most good Python libraries, is self documenting. In the console, import the library then type ‘’help(redmine)’’ for all the details.

Step by Step

Start Python, Import the Module

Open a Python terminal window.

$ python
Python 2.6.1 (r261:67515, Feb 11 2010, 00:51:29)
[GCC 4.2.1 (Apple Inc. build 5646)] on darwin
Type "help", "copyright", "credits" or "license" for more information.

Now, import the Redmine class

>>> from redmine import Redmine

View the documentation

>>> help(Redmine)
Help on class Redmine in module redmine.redmine:
class Redmine
 |  Class to interoperate with a Redmine installation using the REST web services.
 |  instance = Redmine(url, [key=strKey], [username=strName, password=strPass] )
 |  url is the base url of the Redmine install ( http://my.server/redmine )
(type q to quit)


Locate a Redmine installation

If you don’t have Redmine installed somewhere that you can play with you can use the public demo server. With your web browser, go take a look at Find or make a project and note its identifier (not its pretty name, but the path it ends up in such as “testproject” in Make a bug and note its number. The remaining examples will assume you’ve done this.

Currently the Redmine instalation running at does not have the REST interface enabled.

Set up the Connection

Make an instance that represents the server you want to connect to.

>>> demo_anon = Redmine('')


You can perform most of the view actions with this anonymous access, but for the cool stuff, you should register an account and set up that access:

>>> demo = Redmine('', username='pyredmine', password='password')

Since leaving around your password in a script really sucks, Redmine allows you to use a user API key instead. Once logged into Redmine, on the My Account page, click on the Show button under the API Access Key on the right. That will reveal a key that can be used instead of a username/password. If you do not see any reference to the API key in the right-hand panel, the REST interface probably hasn’t been enabled - see Set up Redmine above.

>>> demo = Redmine('', key='701c0aec4330fb2f1db944f1808e1e987050c7f5')

Define the Redmine Version

Different versions of Redmine can use improved security, and have different items available through the REST interface. In order for the module to correctly represent the data and use available security features, you should tell the object what version your Redmine server is using.

>>> demo = Redmine('', username='pyredmine', password='password', version=2.1)

View Project Data

Although you can use this library to look up a large list of projects, the easiest helper functions are designed to work with a single project of a given identifier (testproject, in our example above). The projects parameter on the Redmine object can be used to return a single Project object.

>>> project = demo.projects['demoproject']

Now with that shiny new project object, you can take a look at the data available:

>>> project.identifier

The fields available on the project will differ depending on the version of Redmine. To see the full list of items available for the project, try:

>>> dir(project)
(politely ignore anything staring with a _)

If you happen to know the numeric ID of your project, that can also be used to look it up. If demoproject is in fact id 393, then the following will return the same project:

>>> project = demo.projects[393]

Change the Project

Changing the fields of the project are as easy as changing the objects parameters and invoking the save method.

>>> project.homepage = ''
>>> = 'Dead Parrot Society'

If you try and set a parameter for a read-only field, you’ll get an attribute error.

>>> project.updated_on = 'today'
AttributeError: Can't set attribute updated_on.

If your Redmine instance has custom fields set for projects, those fields and their values will be returned and can be changed in the same manner:

>>> project.custom_fields['Customer'] = 'John Cleese'

Examine All Projects

The projects member can be iterated over to retrieve information about all projects. Be default, Redmine will return 25 items at a time, so the following query might take some time to complete.

>>> for proj in demo.projects:
...   print "%s : %s" % (, proj.homepage)

Test Project LS II : None
Test Project Only : None
Test Project Rizal : None
Create home page : None
Test Project SES : None
Test project SGO : None
Test Project Trial : None
Test Project Tutorial ABCDE : None

Get All Issues for a Project

The issues associated for a project can be retreived by iterating over the ‘issues’ method in a project.

>>> for issue in project.issues:
...    print issue
<Redmine issue #3903, "mary was here too">
<Redmine issue #3902, "Johny was there">
<Redmine issue #3870, "Demo Feature">

(You may get an Unicode error if any of the issues has unicode in the subject. If you do, instead use: print “%s” % issue )

If you want to exclude issues from any subprojects, you can add query parameters to the iterator:

>>> for issue in project.issues(subproject_id='!*'):
...    print issue

Other parameters are:

  • tracker_id: get issues from the tracker with the given id

  • status_id: get issues with the given status id only. Possible values: open, closed, * to get open and closed issues, status id

  • assigned_to_id: get issues which are assigned to the given user id

  • cf_x: get issues with the given value for custom field with an ID of x. (Custom field must have ‘used as a filter’ checked.)

Create a New Issue

You can use the project object to create a new issue for that project:

>>> issue ="Test from Python", description="That rabbit is dynamite!")
>>> issue.created_on
datetime.datetime(2013, 2, 7, 1, 0, 28, tzinfo=tzutc())

Note that the new command returned an Issue object containing all (or, on older Redmine versions, most) of the new issue’s data. You can now go to to see your new issue. Any date/time information is returned as a Python datetime object. (Note the issue ID, you’ll need that for the next steps)

View an Issue

You can view any issue by its ID:

>>> issue = demo.issues[35178]
>>> issue.status
<Redmine status #1 - New>
>>> issue.subject
u'That rabbit is dynamite!'

Like the command above, it’s returning an object with all of the issue data. Note that this command is not running from the Project object but from the Redmine object.

If you examine your issue object, you’ll see that it contains an author parameter, which is itself another object:

<Redmine user #5 - Ian Epperson>

However, this user object is incomplete:



pyRedmine created the object with the data it had on hand, and since it doesn’t have the last_login data (it wasn’t in the issue information) it isn’t shown here. There are two ways to flesh out that data, one is to use the refresh method for the author (works on Redmine 1.1 and later where this data is available).

datetime.datetime(2013, 2, 7, 1, 0, 28, tzinfo=tzutc())

The other is to simply request that user id from the server

>>> demo.users[5]
<Redmine user #5 - Ian Epperson>
datetime.datetime(2013, 2, 7, 1, 0, 28, tzinfo=tzutc())

pyRedmine caches all objects it sees and sets up all cross references. Updating a Redmine object attached to one object will update them all. Also, this allows you to directly compare objects if needed:

>>> == issue.assigned_to

Change an Issue’s Status

You can move an issue through the workflow as well. You must set an issue status based on the status ID, which is can only be discovered in Redmine version 2.2 and later (but not yet available via this library). By default, the library uses the status ID for Resolved and Closed from a default Redmine installation, but if you’ve changed them in the Administration page, you’ll have to change these each time as well.


The closed and resolved methods are available on the issue itself, with an optional comment:

>>> issue.close('Closed the issue from Python!')
>>> issue.resolve('Resolved the issue from Python!')

Some versions of Redmine will not return an error if this operation fails, so be careful of false hopes.

If you need to set another status, you’ll need to find the requisite status ID, then use the set_status method (again, with optional comment):

>>> issue.set_status(8, 'Setting the status from Python!')

If you need to close an issue and don’t need to get an issue object, you can set the issue status directly using the Redmine server object with a single operation:

>>> demo.issues.update(35178, status_id=5)

Change an Issue

Just like with projects, to change a field on an issue simply change the parameter on the issue object then invoke the save method.

>>> issue.description = "The parrot doesn't seem to be alive."

If your installation of Redmine has custom fields on issues, those fields can be inspected and set.

>>> issue.custom_fields['Inform the client']
>>> issue.custom_fields['Inform the client'] = 1

If you want to change the project this issue is assigned to, you can set it directly to either a project object or a numeric project ID, then save it.

>>> issue.project = 12

>>> issue.project = demo.projects['test']

Delete an Issue

There is also an issue delete command that you should use with care. In a real production environment, you normally would never delete an issue - just leave it closed. Deleting it will remove history, time worked, and almost every trace of it. So, be careful! On the demo server, you don’t have permission to delete, so go ahead and try:

>>> demo.issues.delete(35178)
(whole lot of response, including)
urllib2.HTTPError: HTTP Error 403: Forbidden

Different versions of Redmine are inconsistent about when they returns 403 and when they just doesn’t work. You can’t rely on the lack of an HTTPError to guarantee success.

Note that there is no good method to assign an issue to a user. You can assign to the numeric user ID, but there’s no interface yet for looking up the ID based on a user name. You can use the catch-all command updateIssueFromDict to assign the issue to user number 25:

>>> demo.updateIssueFromDict(35178, {'assigned_to_id':'25'} )

Other Objects

Depending on what Redmine version you have, you can use these same commands to get/update/delete different Redmine items:

  • users

  • news

  • time_entries

Not every item supports every method. For instance, no current version of Redmine allows creating a news item, thus:

>>>'does this work?', description='Nope', author_id=4)
AttributeError: new is not available for News

Project details

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

pyredmine-0.2.4.tar.gz (35.9 kB view hashes)

Uploaded source

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page