diff --git a/.travis.yml b/.travis.yml index 6427f87..16dc26f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,10 +1,9 @@ language: python python: - - 2.7 - 3.6 install: - pip install nose - - ./setup.py develop + - pip install -e . script: - nosetests tests notifications: diff --git a/MANIFEST.in b/MANIFEST.in deleted file mode 100644 index 3ec22ce..0000000 --- a/MANIFEST.in +++ /dev/null @@ -1,5 +0,0 @@ -include README.rst LICENSE CHANGES simulate.py -include scripts/tarsnapper - -recursive-include tests * -recursive-exclude tests *.pyc \ No newline at end of file diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..c6182fb --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "tarsnapper" +version = "0.5.0" +description = "Manages tarsnap backups" +readme = "README.md" +authors = [{ name = "Michael Elsdoerfer", email = "michael@elsdoerfer.com" }] +classifiers = [ + "License :: OSI Approved :: BSD License", + "Programming Language :: Python :: 3", +] +dependencies = ["pexpect>=3.1", "python-dateutil>=2.4.0", "pyyaml>=3.09"] +license = { text = "BSD" } +requires-python = ">=3.6" + +[project.scripts] +tarsnapper = "tarsnapper.script:run" + +[project.urls] +Homepage = "http://github.com/miracle2k/tarsnapper" + +[tool.flit.sdist] +include = ["simulate.py", "tests/"] + +[build-system] +requires = ["flit_core >=3.2,<4"] +build-backend = "flit_core.buildapi" diff --git a/scripts/tarsnapper b/scripts/tarsnapper deleted file mode 100644 index f88c7e0..0000000 --- a/scripts/tarsnapper +++ /dev/null @@ -1,3 +0,0 @@ -#!/usr/bin/env python -import tarsnapper.script -tarsnapper.script.run() \ No newline at end of file diff --git a/setup.py b/setup.py deleted file mode 100755 index 712204c..0000000 --- a/setup.py +++ /dev/null @@ -1,50 +0,0 @@ -#!/usr/bin/env python -# encoding: utf8 -"""Adapted from virtualenv's setup.py. -""" - -import sys, os -try: - from setuptools import setup -except ImportError: - from distutils.core import setup - kw = {'scripts': ['scripts/tarsnapper']} -else: - kw = {'entry_points': - """[console_scripts]\ntarsnapper = tarsnapper.script:run\n""", - 'zip_safe': False} -import re - -here = os.path.dirname(os.path.abspath(__file__)) - -# Figure out the version -version_re = re.compile( - r'__version__ = (\(.*?\))') -fp = open(os.path.join(here, 'tarsnapper/__init__.py')) -version = None -for line in fp: - match = version_re.search(line) - if match: - exec("version = %s" % match.group(1)) - version = ".".join(map(str, version)) - break -else: - raise Exception("Cannot find version in __init__.py") -fp.close() - -setup(name='tarsnapper', - version=version, - description="Manages tarsnap backups", - classifiers=[ - 'License :: OSI Approved :: BSD License', - 'Programming Language :: Python :: 2', - 'Programming Language :: Python :: 3' - ], - author='Michael Elsdoerfer', - author_email='michael@elsdoerfer.com', - url='http://github.com/miracle2k/tarsnapper', - license='BSD', - packages=['tarsnapper'], - install_requires = ['argparse>=1.1', 'pyyaml>=3.09', 'python-dateutil>=2.4.0', 'pexpect>=3.1'], - **kw -) diff --git a/tarsnapper/config.py b/tarsnapper/config.py index eb5b45e..7380b7a 100644 --- a/tarsnapper/config.py +++ b/tarsnapper/config.py @@ -38,7 +38,6 @@ source: /important-2/ delta: important """ -from __future__ import print_function from datetime import timedelta import glob @@ -55,7 +54,7 @@ class ConfigError(Exception): pass -class Job(object): +class Job: """Represent a single backup job.""" def __init__(self, **initial): @@ -205,7 +204,7 @@ def load_job(job_name, job_dict): # can only be used for selected commands, then. require_placeholders(new_job.target, ['date'], '%s: target') if job_dict: - raise ConfigError('%s has unsupported configuration values: %s' % ( + raise ConfigError('{} has unsupported configuration values: {}'.format( job_name, ", ".join(job_dict.keys()))) return new_job diff --git a/tarsnapper/expire.py b/tarsnapper/expire.py index 8b086d0..3548b40 100644 --- a/tarsnapper/expire.py +++ b/tarsnapper/expire.py @@ -55,7 +55,7 @@ def expire(backups, deltas): # Always keep the most recent backup most_recent_backup = backups[0][1] - to_keep = set([backups[0][0]]) + to_keep = {backups[0][0]} # Then, for each delta/generation, determine which backup to keep last_delta = deltas.pop() diff --git a/tarsnapper/script.py b/tarsnapper/script.py index 1fed919..758434f 100644 --- a/tarsnapper/script.py +++ b/tarsnapper/script.py @@ -1,5 +1,3 @@ -from __future__ import print_function - import argparse from datetime import datetime import getpass @@ -28,7 +26,7 @@ class TarsnapError(Exception): pass -class TarsnapBackend(object): +class TarsnapBackend: """ The code that calls the tarsnap executable. @@ -61,7 +59,7 @@ def call(self, *arguments): for option in self.options: key = option[0] pre = "-" if len(key) == 1 else "--" - call_with.append("%s%s" % (pre, key)) + call_with.append("{}{}".format(pre, key)) for value in option[1:]: call_with.append(value) call_with.extend(arguments) @@ -77,7 +75,7 @@ def _exec_tarsnap(self, args): child.logfile = sys.stdout # look for the passphrase prompt - has_prompt = (child.expect([u'Please enter passphrase for keyfile .*?:', pexpect.EOF]) == 0) + has_prompt = (child.expect(['Please enter passphrase for keyfile .*?:', pexpect.EOF]) == 0) if has_prompt: child.sendline(self._get_key_passphrase()) child.expect(pexpect.EOF) @@ -85,7 +83,7 @@ def _exec_tarsnap(self, args): child.close() if child.exitstatus != 0: - raise TarsnapError("tarsnap failed with status {0}:{1}{2}".format( + raise TarsnapError("tarsnap failed with status {}:{}{}".format( child.exitstatus, os.linesep, out)) return out @@ -100,7 +98,7 @@ def _exec_util(self, cmdline, shell=False): p = subprocess.Popen(cmdline, shell=True) p.communicate() if p.returncode: - raise RuntimeError('%s failed with exit code %s' % ( + raise RuntimeError('{} failed with exit code {}'.format( cmdline, p.returncode)) def _add_known_archive(self, name): @@ -263,7 +261,7 @@ def timedelta_string(value): raise argparse.ArgumentTypeError('invalid delta value: %r (suffix d, s allowed)' % e) -class Command(object): +class Command: BackendClass = TarsnapBackend @@ -536,7 +534,7 @@ def main(argv): if unknown: log.error('Error: not defined in the config file: %s', ", ".join(unknown)) return 1 - jobs_to_run = dict([(n, j) for n, j in jobs.items() if n in args.jobs]) + jobs_to_run = {n: j for n, j in jobs.items() if n in args.jobs} else: jobs_to_run = jobs diff --git a/tarsnapper/test.py b/tarsnapper/test.py index cd44ac5..ca5f54d 100644 --- a/tarsnapper/test.py +++ b/tarsnapper/test.py @@ -13,7 +13,7 @@ __all__ = ('BackupSimulator',) -class BackupSimulator(object): +class BackupSimulator: """Helper to simulate making backups, and expire old ones, at various points in time. """ diff --git a/tests/test_script.py b/tests/test_script.py index 5c6ef25..4c463b7 100644 --- a/tests/test_script.py +++ b/tests/test_script.py @@ -22,7 +22,7 @@ def __init__(self, *a, **kw): def _exec_tarsnap(self, args): self.calls.append(args[1:]) # 0 is "tarsnap" if '--list-archives' in args: - return u"\n".join(self.fake_archives) + return "\n".join(self.fake_archives) def _exec_util(self, cmdline): self.calls.append(cmdline) @@ -44,7 +44,7 @@ def match(self, expect_calls): return True -class BaseTest(object): +class BaseTest: def setup(self): self.log = logging.getLogger("test_script")