Skip to content

Instantly share code, notes, and snippets.



Last active Nov 27, 2018
What would you like to do?
Another version of Toggl-parser.
import sys
import csv
import xlwt
import requests
import json
import pandas
from datetime import datetime
def parse_file(filename):
csv_file = sys.argv[1]
# if argument given raises an exception - we should try use a default name or file in the same dir w/ .csv?
wb = open(csv_file)
reader = csv.reader(wb)
data = []
# We need Cols: 3, empty, 5, 7, 9 for `Project`, `Effort`, `Task
# description`, `Start date`, `End date`
first_row = True
for row in reader:
if first_row: # skip first row
first_row = False
project = str(row[3])
time = row[11] # We using `Duration` value for the effort calculation
effort = int(time[0:2]) + int(int(time[3:5])) / 60 + \
int(int(time[6:7])) / 3600 # Hourly effort formula
task = str(row[5])
started = str(row[7])
completed = str(row[9])
data.append((project, effort, task, started, completed))
return data
def get_workspace(token):
print('Proceeding with your token, getting your workspace id now...')
r = requests.get('', auth=(token, 'api_token'))
req = r.json()
workspace = req[0]['id'] # we know user's workspace id now
return workspace
def parse_online(token, workspace_id):
# TODO: add two more arguments for parsing requested period of time
print('Proceeding with your token, collecting your data now...')
since = '2018-10-01' # Begin of retrieved records
until = '2018-10-31' # End of retrieved period
r = requests.get("", auth=(token, 'api_token'), params={
'workspace_id': workspace_id,
'page': '1', # we did 50 records. So this a minimum. Less will lead to fail? TODO: the rest
'since': since,
'until': until,
'user_agent': 'api_test'
data = r.json()
Or... The first request for amount of records retrieving (dry run).
Then we'll do a work request???
pages_amount = int(data['total_count'] / 50)
pages_remainder = int(data['total_count']) % 50
print(pages_amount, pages_remainder) # this give us amount of loops (w/ 50 recs each) and a remainder
parsed = []
for rec in range(00, 50):
project = data['data'] [rec] ['project']
effort = ((lambda dur: dur / 1000 / 3600) (data['data'] [rec] ['dur'])) # Millisec -> Sec -> Hours in decimal (effort)
task = data['data'] [rec] ['description']
started = data['data'] [rec] ['start']
completed = data['data'] [rec] ['end']
parsed.append((project, effort, task, started, completed))
return parsed
def export_xls(data):
xls_file = 'timereport.xls' # TODO: add date period to the filename automatically
book = xlwt.Workbook(encoding="utf-8")
date_format = xlwt.XFStyle()
date_format.num_format_str = 'yyyy/mm/dd'
sheet1 = book.add_sheet("Efforts")
# create DataFrame to remove duplicates
df = pandas.DataFrame(
data, columns=['project', 'effort', 'task', 'started', 'completed'])
# sum duplicates
df = df.groupby(['project', 'task', 'started', 'completed']
# add header row to xls file
sheet1.write(0, 0, 'Project-Task')
sheet1.write(0, 1, 'Effort')
sheet1.write(0, 2, 'Description')
sheet1.write(0, 3, 'Started Date')
sheet1.write(0, 4, 'Completion Date')
for i, row in df.iterrows():
sheet1.write(i+1, 0, row['project'])
sheet1.write(i+1, 1, row['effort'])
sheet1.write(i+1, 2, row['task'])
sheet1.write(i+1, 3, datetime.strptime(
row['started'], '%Y-%m-%d'), date_format)
sheet1.write(i+1, 4, datetime.strptime(
row['completed'], '%Y-%m-%d'), date_format)
i += 1
print('The Toggl data has been successfully exported:',xls_file)
def print_usage():
print('''Usage: python3 <CSV filename> | <toggl API token>
python3 <CSV file> - parse the given file and generate timereport.xls at the same directory
python3 <toggle API token> - request detailed report from Toggl and generate timereport.xls
Supposed, that you have Toggl account already for start using this utility.
As for our company - the best practice will be the following:
- Create Client names i.e. `Microsoft`
- Create a bunch of Project names
formatted as `ProjectName.TypeOfActivity` i.e. `AppCenter.Development`
- Start track your every activity by using a dropdown menu
and by selecting the right `ProjectName.TypeOfActivity` value
- You all set!
Finally, you can either download a CSV-file from the Report page
(go<your workspace id will be here>/period/thisMonth)
or use API-token (go for get your one) for the further parsing.''')
if len(sys.argv) < 2:
argument = str(sys.argv[1])
if argument[-4:] == '.csv': # the given argument ends with ".csv"
print('Parsing the file given:', argument)
print('Proceed with token given. Request data online and parsing ')
export_xls(parse_online(argument, get_workspace(argument)))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment