From e008454cf5c1a35f0cacf4df9cb1e5c64a9178da Mon Sep 17 00:00:00 2001 From: EpocDotFr Date: Mon, 5 Dec 2016 09:55:45 +0100 Subject: [PATCH] Use dicts for tags instead of list of tuples --- README.md | 38 +++++++++++++++++++++----------------- setup.py | 2 +- todotxtio.py | 22 +++++++++++++++------- 3 files changed, 37 insertions(+), 25 deletions(-) diff --git a/README.md b/README.md index 8ba4450..98e361b 100644 --- a/README.md +++ b/README.md @@ -2,22 +2,28 @@ A simple Python module to parse, manipulate and write [Todo.txt](http://todotxt.com/) data. -[![PyPI](https://img.shields.io/pypi/v/todotxtio.svg)]() [![PyPI](https://img.shields.io/pypi/l/todotxtio.svg)]() +[![PyPI](https://img.shields.io/pypi/pyversions/todotxtio.svg)]() [![PyPI](https://img.shields.io/pypi/v/todotxtio.svg)]() [![PyPI](https://img.shields.io/pypi/l/todotxtio.svg)]() -This module 100% comply to the [Todo.txt specifications](https://github.com/ginatrapani/todo.txt-cli/wiki/The-Todo.txt-Format). There aren't any unit tests, but trust me. +This module tries to comply to the [Todo.txt specifications](https://github.com/ginatrapani/todo.txt-cli/wiki/The-Todo.txt-Format) (disclaimer: there aren't any unit tests). ## Prerequisites -[![PyPI](https://img.shields.io/pypi/pyversions/todotxtio.svg)]() - Should work on any Python 3.x version. Feel free to test with another Python version and give me feedback. ## Installation +The usual way: + ``` pip install todotxtio ``` +The McGyver way, after cloning/downloading this repo: + +``` +python setup.py install +``` + ## Usage Firstly, import the module: @@ -35,11 +41,9 @@ The functions below all return a plain-old Python list filled with `Todo` object **Parsing from a file:** ```python -todos = todotxtio.from_file('todo.txt') +todos = todotxtio.from_file('todo.txt', encoding='utf-8') # utf-8 is the default ``` -**Note:** The Todo.txt file is assumed to be UTF-8 encoded. - **Parsing from a string:** ```python @@ -201,28 +205,28 @@ Of course, inverse is also applicable (setting `completed` to `False` removes th #### Tags -Tags, also called add-ons metadata, are lists of key/value represented by a tuple. They allow you to easily -define and retrieve custom data: +Tags, also called add-ons metadata, are represented by a simple one-dimension dictionary. They allow you to easily +define and retrieve custom formatted data: ```python todo = todotxtio.Todo( text='Thank Guido for such an awesome programming language' ) -todo.tags = [ # Define some tags - ('key', 'value'), - ('second', 'tag') -] +todo.tags = { # Define some tags + 'key': 'value', + 'second': 'tag' +} -todo.tags.append(('due', '2016-12-01')) # Append to existing +todo.tags['due'] = '2016-12-01' # Remove a tag -del todo.tags[1] +del todo.tags['second'] print(todo) # Thank Guido for such an awesome programming language key:value due:2016-12-01 # Empty tags -todo.tags = [] # Or None +todo.tags = {} # Or None ``` #### Searching a todo list @@ -257,7 +261,7 @@ At some point you'll need to save your todo list. ```python # todos is a list of Todo objects -todotxtio.to_file('todo.txt', todos) +todotxtio.to_file('todo.txt', todos, encoding='utf-8') # utf-8 is the default ``` **Caution:** This will overwrite the whole file. Also, data will be UTF-8 encoded. diff --git a/setup.py b/setup.py index 1a66c1c..fd9f58d 100644 --- a/setup.py +++ b/setup.py @@ -6,7 +6,7 @@ name='todotxtio', version=todotxtio.__version__, description='A simple Python module to parse, manipulate and write Todo.txt data', - long_description='All you need to know is located `here `_.', + long_description='You can find the documentation `here `_.', url='https://github.com/EpocDotFr/todotxtio', author='Maxime "Epoc" G.', author_email='contact.nospam@epoc.nospam.fr', diff --git a/todotxtio.py b/todotxtio.py index d451633..7599765 100644 --- a/todotxtio.py +++ b/todotxtio.py @@ -1,7 +1,7 @@ import os import re -__version__ = '0.1.0' +__version__ = '0.2.0' __all__ = [ 'from_dicts', @@ -99,7 +99,9 @@ def from_string(string): todo_tags = todo_tag_regex.findall(text) if len(todo_tags) > 0: - todo.tags = todo_tags + for todo_tag in todo_tags: + todo.tags[todo_tag[0]] = todo_tag[1] + text = todo_tag_regex.sub('', text).strip() todo.text = text @@ -146,7 +148,7 @@ class Todo: :param str creation_date: A create date, in the YYYY-MM-DD format (default to None) :param list projects: A list of projects without + (default to an empty list) :param list contexts: A list of projects without @ (default to an empty list) - :param list tags: A list of tags (default to an empty list) + :param list tags: A dict of tags (default to an empty dict) """ text = None completed = False @@ -155,7 +157,7 @@ class Todo: creation_date = None projects = [] contexts = [] - tags = [] + tags = {} def __init__(self, text=None, completed=False, completion_date=None, priority=None, creation_date=None, projects=None, contexts=None, tags=None): self.text = text @@ -192,12 +194,18 @@ def __setattr__(self, name, value): super().__setattr__('completed', True) # Setting the completion date must set this todo as completed... else: super().__setattr__('completed', False) # ...and vice-versa - elif name in ['projects', 'contexts', 'tags']: + elif name in ['projects', 'contexts']: if not value: - super().__setattr__(name, []) # Force contexts, projects and tags to be lists when setting them to a falsely value + super().__setattr__(name, []) # Force contexts, projects to be lists when setting them to a falsely value return elif type(value) is not list: # Make sure, otherwise, that the provided value is a list raise ValueError(name + ' should be a list') + elif name == 'tags': + if not value: + super().__setattr__(name, {}) # Force tags to be a dict when setting them to a falsely value + return + elif type(value) is not dict: # Make sure, otherwise, that the provided value is a dict + raise ValueError(name + ' should be a dict') super().__setattr__(name, value) @@ -226,7 +234,7 @@ def __str__(self): ret.append(''.join([' @' + context for context in self.contexts]).strip()) if self.tags: - ret.append(''.join([' ' + tag[0] + ':' + tag[1] for tag in self.tags]).strip()) + ret.append(''.join([' ' + tag_name + ':' + tag_value for tag_name, tag_value in self.tags.items()]).strip()) return ' '.join(ret)