diff --git a/.travis.yml b/.travis.yml index 346853a6..e415d4cc 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,11 +1,9 @@ language: python python: - - 2.7 - 3.5 - 3.6 - 3.7 - 3.8 - - pypy - pypy3 jobs: include: diff --git a/appveyor.yml b/appveyor.yml index de78ed90..03e48524 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -4,7 +4,6 @@ environment: matrix: # https://www.appveyor.com/docs/installed-software#python lists available # versions - - PYTHON: "C:\\Python27" - PYTHON: "C:\\Python35" - PYTHON: "C:\\Python36" - PYTHON: "C:\\Python37" diff --git a/setup.py b/setup.py index d2c8277e..f12625e5 100755 --- a/setup.py +++ b/setup.py @@ -46,9 +46,8 @@ def read(filename): ]) tests_require = ['freezegun'] -if sys.version_info < (3,): - # Python 2 doesn't have unittest.mock - tests_require.append('mock') +if sys.version_info < (3, 5, 0): + sys.exit("Python 3.5 is the minimum required version") setup( name='gtimelog', @@ -64,7 +63,6 @@ def read(filename): 'Development Status :: 4 - Beta', 'Environment :: X11 Applications :: GTK', 'License :: OSI Approved :: GNU General Public License (GPL)', - 'Programming Language :: Python :: 2.7', 'Programming Language :: Python :: 3.5', 'Programming Language :: Python :: 3.6', 'Programming Language :: Python :: 3.7', @@ -73,6 +71,7 @@ def read(filename): 'Programming Language :: Python :: Implementation :: PyPy', 'Topic :: Office/Business', ], + python_requires='>= 3.5', packages=find_packages('src'), package_dir={'': 'src'}, @@ -84,9 +83,6 @@ def read(filename): 'test': [ 'freezegun', ], - 'test:python_version == "2.7"': [ - 'mock', - ], }, zip_safe=False, entry_points=""" diff --git a/src/gtimelog/main.py b/src/gtimelog/main.py index 029b731a..59258325 100644 --- a/src/gtimelog/main.py +++ b/src/gtimelog/main.py @@ -1,6 +1,4 @@ """An application for keeping track of your time.""" -from __future__ import print_function, absolute_import - import time import sys @@ -90,20 +88,6 @@ def require_version(namespace, version): Reports, ReportRecord, TaskList, TimeLog) -if str is bytes: - # Python 2: GTK+ gives us back UTF-8 strings - def to_unicode(s): - return s.decode('UTF-8') - def to_bytes(s): - return s -else: - # Python 3: GTK+ gives us Unicode strings - def to_unicode(s): - return s - def to_bytes(s): - return s.encode('UTF-8') - - mark_time("gtimelog imports done") @@ -1951,7 +1935,7 @@ def update_subject(self, *args): return # not loaded yet window = self.get_time_window() reports = Reports(window) - name = to_unicode(self.name) + name = self.name if self.time_range == 'day': self._subject = reports.daily_report_subject(name) elif self.time_range == 'week': @@ -1969,8 +1953,8 @@ def populate_report(self): window = self.get_time_window() reports = Reports(window, email_headers=False, style=self.report_style) output = StringIO() - recipient = to_unicode(self.recipient) - name = to_unicode(self.name) + recipient = self.recipient + name = self.name if self.time_range == 'day': reports.daily_report(output, recipient, name) elif self.time_range == 'week': diff --git a/src/gtimelog/settings.py b/src/gtimelog/settings.py index 4ff5b7e8..f6c3b209 100644 --- a/src/gtimelog/settings.py +++ b/src/gtimelog/settings.py @@ -8,12 +8,7 @@ import locale import os -try: - from configparser import RawConfigParser - PY3 = True -except ImportError: - from ConfigParser import RawConfigParser - PY3 = False +from configparser import RawConfigParser from gtimelog.timelog import parse_time @@ -101,8 +96,8 @@ def _config(self): config = RawConfigParser() config.add_section('gtimelog') config.set('gtimelog', 'list-email', self.email) - config.set('gtimelog', 'name', self.from_unicode(self.name)) - config.set('gtimelog', 'sender', self.from_unicode(self.sender)) + config.set('gtimelog', 'name', self.name) + config.set('gtimelog', 'sender', self.sender) config.set('gtimelog', 'editor', self.editor) config.set('gtimelog', 'mailer', self.mailer) config.set('gtimelog', 'spreadsheet', self.spreadsheet) @@ -126,25 +121,14 @@ def _config(self): config.set('gtimelog', 'start_in_tray', str(self.start_in_tray)) return config - if PY3: # pragma: PY3 - def to_unicode(self, value): - return value # ConfigParser already gives us unicode - def from_unicode(self, value): - return value # ConfigParser already accepts unicode - else: # pragma: PY2 - def to_unicode(self, value): - return value.decode(self._encoding) - def from_unicode(self, value): - return value.encode(self._encoding) - def load(self, filename=None): if filename is None: filename = self.get_config_file() config = self._config() config.read([filename]) self.email = config.get('gtimelog', 'list-email') - self.name = self.to_unicode(config.get('gtimelog', 'name')) - self.sender = self.to_unicode(config.get('gtimelog', 'sender')) + self.name = config.get('gtimelog', 'name') + self.sender = config.get('gtimelog', 'sender') self.editor = config.get('gtimelog', 'editor') self.mailer = config.get('gtimelog', 'mailer') self.spreadsheet = config.get('gtimelog', 'spreadsheet') diff --git a/src/gtimelog/tests/test_main.py b/src/gtimelog/tests/test_main.py index 2906172e..860b93fa 100644 --- a/src/gtimelog/tests/test_main.py +++ b/src/gtimelog/tests/test_main.py @@ -4,12 +4,7 @@ import textwrap import unittest -try: - # Python 3 - from unittest import mock -except ImportError: - # Python 2 - import mock +from unittest import mock gi = mock.MagicMock() diff --git a/src/gtimelog/tests/test_timelog.py b/src/gtimelog/tests/test_timelog.py index 3153700f..d6fadcf2 100644 --- a/src/gtimelog/tests/test_timelog.py +++ b/src/gtimelog/tests/test_timelog.py @@ -10,19 +10,11 @@ import textwrap import time import unittest -import sys -try: - from cStringIO import StringIO -except ImportError: - from io import StringIO +import sys # noqa: F401 +from io import StringIO import freezegun -try: - # Python 3 - from unittest import mock -except ImportError: - # Python 2 - import mock +from unittest import mock from gtimelog.timelog import ( TimeLog, Reports, ReportRecord, Exports, TaskList, TimeCollection, diff --git a/src/gtimelog/timelog.py b/src/gtimelog/timelog.py index ab2bb728..7339c8b5 100644 --- a/src/gtimelog/timelog.py +++ b/src/gtimelog/timelog.py @@ -17,9 +17,6 @@ from operator import itemgetter -PY3 = sys.version_info[0] >= 3 - - def as_minutes(duration): """Convert a datetime.timedelta to an integer number of minutes.""" return duration.days * 24 * 60 + duration.seconds // 60 @@ -423,7 +420,7 @@ def to_csv_complete(self, output, title_row=True): The file has two columns: task title and time (in minutes). """ - writer = CSVWriter(output) + writer = csv.writer(output) if title_row: writer.writerow(["task", "time (minutes)"]) work, slack = self.window.grouped_entries() @@ -439,7 +436,7 @@ def to_csv_daily(self, output, title_row=True): The file has four columns: date, time from midnight til arrival at work, slacking, and work (in decimal hours). """ - writer = CSVWriter(output) + writer = csv.writer(output) if title_row: writer.writerow(["date", "day-start (hours)", "slacking (hours)", "work (hours)"]) @@ -1127,23 +1124,3 @@ def load(self): def reload(self): """Reload the task list.""" self.load() - - -class CSVWriter(object): - - def __init__(self, *args, **kw): - self._writer = csv.writer(*args, **kw) - - if PY3: # pragma: PY3 - def writerow(self, row): - self._writer.writerow(row) - else: # pragma: PY2 - def writerow(self, row): - self._writer.writerow([ - s.encode('UTF-8') if isinstance(s, unicode) else s # noqa: F821 - for s in row - ]) - - def writerows(self, rows): - for row in rows: - self.writerow(row) diff --git a/tox.ini b/tox.ini index 953138c9..7972e6e3 100644 --- a/tox.ini +++ b/tox.ini @@ -1,14 +1,12 @@ [tox] envlist = - py27,py35,py36,py37,py38,pypy,pypy3,flake8 + py35,py36,py37,py38,pypy3,flake8 [testenv] setenv = LC_ALL=C deps = freezegun - py27: mock - pypy: mock skip_install = true commands = pip install --no-deps -e .