Commit 4d8c1b37 authored by Bram Schoenmakers's avatar Bram Schoenmakers

Drop Python 2.7 support

Supporting Python 2 resulted in some additional dependencies (six,
ushlex, get_terminal_size). Removing 2.7 support makes things a bit
easier and maintainable.
parent bbdfb2a5
sudo: false # run on new infrastructure
language: python
python:
- "2.7"
- "3.2"
- "3.3"
- "3.4"
......
......@@ -20,9 +20,6 @@ def find_version(*file_paths):
return version_match.group(1)
raise RuntimeError("Unable to find version string.")
_PYTHON_VERSION = sys.version_info
_IS_PYTHON_27 = _PYTHON_VERSION.major == 2 and _PYTHON_VERSION.minor == 7
setup(
name = "topydo",
packages = find_packages(exclude=["test"]),
......@@ -32,18 +29,13 @@ setup(
author_email = "me@bramschoenmakers.nl",
url = "https://github.com/bram85/topydo",
install_requires = [
'six >= 1.9.0',
'arrow >= 0.7.0',
'colorama >= 0.2.5' if sys.platform == "win32" else '',
# shutil.get_terminal_size() was introduced in Python 3.3
'backports.shutil_get_terminal_size>=1.0.0' if _IS_PYTHON_27 else '',
'ushlex' if _IS_PYTHON_27 else ''
],
extras_require = {
'ical': ['icalendar'],
'prompt-toolkit': ['prompt-toolkit >= 0.53'],
'test': ['coverage', 'freezegun', 'green', ],
'test:python_version=="2.7"': ['mock'],
'test:python_version!="3.2"': ['pylint'],
},
entry_points= {
......@@ -55,7 +47,6 @@ setup(
"Intended Audience :: End Users/Desktop",
"License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)",
"Natural Language :: English",
"Programming Language :: Python :: 2.7",
"Programming Language :: Python :: 3.2",
"Programming Language :: Python :: 3.3",
"Programming Language :: Python :: 3.4",
......
......@@ -18,8 +18,6 @@ import unittest
from datetime import date
from io import StringIO
from six import u
from test.command_testcase import CommandTest
from topydo.commands import AddCommand, ListCommand
from topydo.lib import TodoList
......@@ -298,29 +296,29 @@ class AddCommandTest(CommandTest):
self.assertEqual(self.errors, command.usage() + "\n")
def test_add_unicode(self):
command = AddCommand.AddCommand([u("Special \u25c4")], self.todolist,
command = AddCommand.AddCommand([u"Special \u25c4"], self.todolist,
self.out, self.error)
command.execute()
self.assertEqual(self.output,
u("| 1| {} Special \u25c4\n").format(self.today))
u"| 1| {} Special \u25c4\n".format(self.today))
self.assertEqual(self.errors, "")
@mock.patch("topydo.commands.AddCommand.stdin",
StringIO(u("Fo\u00f3 due:tod id:1\nB\u0105r before:1")))
StringIO(u"Fo\u00f3 due:tod id:1\nB\u0105r before:1"))
def test_add_from_stdin(self):
command = AddCommand.AddCommand(["-f", "-"], self.todolist, self.out,
self.error)
command.execute()
self.assertEqual(self.output, u("| 1| {tod} Fo\u00f3 due:{tod} id:1\n| 2| {tod} B\u0105r p:1\n".format(tod=self.today)))
self.assertEqual(self.output, u"| 1| {tod} Fo\u00f3 due:{tod} id:1\n| 2| {tod} B\u0105r p:1\n".format(tod=self.today))
self.assertEqual(self.errors, "")
def test_add_from_file(self):
command = AddCommand.AddCommand(["-f", "test/data/AddCommandTest-from_file.txt"], self.todolist, self.out, self.error)
command.execute()
self.assertEqual(self.output, u("| 1| {tod} Foo @fo\u00f3b\u0105r due:{tod} id:1\n| 2| {tod} Bar +baz t:{tod} p:1\n".format(tod=self.today)))
self.assertEqual(self.output, u"| 1| {tod} Foo @fo\u00f3b\u0105r due:{tod} id:1\n| 2| {tod} Bar +baz t:{tod} p:1\n".format(tod=self.today))
self.assertEqual(self.errors, "")
def test_add_task_without_date(self):
......
......@@ -16,8 +16,6 @@
import unittest
from six import u
from test.command_testcase import CommandTest
from topydo.commands.DeleteCommand import DeleteCommand
from topydo.lib.Config import config
......@@ -179,14 +177,14 @@ class DeleteCommandTest(CommandTest):
"""
Throw an error with invalid argument containing special characters.
"""
command = DeleteCommand([u("Fo\u00d3B\u0105r"), "Bar"], self.todolist,
command = DeleteCommand([u"Fo\u00d3B\u0105r", "Bar"], self.todolist,
self.out, self.error, None)
command.execute()
self.assertFalse(self.todolist.is_dirty())
self.assertEqual(self.output, "")
self.assertEqual(self.errors,
u("Invalid todo number given: Fo\u00d3B\u0105r.\n"))
u"Invalid todo number given: Fo\u00d3B\u0105r.\n")
def test_expr_del1(self):
command = DeleteCommand(["-e", "@test"], self.todolist, self.out,
......
......@@ -16,8 +16,6 @@
import unittest
from six import u
from test.command_testcase import CommandTest
from topydo.commands.DepriCommand import DepriCommand
from topydo.lib.TodoList import TodoList
......@@ -152,14 +150,14 @@ class DepriCommandTest(CommandTest):
"""
Throw an error with invalid argument containing special characters.
"""
command = DepriCommand([u("Fo\u00d3B\u0105r"), "Bar"], self.todolist,
command = DepriCommand([u"Fo\u00d3B\u0105r", "Bar"], self.todolist,
self.out, self.error, None)
command.execute()
self.assertFalse(self.todolist.is_dirty())
self.assertFalse(self.output)
self.assertEqual(self.errors,
u("Invalid todo number given: Fo\u00d3B\u0105r.\n"))
u"Invalid todo number given: Fo\u00d3B\u0105r.\n")
def test_empty(self):
command = DepriCommand([], self.todolist, self.out, self.error)
......
......@@ -17,8 +17,6 @@
import unittest
from datetime import date, timedelta
from six import u
from test.command_testcase import CommandTest
from topydo.commands.DoCommand import DoCommand
from topydo.lib.TodoList import TodoList
......@@ -357,13 +355,13 @@ class DoCommandTest(CommandTest):
"""
Throw an error with invalid argument containing special characters.
"""
command = DoCommand([u("Fo\u00d3B\u0105r"), "Bar"], self.todolist,
command = DoCommand([u"Fo\u00d3B\u0105r", "Bar"], self.todolist,
self.out, self.error, None)
command.execute()
self.assertFalse(self.todolist.is_dirty())
self.assertEqual(self.errors,
u("Invalid todo number given: Fo\u00d3B\u0105r.\n"))
u"Invalid todo number given: Fo\u00d3B\u0105r.\n")
def test_expr_do1(self):
command = DoCommand(["-e", "@test"], self.todolist, self.out,
......
......@@ -17,8 +17,6 @@
import os
import unittest
from six import u
from test.command_testcase import CommandTest
from topydo.commands.EditCommand import EditCommand
from topydo.lib.Config import config
......@@ -40,7 +38,7 @@ class EditCommandTest(CommandTest):
"Foo id:1",
"Bar p:1 @test",
"Baz @test",
u("Fo\u00f3B\u0105\u017a"),
u"Fo\u00f3B\u0105\u017a",
]
self.todolist = TodoList(todos)
......@@ -59,7 +57,7 @@ class EditCommandTest(CommandTest):
self.assertEqual(self.errors, "")
self.assertTrue(self.todolist.is_dirty())
self.assertEqual(self.todolist.print_todos(), u("Bar p:1 @test\nBaz @test\nFo\u00f3B\u0105\u017a\nFoo id:1"))
self.assertEqual(self.todolist.print_todos(), u"Bar p:1 @test\nBaz @test\nFo\u00f3B\u0105\u017a\nFoo id:1")
@mock.patch('topydo.commands.EditCommand._is_edited')
@mock.patch('topydo.commands.EditCommand.EditCommand._todos_from_temp')
......@@ -76,7 +74,7 @@ class EditCommandTest(CommandTest):
self.assertTrue(self.todolist.is_dirty())
self.assertEqual(self.errors, "")
self.assertEqual(self.todolist.print_todos(), u("Foo id:1\nBaz @test\nFo\u00f3B\u0105\u017a\nLazy Cat"))
self.assertEqual(self.todolist.print_todos(), u"Foo id:1\nBaz @test\nFo\u00f3B\u0105\u017a\nLazy Cat")
def test_edit03(self):
""" Throw an error after invalid todo number given as argument. """
......@@ -100,13 +98,13 @@ class EditCommandTest(CommandTest):
"""
Throw an error with invalid argument containing special characters.
"""
command = EditCommand([u("Fo\u00d3B\u0105r"), "Bar"], self.todolist,
command = EditCommand([u"Fo\u00d3B\u0105r", "Bar"], self.todolist,
self.out, self.error, None)
command.execute()
self.assertFalse(self.todolist.is_dirty())
self.assertEqual(self.errors,
u("Invalid todo number given: Fo\u00d3B\u0105r.\n"))
u"Invalid todo number given: Fo\u00d3B\u0105r.\n")
@mock.patch('topydo.commands.EditCommand._is_edited')
@mock.patch('topydo.commands.EditCommand.EditCommand._todos_from_temp')
......@@ -117,14 +115,14 @@ class EditCommandTest(CommandTest):
mock_todos_from_temp.return_value = [Todo('Lazy Cat')]
mock_is_edited.return_value = True
command = EditCommand([u("Fo\u00f3B\u0105\u017a")], self.todolist,
command = EditCommand([u"Fo\u00f3B\u0105\u017a"], self.todolist,
self.out, self.error, None)
command.execute()
self.assertTrue(self.todolist.is_dirty())
self.assertEqual(self.errors, "")
self.assertEqual(self.todolist.print_todos(),
u("Foo id:1\nBar p:1 @test\nBaz @test\nLazy Cat"))
u"Foo id:1\nBar p:1 @test\nBaz @test\nLazy Cat")
@mock.patch('topydo.commands.EditCommand._is_edited')
@mock.patch('topydo.commands.EditCommand.EditCommand._todos_from_temp')
......@@ -141,7 +139,7 @@ class EditCommandTest(CommandTest):
self.assertFalse(self.todolist.is_dirty())
self.assertEqual(self.errors, "Editing aborted. Nothing to do.\n")
self.assertEqual(self.todolist.print_todos(), u("Foo id:1\nBar p:1 @test\nBaz @test\nFo\u00f3B\u0105\u017a"))
self.assertEqual(self.todolist.print_todos(), u"Foo id:1\nBar p:1 @test\nBaz @test\nFo\u00f3B\u0105\u017a")
@mock.patch('topydo.commands.EditCommand._is_edited')
@mock.patch('topydo.commands.EditCommand.EditCommand._todos_from_temp')
......@@ -157,12 +155,12 @@ class EditCommandTest(CommandTest):
self.error, None)
command.execute()
expected = u("| 3| Lazy Cat\n| 4| Lazy Dog\n")
expected = u"| 3| Lazy Cat\n| 4| Lazy Dog\n"
self.assertEqual(self.errors, "")
self.assertTrue(self.todolist.is_dirty())
self.assertEqual(self.output, expected)
self.assertEqual(self.todolist.print_todos(), u("Foo id:1\nFo\u00f3B\u0105\u017a\nLazy Cat\nLazy Dog"))
self.assertEqual(self.todolist.print_todos(), u"Foo id:1\nFo\u00f3B\u0105\u017a\nLazy Cat\nLazy Dog")
@mock.patch('topydo.commands.EditCommand.check_call')
def test_edit_archive(self, mock_call):
......
......@@ -16,8 +16,6 @@
import unittest
from six import u
from test.topydo_testcase import TopydoTest
from topydo.Commands import get_subcommand
from topydo.commands.AddCommand import AddCommand
......@@ -60,7 +58,7 @@ class GetSubcommandTest(TopydoTest):
args = ["smile"]
real_cmd, final_args = get_subcommand(args)
self.assertTrue(issubclass(real_cmd, ListCommand))
self.assertEqual(final_args, [u("\u263b")])
self.assertEqual(final_args, [u"\u263b"])
def test_default_cmd01(self):
args = ["bar"]
......
......@@ -18,8 +18,6 @@ import codecs
import re
import unittest
from six import u
from test.command_testcase import CommandTest
from test.facilities import load_file_to_todolist
from topydo.commands.ListCommand import ListCommand
......@@ -316,13 +314,13 @@ class ListCommandUnicodeTest(CommandTest):
def test_list_unicode1(self):
""" Unicode filters."""
command = ListCommand([u("\u25c4")], self.todolist, self.out,
command = ListCommand([u"\u25c4"], self.todolist, self.out,
self.error)
command.execute()
self.assertFalse(self.todolist.is_dirty())
expected = u("| 1| (C) And some sp\u00e9cial tag:\u25c4\n")
expected = u"| 1| (C) And some sp\u00e9cial tag:\u25c4\n"
self.assertEqual(self.output, expected)
......
......@@ -17,8 +17,6 @@
import unittest
from datetime import date, timedelta
from six import u
from test.command_testcase import CommandTest
from topydo.commands.PostponeCommand import PostponeCommand
from topydo.lib.TodoList import TodoList
......@@ -252,14 +250,14 @@ class PostponeCommandTest(CommandTest):
def test_postpone20(self):
""" Throw an error with invalid argument containing special characters. """
command = PostponeCommand([u("Fo\u00d3B\u0105r"), "Bar", "1d"],
command = PostponeCommand([u"Fo\u00d3B\u0105r", "Bar", "1d"],
self.todolist, self.out, self.error, None)
command.execute()
self.assertFalse(self.todolist.is_dirty())
self.assertEqual(self.output, "")
self.assertEqual(self.errors,
u("Invalid todo number given: Fo\u00d3B\u0105r.\n"))
u"Invalid todo number given: Fo\u00d3B\u0105r.\n")
def test_expr_postpone1(self):
command = PostponeCommand(["-e", "due:tod", "2w"], self.todolist,
......
......@@ -16,8 +16,6 @@
import unittest
from six import u
from test.command_testcase import CommandTest
from topydo.commands.PriorityCommand import PriorityCommand
from topydo.lib.TodoList import TodoList
......@@ -198,14 +196,14 @@ class PriorityCommandTest(CommandTest):
"""
Throw an error with invalid argument containing special characters.
"""
command = PriorityCommand([u("Fo\u00d3B\u0105r"), "Bar", "C"],
command = PriorityCommand([u"Fo\u00d3B\u0105r", "Bar", "C"],
self.todolist, self.out, self.error, None)
command.execute()
self.assertFalse(self.todolist.is_dirty())
self.assertEqual(self.output, "")
self.assertEqual(self.errors,
u("Invalid todo number given: Fo\u00d3B\u0105r.\n"))
u"Invalid todo number given: Fo\u00d3B\u0105r.\n")
def test_invalid8(self):
"""
......
......@@ -20,7 +20,6 @@ import unittest
from datetime import date
from glob import glob
from six import u
from uuid import uuid4
from test.command_testcase import CommandTest
......
......@@ -16,8 +16,6 @@
import unittest
from six import u
from test.facilities import load_file
from test.topydo_testcase import TopydoTest
......@@ -32,7 +30,7 @@ class TodoFileTest(TopydoTest):
todofile = load_file('test/data/utf-8.txt')
self.assertEqual(todofile[0].source(),
u('(C) \u25ba UTF-8 test \u25c4'))
u'(C) \u25ba UTF-8 test \u25c4')
if __name__ == '__main__':
unittest.main()
......@@ -21,8 +21,6 @@ I/O on the command-line.
import getopt
import sys
from six import PY2
from six.moves import input
MAIN_OPTS = "ac:d:ht:v"
READ_ONLY_COMMANDS = ('List', 'ListContext', 'ListProject')
......@@ -128,9 +126,6 @@ class CLIApplicationBase(object):
def _process_flags(self):
args = sys.argv[1:]
if PY2:
args = [arg.decode('utf-8') for arg in args]
try:
opts, args = getopt.getopt(args, MAIN_OPTS)
except getopt.GetoptError as e:
......@@ -188,12 +183,6 @@ class CLIApplicationBase(object):
else:
pass # TODO
def _input(self):
"""
Returns a function that retrieves user input.
"""
return input
def is_read_only(self, p_command):
""" Returns True when the given command class is read-only. """
read_only_commands = tuple(cmd + 'Command' for cmd in ('Revert', ) +
......@@ -216,7 +205,7 @@ class CLIApplicationBase(object):
self.todolist,
lambda o: write(sys.stdout, o),
error,
self._input())
input)
if command.execute() != False:
return True
......
......@@ -24,13 +24,9 @@ from topydo.cli.CLIApplicationBase import CLIApplicationBase, error, usage
from topydo.cli.TopydoCompleter import TopydoCompleter
from prompt_toolkit.shortcuts import prompt
from prompt_toolkit.history import InMemoryHistory
from six import PY2
from topydo.lib.Config import config, ConfigError
if PY2:
import ushlex as shlex
# First thing is to poke the configuration and check whether it's sane
# The modules below may already read in configuration upon import, so
# make sure to bail out if the configuration is invalid.
......@@ -84,8 +80,6 @@ class PromptApplication(CLIApplicationBase):
self.todolist = TodoList.TodoList(self.todofile.read())
self.mtime = current_mtime
# suppress upstream issue with Python 2.7
# pylint: disable=no-value-for-parameter
self.completer = TopydoCompleter(self.todolist)
def run(self):
......
......@@ -18,8 +18,6 @@ import os
import tempfile
from subprocess import CalledProcessError, check_call
from six import u
from topydo.lib.Config import config
from topydo.lib.MultiCommand import MultiCommand
from topydo.lib.PrettyPrinterFilter import PrettyPrinterNumbers
......@@ -97,7 +95,7 @@ class EditCommand(MultiCommand):
if len(self.invalid_numbers) > 1 or len(self.invalid_numbers) > 0 and len(self.todos) > 0:
for number in self.invalid_numbers:
errors.append(u("Invalid todo number given: {}.").format(number))
errors.append(u"Invalid todo number given: {}.".format(number))
elif len(self.invalid_numbers) == 1 and len(self.todos) == 0:
errors.append("Invalid todo number given.")
......
......@@ -14,16 +14,10 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import configparser
import os
import shlex
from six import iteritems, PY2
from six.moves import configparser
if PY2:
import ushlex as shlex
import codecs
class ConfigError(Exception):
def __init__(self, p_text):
self.text = p_text
......@@ -121,7 +115,7 @@ class _Config:
for section in self.defaults:
self.cp.add_section(section)
for option, value in iteritems(self.defaults[section]):
for option, value in self.defaults[section].items():
self.cp.set(section, option, value)
files = [
......@@ -137,16 +131,7 @@ class _Config:
if p_path is not None:
files = [p_path]
if PY2:
for path in files:
try:
with codecs.open(path, 'r', encoding='utf-8') as f:
self.cp.readfp(f)
except IOError:
pass
else:
self.cp.read(files)
self.cp.read(files)
self._supplement_sections()
if p_overrides:
......
......@@ -19,8 +19,6 @@
import arrow
import re
from six import u
from topydo.lib.Config import config
from topydo.lib.Utils import get_terminal_size
......@@ -162,13 +160,13 @@ class ListFormatParser(object):
# list of tags (spaces) without hidden ones and due: and t:
'k': lambda t: ' '.join([u('{}:{}').format(tag, value)
'k': lambda t: ' '.join([u'{}:{}'.format(tag, value)
for tag, value in sorted(t.tags()) if
tag not in config().hidden_tags() +
[config().tag_start(), config().tag_due()]]),
# list of all tags (spaces)
'K': lambda t: ' '.join([u('{}:{}').format(tag, value)
'K': lambda t: ' '.join([u'{}:{}'.format(tag, value)
for tag, value in sorted(t.tags())]),
# priority
......
......@@ -14,8 +14,6 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from six import u
from topydo.lib.ExpressionCommand import ExpressionCommand
from topydo.lib.TodoListBase import InvalidTodoException
......@@ -90,7 +88,7 @@ class MultiCommand(ExpressionCommand):
if len(self.invalid_numbers) > 1 or len(self.invalid_numbers) > 0 and len(self.todos) > 0:
for number in self.invalid_numbers:
errors.append(u("Invalid todo number given: {}.").format(number))
errors.append(u"Invalid todo number given: {}.".format(number))
elif len(self.invalid_numbers) == 1 and len(self.todos) == 0:
errors.append("Invalid todo number given.")
elif len(self.todos) == 0 and len(self.invalid_numbers) == 0:
......
......@@ -19,7 +19,6 @@
import re
from collections import OrderedDict
from six import u
from topydo.lib.Colors import NEUTRAL_COLOR, Colors
from topydo.lib.Config import config
......@@ -99,7 +98,7 @@ class PrettyPrinterNumbers(PrettyPrinterFilter):
def filter(self, p_todo_str, p_todo):
""" Prepends the number to the todo string. """
return u("|{:>3}| {}").format(self.todolist.number(p_todo), p_todo_str)
return u"|{:>3}| {}".format(self.todolist.number(p_todo), p_todo_str)
class PrettyPrinterFormatFilter(PrettyPrinterFilter):
......
......@@ -21,8 +21,6 @@ This module contains the class that represents a single todo item.
import re
from datetime import date
from six import u
from topydo.lib.TodoParser import parse_line
from topydo.lib.Utils import is_valid_priority
......@@ -218,7 +216,7 @@ class TodoBase(object):
self.src = re.sub(
r'^(x \d{4}-\d{2}-\d{2} |\([A-Z]\) )?(\d{4}-\d{2}-\d{2} )?(.*)$',
lambda m:
u("{}{} {}").format(m.group(1) or '', p_date.isoformat(),
u"{}{} {}".format(m.group(1) or '', p_date.isoformat(),
m.group(3)), self.src)
def creation_date(self):
......
......@@ -21,8 +21,6 @@ A list of todo items.
import re
from datetime import date
from six import text_type
from topydo.lib import Filter
from topydo.lib.Config import config
from topydo.lib.HashListValues import hash_list_values
......@@ -128,7 +126,7 @@ class TodoListBase(object):
if not result:
# convert integer to text so we pass on a valid regex
result = todo_by_regexp(text_type(p_identifier))
result = todo_by_regexp(str(p_identifier))
return result
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment