Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 12 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,13 @@
*.pyc
tests_live_config.json
tests_live_config.json

# Setuptools distribution folder.
/dist/
/build/

# Python egg metadata, regenerated from source files by setuptools.
/*.egg-info

# Others
*.swp
.DS_Store
6 changes: 5 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,11 @@ There is already a similar library, [toggl_target](https://github.com/mos3abof/t

# Usage

The library is currently not in a Python PIP package yet. For now simply download to a location of your choice and do the following.
## Pypi Package
pip install python-toggl

## Manual installation
Download to a location of your choice and do the following.

```python

Expand Down
99 changes: 99 additions & 0 deletions README.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
toggl-python-api-client
=======================

`Toggl <http://toggl.com>`__ is an "insanely simple time tracking"
service.

This specific library is a Python-based REST client to interface with
the Toggle API utilizing
`requests <http://docs.python-requests.org/en/latest/>`__.

This library is a pure api client to help other python apps interface
with Toggl. I created this project primarily to help with a bigger
internal project that I am doing at work while at the same time getting
my feet wet in Python.

Others out there
================

There is already a similar library,
`toggl\_target <https://github.com/mos3abof/toggl_target>`__ though it
is more of an application and the client api is not separate repo. Some
ideas/concepts on the client api were taken from there but I had needed
a client api only to help interface with my bigger app.

Usage
=====

Pypi Package
------------

::

pip install python-toggl

Manual installation
-------------------

Download to a location of your choice and do the following.

.. code:: python


from toggl-python-api-client.api_client import TogglClientApi

settings = {
'token': 'xxx',
'user_agent': 'your app name'
}
toggle_client = TogglClientApi(settings)

response = toggle_client.get_workspaces()

Dependencies
============

- Python 2.7 onwards
- `requests <http://docs.python-requests.org/en/latest/>`__

Tests Dependencies
------------------

To run the tests, you will need the following packages

- unittest
- json
- `httpretty <https://github.com/gabrielfalcao/HTTPretty>`__

Tests
=====

Tests created under ``/tests`` are primarily integration tests and are
not strictly unit tests. They consists of an offline and online(live)
test.

Offline
-------

``tests/tests_offline.py``

These tests are for the logic of the api client. They do not connect to
the actual Toggl servers - instead use
`httpretty <https://github.com/gabrielfalcao/HTTPretty>`__ to mock the
responses. Sample responses are included in ``tests/json_responses`` and
are based on Toggle responses for V8 of the main api and V2 of the
report api.

Online/Live
-----------

``tests/tests_live.py``

These tests are to check the connections to Toggl's API and to ensure
that the client is handling the live responses from Toggl as expected.

To avoid adding sensitive data to version control, no api credentials
have been included. To enable live tests, - make a copy of
``tests/tests_live_config.json.sample`` as
``tests/tests_live_config.json`` - update the settings on
``tests/tests_live_config.json`` as needed
22 changes: 22 additions & 0 deletions setup.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
from setuptools import setup


def readme():
with open('README.rst') as f:
return f.read()

setup(name='python-toggl',
version='0.1.4',
description='Python Wrapper for Toggl API',
long_description=readme(),
url='https://github.com/swappsco/toggl-python-api-client',
author='mechastorm',
author_email='[email protected]',
license='MIT',
packages=['toggl'],
install_requires=[
'requests',
],
test_suite='nose.collector',
tests_require=['nose', 'httpretty'],
zip_safe=False)
4 changes: 2 additions & 2 deletions tests/tests_live.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import unittest
import json
from ..api_client import TogglClientApi
from toggl.api_client import TogglClientApi


class TogglClientApiLiveTests(unittest.TestCase):
Expand All @@ -21,7 +21,7 @@ def tearDown(self):

def test_api_client_instance_created(self):
self.assertNotEqual(self.api, None)

def test_valid_toggl_base_url(self):
self.assertEqual(self.api.api_base_url, 'https://www.toggl.com/api/v8')

Expand Down
5 changes: 3 additions & 2 deletions tests/tests_offline.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import unittest
import httpretty
import json
from ..api_client import TogglClientApi
from toggl.api_client import TogglClientApi


class ToogleClientApiTests(unittest.TestCase):

Expand Down Expand Up @@ -33,7 +34,7 @@ def tearDown(self):
httpretty.disable()
httpretty.reset()

def load_json_file(self, location, base_path='json_responses'):
def load_json_file(self, location, base_path='tests/json_responses'):
file_contents = open(base_path+'/'+location+'.json')
json_data = json.load(file_contents)
file_contents.close()
Expand Down
1 change: 1 addition & 0 deletions toggl/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from toggl import api_client
33 changes: 30 additions & 3 deletions api_client.py → toggl/api_client.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import requests

from datetime import date

class TogglClientApi:

Expand All @@ -26,6 +26,8 @@ def __init__(self, credentials):
self.api_report_base_url = self.build_api_url(self.credentials['base_url_report'], self.credentials['ver_report'])
self.api_token = self.credentials['token']
self.api_username = self.credentials['username']
self.user_agent = self.credentials['user_agent']
self.workspace_id = int(self.credentials['workspace_id'])
return

@staticmethod
Expand All @@ -47,10 +49,13 @@ def get_workspace_by_name(self, name):
return workspace_found

def get_workspaces(self):
return self.query('/workspaces');
return self.query('/workspaces')

def get_projects(self):
return self.query('/workspaces/%i/projects' % self.workspace_id)

def get_workspace_members(self, workspace_id):
response = self.query('/workspaces/'+str(workspace_id)+'/workspace_users');
response = self.query('/workspaces/'+str(workspace_id)+'/workspace_users')
return response

"""
Expand Down Expand Up @@ -78,6 +83,26 @@ def get_user_hours_range(self, user_agent, workspace_id, user_id, start_date, en

return time_total

"""
@param start_date datetime.date()
@param end_date datetime.date()
"""""
def get_project_times(self, project_id, start_date, end_date):
params = {
'workspace_id': self.workspace_id,
'project_ids': project_id,
'since': start_date.strftime('%Y-%m-%d'),
'until': end_date.strftime('%Y-%m-%d'),
'user_agent': self.user_agent,
'grouping': 'users',
'subgrouping': 'projects'
}
time_entries_response = self.query_report('/details', params)

json_response = time_entries_response.json()

return json_response

def query_report(self, url, params={}, method='GET'):
return self._query(self.api_report_base_url, url, params, method)

Expand All @@ -100,6 +125,8 @@ def _query(self, base_url, url, params, method):

@staticmethod
def _do_get_query(url, headers, auth, params):
print url
print params
response = requests.get(url, headers=headers, auth=auth, params=params)

return response