Skip to content

Instantly share code, notes, and snippets.

@meunomemauricio
Last active February 10, 2021 10:57
Show Gist options
  • Save meunomemauricio/a7734a4847d9a1139784 to your computer and use it in GitHub Desktop.
Save meunomemauricio/a7734a4847d9a1139784 to your computer and use it in GitHub Desktop.
Script to Import a CSV file exported from Toggl.com to a Hamster DB
#! /usr/bin/python
"""Import CSV Files from Toggl to a Hamster DB."""
import argparse
import codecs
import csv
import sys
from datetime import datetime
try:
import hamster.client
except ImportError:
print 'Hamster must be Installed!'
sys.exit(1)
# XXX: Depending on the version, Fact is either on __init__ of the package or
# on the stuff module.
try:
from hamster.lib import Fact
except ImportError:
try:
from hamster.lib.stuff import Fact
except ImportError:
print 'Hamster must be Installed!'
sys.exit(1)
class UTF8Recoder(object):
"""Parse CSV files with Unicode."""
def __init__(self, f, encoding):
self.reader = codecs.getreader(encoding)(f)
def __iter__(self):
return self
def next(self):
"""Reads and returns the next line."""
return self.reader.next().encode('utf-8')
class UnicodeReader(object):
"""Parse CSV files with Unicode."""
def __init__(self, f, dialect=csv.excel, encoding='utf-8-sig', **kwds):
f = UTF8Recoder(f, encoding)
self.reader = csv.reader(f, dialect=dialect, **kwds)
def next(self):
"""Reads and returns the next line as a Unicode string."""
row = self.reader.next()
return [unicode(s, 'utf-8') for s in row]
def __iter__(self):
return self
def read_csv_file(origin):
"""Read the CSV File exported from the Toggl interface.
The CSV has the fields: User, Email, Client, Project, Task, Description,
Billable, Start date, Start time, End date, End time, Duration, Tags and
Amount.
Those are threated as follow:
* The Project field is the Hamster Category;
* Description is the Hasmter Activity name (not the Hamster Description);
* Start Date and Start Time are concatenated and transformed into a
datetime object. Same is done to the End Date/Time;
* Fields User, Email, Client, Task, Billable and Amount are ignored;
* Tags are Tags :D.
After parsing, the function returns a list for each line on the CSV file.
Each entry on the list is a dictionary in the format:
example_dict = {
'category': '<Toggl Project>',
'activity': '<Toggl Description>',
'start_time': datetime('<Start Date> + <Start Time>'),
'end_time': datetime('<End Date> + <End Time>'),
'tags': '#<tag1> #<tag2>']
}
"""
try:
with open(origin, 'rb') as csvfile:
reader = UnicodeReader(csvfile, delimiter=',', quotechar='"')
parsed_list = list(reader)
except IOError as error_msg:
print error_msg
sys.exit(1)
# Ignore the first line
parsed_list = parsed_list[1:]
fact_list = []
for line in parsed_list:
category = line[3]
activity = line[5]
start_time = '{0} {1}'.format(line[7], line[8])
end_time = '{0} {1}'.format(line[9], line[10])
# Create a string from the tags
tags = line[12]
if tags:
tags = line[12].split(',')
tags = ['#{0}'.format(tag.strip()) for tag in tags]
tags = ' '.join(tags)
fact = {
'category': category,
'activity': activity,
'start_time': datetime.strptime(start_time, '%Y-%m-%d %H:%M:%S'),
'end_time': datetime.strptime(end_time, '%Y-%m-%d %H:%M:%S'),
'tags': tags
}
fact_list.append(fact)
return fact_list
def parse_arguments():
"""Parse command line arguments from the CLI."""
parser = argparse.ArgumentParser(
description=__doc__,
formatter_class=argparse.RawDescriptionHelpFormatter,
)
parser.add_argument(
'-d', '--dryrun', action='store_true', default=False,
help='Just prints the parsed contents of the CSV File.'
)
parser.add_argument('origin', action='store', help='Origin CSV file.')
return parser.parse_args()
def add_hamster_fact(hamster_storage, fact_dict):
"""Add a Hamster Fact to the DB through the API."""
fact = Fact(
activity=fact_dict['activity'],
category=fact_dict['category'],
tags=fact_dict['tags'],
start_time=fact_dict['start_time'],
end_time=fact_dict['end_time'],
)
hamster_storage.add_fact(fact)
def main():
"""Main Routine."""
args = parse_arguments()
print 'Parsing CSV File...'
fact_list = read_csv_file(args.origin)
# Dry Run
if args.dryrun:
template = ('{category} | {activity} | {start_time} | '
'{end_time} | {tags}')
for fact in fact_list:
print template.format(**fact)
sys.exit(0)
# Send facts to Hamster
print 'Storing Facts on Hamster...'
hamster_storage = hamster.client.Storage()
for fact in fact_list:
add_hamster_fact(hamster_storage, fact)
print 'Done!'
if __name__ == '__main__':
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment