Giter Site home page Giter Site logo

assembla's Introduction

Python wrapper for the Assembla API

An easy to use wrapper around the Assembla API.

Installation

Install assembla with pip:

$ pip install assembla

Connecting to Assembla's API requires your user account's authentication key and secret, which are accessible from https://www.assembla.com/user/edit/manage_clients.

Basic example

The following example connects to Assembla, retrieves a list of tickets for a space and then outputs information about each.

from assembla import API

assembla = API(
    key='8a71541e5fb2e4741120',
    secret='a260dc4448c81c907fc7c85ad09d31306c425417',
    # Use your API key/secret from https://www.assembla.com/user/edit/manage_clients
)

my_space = assembla.spaces(name='My Space')[0]

for ticket in my_space.tickets():
    print '#{0} - {1}'.format(ticket['number'], ticket['summary'])

# >>> #1 - My first ticket
# >>> #2 - My second ticket
# ...

User guide

The Assembla API wrapper uses a number of Python classes to represent the objects retrieved from Assembla, some of which possess the following methods and properties:

API

API instances are the primary facet of the Assembla API wrapper and are the starting point for interactions with the API. APIs are instantiated with authentication details (available from https://www.assembla.com/user/edit/manage_clients) and offer two methods of navigating Assembla's data:

###API.stream() Returns a list of Event instances indicating the activity stream you have access to. Keyword arguments can be provided to filter the results.

###API.spaces() Returns a list of Space instances which represent all the spaces that you have access to. Keyword arguments can be provided to filter the results.

Here's an example which prints a list of the spaces available:

from assembla import API

assembla = API(
    key='8a71541e5fb2e4741120',
    secret='a260dc4448c81c907fc7c85ad09d31306c425417',
    # Use your API key/secret from https://www.assembla.com/user/edit/manage_clients
)

for space in assembla.spaces():
	print space['name']

Space

See the Space object field reference for field names and explanations.

Spaces possess the following methods:

###Space.tickets() Returns a list of all Ticket instances inside the Space. Keyword arguments can be provided to filter the results. ###Space.milestones() Returns a list of all Milestone instances inside the Space. Keyword arguments can be provided to filter the results. ###Space.components() Returns a list of all Component instances inside the Space. Keyword arguments can be provided to filter the results. ###Space.tools() Returns a list of all SpaceTool instances inside the Space. Keyword arguments can be provided to filter the results. ###Space.users() Returns a list of all User instances with access to the Space. Keyword arguments can be provided to filter the results. ###Space.tags() Returns a list of all Tag instances inside the Space. Keyword arguments can be provided to filter the results.

Here is an example which prints a report of all the tickets in a Space which have the status 'New' and belong to a milestone called 'Alpha Release':

space = assembla.spaces(name='My Space')[0]

milestone = space.milestones(title='Alpha Release')[0]

tickets = space.tickets(
	milestone_id=milestone['id'],
	status='New'
)

print 'New tickets in "{0}".format(milestone['title'])
for ticket in tickets:
    print '#{0} - {1}'.format(ticket['number'], ticket['summary'])

# >>> New tickets in "Alpha Release"
# >>> #1 - My first ticket
# >>> #2 - My second ticket
# ...

Milestone

See the Milestone object field reference for field names and explanations.

Milestone instances possess the following method:

###Milestone.tickets() Returns a list of all Ticket instances which are connected to the Milestone. Keyword arguments can be provided to filter the results.

Here is an example which prints a report of all the tickets in a milestone:

milestone = space.milestones()[0]

for ticket in milestone.tickets():
    print '#{0} - {1}'.format(ticket['number'], ticket['summary'])

# >>> #1 - My first ticket
# >>> #2 - My second ticket
# ...

Ticket

See the Ticket object field reference for field names and explanations.

Ticket instances possess the following methods:

###Ticket.milestone() Returns an instance of the Milestone that the Ticket belongs to.

###Ticket.user() Returns an instance of the User that the Ticket is assigned to.

###Ticket.component() An instance of the Component that the Ticket is assigned to.

###Ticket.comments() Returns a list of the Ticket Comment instances relating to the Ticket.

###Ticket.write() Calling Ticket.write() sends the ticket back to Assembla. The ticket object must have a space attribute set to the corresponding Space object.

If the Ticket object has a 'number' key (i.e. if it already exists), the corresponding Ticket on Assembla is updated (using an HTTP PUT request), otherwise a new ticket is created in the space (using HTTP POST).

Ticket.write() returns the instance of the ticket. If a new ticket was created, the returned instance will have the number, id, and other server-generated fields populated.

###Ticket.delete() Calling Ticket.delete() deletes the ticket from Assembla. The ticket object must have a space attribute set to the corresponding Space object.

Ticket Comment

See the Ticket Comment object field reference for field names and explanations.

User

See the User object field reference for field names and explanations.

User instances possess the following method:

###User.tickets() Returns a list of all Ticket instances which are assigned to the User. Keyword arguments can be provided to filter the results.

Here is an example which prints a report of all the tickets assigned to a user named 'John Smith':

user = space.users(name='John Smith')[0]

for ticket in user.tickets():
    print '#{0} - {1}'.format(ticket['number'], ticket['summary'])

# >>> #1 - John's first ticket
# >>> #2 - John's second ticket
# ...

Component

See the Ticket Component object field reference for field names and explanations.

Space tool

See the Space tool object field reference for field names and explanations.

Wiki Page

See the Wiki Page object field reference for field names and explanations.

Wiki Page instances possess the following methods:

###WikiPage.write() Calling WikiPage.write() sends the page back to Assembla. The WikiPage object must have a space attribute set to the corresponding Space object.

If the WikiPage object has a 'id' key (i.e. if it already exists), the corresponding WikiPage on Assembla is updated (using an HTTP PUT request), otherwise a new ticket is created in the space (using HTTP POST).

WikiPage.write() returns the instance of the ticket. If a new ticket was created, the returned instance will have the id and other server-generated fields populated.

###WikiPage.delete() Calling WikiPage.delete() deletes the ticket from Assembla. The WikiPage object must have a space attribute set to the corresponding Space object.

Tag

See the Tag object field reference for field names and explanations.

Event

See the Event object field reference for field names and explanations.

Filtering objects with keyword arguments

Most data retrieval methods allow for filtering of the objects based on the data returned by Assembla. The keyword arguments to use correlate to the field names returned by Assembla, for example Tickets can be filtered with keyword arguments similar to field names specified in Assembla's Ticket Fields documentation

Using Space.tickets as an example of filtering with keyword arguments:

  • space.tickets(number=100) will return the ticket with the number 100.
  • space.tickets(status='New', assigned_to_id=100) will return new tickets assigned to a user with the id 100

Normal keyword filtering will only act on the data that Assembla returns. If you wish to take advantage of the pre-filtering that Assembla's API offers, an extra_params keyword argument can be provided. The argument should be a dictionary that contains extra parameters which will be passed along when the GET request is sent.

For example, to filter Stream events from a certain period:

assembla.stream(extra_params={
    'from': '2014-01-19 09:20'
})

Custom fields

An object's custom fields are retrieved similarly to most fields, the only difference is that they are nested within a dictionary named custom_fields.

Here's an example to get a custom field 'billing_code' from a ticket:

billing_code = ticket['custom_fields']['billing_code']

Caching

The API wrapper has an optional response caching system which is deactivated by default. Turning the caching system on will reduce the overhead on repeated requests, but can cause stale data to perpetuate for long-running processes. Turning the cache on is done by setting an API instance's cache_responses variable to True. The cache can be turned off by setting cache_responses to False.

Here is an example of how to instantiate the wrapper and activate the cache.

from assembla import API

assembla = API(
	# Auth details...
)

assembla.cache_responses = True

Colophon

A list of contributors is available on Github.

This project is licensed under The MIT License (MIT). Copyright (c) 2014, Mark Finger.

For more information about the license for this particular project read the LICENSE.txt file.

assembla's People

Contributors

arjunchitturi avatar gak avatar markfinger avatar martyzz1 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

assembla's Issues

increasing per_page triggers downloading all

in API._get_json You explicitly call out

# If the number of results is divisible by the maximum limit per
# page, then we need to fetch the next page

However this is not necessarily the case nor does it match assembla.

For example, the default activity query returns 10. In that scenario API.stream() and ...activity.json are equivalent.

If this gets bumped to 25

assembla.stream(extra_params={
    'per_page': 25
})

every activity is queried where running the same command ...activity.json?per_page=25 gives only those first 25 or activity.json?per_page=25&page=2 would give the second 25.

It would be nice to have control of whether to make the recursive call to get more results or limit them to a single page. The workaround for forcing a limit is to define {'from': 'yyyy-mm-dd hh:mm'}

Writeback from github issue to Assembla

Hi there,

Can't figure this out from the current documentation, but it is possible to CRUD from Github back to Assembla, so:

ticket99example in Assembla writes to Github. That tickets gets modified on Github, would that modification than be sent back to Assembla in #ticket99example

Thanks, Siem

v2 filtering

v2 codebase doesn't have much native support for filtering objects

Appears to hang on a large ticket set

I've found that when I'm trying to grab a single ticket, it is a lot quicker to call https://api.assembla.com/v1/spaces/space_id/tickets/ticket_number.json directly instead of waiting for the script to complete. In fact, after a few minutes I just hit ctrl+c.

from assembla import API
print 'API'
assembla = API(
    key='<snip>',
    secret='<snip>',
)
for space in assembla.spaces():
    print space['name']
print 'spaces'
space = assembla.spaces(name='my-space')[0]
print space['id']
print 'tickets'
ticket = space.ticket(number=10)

print 'end'
print '#{0} - {1}'.format(ticket['number'], ticket['summary'])

As you can see, my script is fairly simple. It's just the fact that I have so many tickets to go through, it takes for ever. It even seems like it hangs on me.

Space.users returns 403

Hi,

I've tried:

from assembla import API
assembla = API(
# ...proper settings
)
space = assembla.spaces(name='_space_name')[0]
for user in space.users():
print user['name']

Expected:
printed out list of user names

Current output:
Traceback (most recent call last):
File "myfile.py", line 27, in
for user in space.users():
File "/usr/local/lib/python2.6/dist-packages/assembla/lib.py", line 34, in wrapper
results = func(class_instance)
File "/usr/local/lib/python2.6/dist-packages/assembla/init.py", line 175, in users
rel_path=self._build_rel_path('users'),
File "/usr/local/lib/python2.6/dist-packages/assembla/init.py", line 109, in _get_json
url,
Exception: Code 403 returned from https://api.assembla.com/v1/spaces/_space_id/users.json?page=1.

It might be Assembla issue, but before I contact them I would like to confirm.

Best regards!

Supporting Extraction of Comments and Statuses from Tickets

Hello,
I was looking into the API and I am wondering if there a quick and dirty way I can implement the extraction of comments from tickets into the API. From what I understand the URL is composed of api root, version and space, and I was wondering how I could extend it to iterate all the comments from the tickets url = '{0}/{1}/{2}{TICKET}comment.json?{3}'.format(

I am not that familiar with python sorry if it makes no sense..

Regards.
P.T.

Pagination is broken

Assembla sets some soft limits on the amount of data returned - for example a Space's Ticket list defaults to maximum 1000 - which causes data to be omitted on larger projects.

Some tickets aren't being returned

I have found that for some reason the odd ticket doesn't get returned when this call is made:
space.tickets()

Will investigate this when I get a chance. For my reference, NFSA ticket 1206 doesn't get returned.

Python 3 support

Currently, this library fails to install entirely on Python 3 (3.3 in the case of my test). I would love to see Python 3 support so that I can use it in my own Python 3 projects.

keyword filtering does not work for stream

According to the doc, Keyword arguments can be provided to filter the stream() results. Per /v1/activity these are: space_id, to, from, page, per_page

A couple of issues here:

  1. passing keywords does not appear to work
    .stream(page=2)
    .stream(per_page=25)
  2. how are you supposed to pass the reserved word from?

API wrapper may be out of date

Recent API changes by Assembla require checking that the wrapper still functions as expected. Successful completion of the unit tests should satisfy this.

One possible fail may be caused by a change whereby the API now serves over HTTPS, rather than HTTP. A small tweak the base_url (or whatever it was called) constant should fix this though.

If development goes ahead to build v2 against the new API, one bonus is that we'll can get JSON responses rather than xml.

How to get values for custom fields

Hello Mark,

I'm having some difficulty getting a list of available custom fields and their values.
It would be very useful for us to be able to do this, can you please investigate?

Thanks.

Extremely slow response with large ticket sets

I believe I am having a problem similar to problem #13 - however my results slightly different instead of "hanging" the response is just extremely slow. We have over 5000 tickets in our Assembla space and I get response time of almost 45 to 50 seconds when trying to find a specific ticket.

     for ticket in myspace.tickets(number=ticket_num):

I do have the latest release of the library. Any suggestions for speeding this up? Is there a faster way to lookup a specific ticket?

Thanks.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.