diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
new file mode 100644
index 0000000..fc1c641
--- /dev/null
+++ b/.pre-commit-config.yaml
@@ -0,0 +1,15 @@
+repos:
+ - repo: https://github.com/pre-commit/pre-commit-hooks
+ rev: v2.4.0
+ hooks:
+ - id: trailing-whitespace
+ args: [--markdown-linebreak-ext=md]
+ - id: end-of-file-fixer
+ - id: check-toml
+ - id: check-added-large-files
+ - id: debug-statements
+ - repo: https://gitlab.com/pycqa/flake8
+ rev: "master" # pick a git hash / tag to point to
+ hooks:
+ - id: flake8
+ additional_dependencies: [flake8-import-order, flake8-bugbear]
diff --git a/.travis.yml b/.travis.yml
index f81bc77..04b6d49 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -2,6 +2,7 @@
"branches": {
"only": [
"auto",
+ "next",
"master",
"/^.*-maintenance$/"
]
@@ -13,9 +14,6 @@
},
"install": [
". scripts/travis-install.sh",
- "pip install -U pip setuptools",
- "pip install wheel",
- "make -e install-dev",
"make -e install-$BUILD"
],
"language": "python",
diff --git a/Makefile b/Makefile
index 9f69944..7efe354 100644
--- a/Makefile
+++ b/Makefile
@@ -71,7 +71,7 @@ install-servers:
(cd $(TESTSERVER_BASE)$$server && sh install.sh); \
done
-install-test: install-servers
+install-test: install-servers install-dev
pip install -Ur test-requirements.txt
set -xe && if [ "$$REQUIREMENTS" = "devel" ]; then \
pip install -U --force-reinstall \
@@ -81,9 +81,9 @@ install-test: install-servers
fi
[ -z "$(TEST_EXTRA_PACKAGES)" ] || pip install $(TEST_EXTRA_PACKAGES)
-install-style: install-docs
- pip install -U flake8==3.5.0 flake8-import-order 'flake8-bugbear>=17.3.0' autopep8
-
+install-style: install-docs install-dev
+ pip install -U flake8 flake8-import-order flake8-bugbear autopep8
+
style:
flake8
! git grep -i syncroniz */*
@@ -114,6 +114,7 @@ release-deb:
sh scripts/release-deb.sh ubuntu zesty
install-dev:
+ pip install -U pip setuptools wheel
pip install -e .
[ "$(ETESYNC_TESTS)" = "false" ] || pip install -Ue .[etesync]
set -xe && if [ "$(REQUIREMENTS)" = "devel" ]; then \
diff --git a/README.rst b/README.rst
index fb8c82d..10ba6d1 100644
--- a/README.rst
+++ b/README.rst
@@ -2,6 +2,26 @@
vdirsyncer
==========
+.. image:: https://travis-ci.org/pimutils/vdirsyncer.svg?branch=master
+ :target: https://travis-ci.org/pimutils/vdirsyncer
+ :alt: CI status
+
+.. image:: https://codecov.io/github/pimutils/vdirsyncer/coverage.svg?branch=master
+ :target: https://codecov.io/github/pimutils/vdirsyncer?branch=master
+ :alt: Codecov coverage report
+
+.. image:: https://readthedocs.org/projects/vdirsyncer/badge/
+ :target: https://vdirsyncer.rtfd.org/
+ :alt: documentation
+
+.. image:: https://img.shields.io/pypi/v/vdirsyncer.svg
+ :target: https://pypi.python.org/pypi/vdirsyncer
+ :alt: version on pypi
+
+.. image:: https://img.shields.io/pypi/l/vdirsyncer.svg
+ :target: https://github.com/pimutils/vdirsyncer/blob/master/LICENCE
+ :alt: licence: BSD
+
- `Documentation `_
- `Source code `_
@@ -20,15 +40,6 @@ It aims to be for calendars and contacts what `OfflineIMAP
.. _programs: https://vdirsyncer.pimutils.org/en/latest/tutorials/
-.. image:: https://travis-ci.org/pimutils/vdirsyncer.svg?branch=master
- :target: https://travis-ci.org/pimutils/vdirsyncer
-
-.. image:: https://codecov.io/github/pimutils/vdirsyncer/coverage.svg?branch=master
- :target: https://codecov.io/github/pimutils/vdirsyncer?branch=master
-
-.. image:: https://badge.waffle.io/pimutils/vdirsyncer.svg?label=ready&title=Ready
- :target: https://waffle.io/pimutils/vdirsyncer
-
Links of interest
=================
diff --git a/docs/changelog.rst b/docs/changelog.rst
index 1743454..565b052 100644
--- a/docs/changelog.rst
+++ b/docs/changelog.rst
@@ -1 +1 @@
-.. include:: ../CHANGELOG.rst
+.. include:: ../CHANGELOG.rst
diff --git a/docs/conf.py b/docs/conf.py
index bbcd7e0..385d2e8 100644
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -1,9 +1,7 @@
-# -*- coding: utf-8 -*-
-
import datetime
import os
-import setuptools_scm
+from pkg_resources import get_distribution
extensions = ['sphinx.ext.autodoc']
@@ -12,11 +10,11 @@ templates_path = ['_templates']
source_suffix = '.rst'
master_doc = 'index'
-project = u'vdirsyncer'
-copyright = (u'2014-{}, Markus Unterwaditzer & contributors'
+project = 'vdirsyncer'
+copyright = ('2014-{}, Markus Unterwaditzer & contributors'
.format(datetime.date.today().strftime('%Y')))
-release = setuptools_scm.get_version(root='..', relative_to=__file__)
+release = get_distribution('vdirsyncer').version
version = '.'.join(release.split('.')[:2]) # The short X.Y version.
rst_epilog = '.. |vdirsyncer_version| replace:: %s' % release
@@ -44,18 +42,18 @@ htmlhelp_basename = 'vdirsyncerdoc'
latex_elements = {}
latex_documents = [
- ('index', 'vdirsyncer.tex', u'vdirsyncer Documentation',
- u'Markus Unterwaditzer', 'manual'),
+ ('index', 'vdirsyncer.tex', 'vdirsyncer Documentation',
+ 'Markus Unterwaditzer', 'manual'),
]
man_pages = [
- ('index', 'vdirsyncer', u'vdirsyncer Documentation',
- [u'Markus Unterwaditzer'], 1)
+ ('index', 'vdirsyncer', 'vdirsyncer Documentation',
+ ['Markus Unterwaditzer'], 1)
]
texinfo_documents = [
- ('index', 'vdirsyncer', u'vdirsyncer Documentation',
- u'Markus Unterwaditzer', 'vdirsyncer',
+ ('index', 'vdirsyncer', 'vdirsyncer Documentation',
+ 'Markus Unterwaditzer', 'vdirsyncer',
'Synchronize calendars and contacts.', 'Miscellaneous'),
]
diff --git a/docs/config.rst b/docs/config.rst
index c54b0cd..425f740 100644
--- a/docs/config.rst
+++ b/docs/config.rst
@@ -286,7 +286,7 @@ Service to hardcode those into opensource software [googleterms]_:
3. In the sidebar, select "Credentials" and create a new "OAuth Client ID". The
application type is "Other".
-
+
You'll be prompted to create a OAuth consent screen first. Fill out that
form however you like.
@@ -368,7 +368,7 @@ password. Neither are stored.
secrets_dir = ...
#server_path = ...
#db_path = ...
-
+
:param email: The email address of your account.
:param secrets_dir: A directory where vdirsyncer can store the encryption
key and authentication token.
@@ -386,7 +386,7 @@ password. Neither are stored.
secrets_dir = ...
#server_path = ...
#db_path = ...
-
+
:param email: The email address of your account.
:param secrets_dir: A directory where vdirsyncer can store the encryption
key and authentication token.
diff --git a/docs/keyring.rst b/docs/keyring.rst
index 2447f96..b3fc442 100644
--- a/docs/keyring.rst
+++ b/docs/keyring.rst
@@ -60,7 +60,7 @@ passwords from the OS's password store. Installation::
Basic usage::
password.fetch = ["command", "keyring", "get", "example.com", "foouser"]
-
+
.. _keyring: https://github.com/jaraco/keyring/
Password Prompt
diff --git a/docs/tutorials/baikal.rst b/docs/tutorials/baikal.rst
index 815750d..f721fc7 100644
--- a/docs/tutorials/baikal.rst
+++ b/docs/tutorials/baikal.rst
@@ -7,4 +7,4 @@ Vdirsyncer is continuously tested against the latest version of Baikal_.
- Baikal up to ``0.2.7`` also uses an old version of SabreDAV, with the same
issue as ownCloud, see :gh:`160`. This issue is fixed in later versions.
-.. _Baikal: http://baikal-server.com/
+.. _Baikal: http://sabre.io/baikal/
diff --git a/docs/tutorials/claws-mail.rst b/docs/tutorials/claws-mail.rst
index 337b863..fba9e98 100644
--- a/docs/tutorials/claws-mail.rst
+++ b/docs/tutorials/claws-mail.rst
@@ -69,7 +69,7 @@ Now we discover and sync our contacts::
Claws Mail
----------
-Open Claws-Mail. Got to **Tools** => **Addressbook**.
+Open Claws-Mail. Go to **Tools** => **Addressbook**.
Click on **Addressbook** => **New vCard**. Choose a name for the book.
@@ -77,7 +77,7 @@ Then search for the for the vCard in the folder **~/.contacts/**. Click
ok, and you we will see your contacts.
.. note::
-
+
Claws-Mail shows only contacts that have a mail address.
Crontab
diff --git a/docs/tutorials/fastmail.rst b/docs/tutorials/fastmail.rst
index d066de3..5f133ef 100644
--- a/docs/tutorials/fastmail.rst
+++ b/docs/tutorials/fastmail.rst
@@ -10,13 +10,13 @@ the settings to use::
[storage cal]
type = "caldav"
- url = "https://caldav.messagingengine.com/"
+ url = "https://caldav.fastmail.com/"
username = ...
password = ...
[storage card]
type = "carddav"
- url = "https://carddav.messagingengine.com/"
+ url = "https://carddav.fastmail.com/"
username = ...
password = ...
diff --git a/docs/when.rst b/docs/when.rst
index b69aed4..a7ae997 100644
--- a/docs/when.rst
+++ b/docs/when.rst
@@ -39,7 +39,7 @@ program chosen:
* Like with ``todo.txt``, Dropbox and friends are obviously agnostic/unaware of
the files' contents. If a file has changed on both sides, Dropbox just copies
both versions to both sides.
-
+
This is a good idea if the user is directly interfacing with the file system
and is able to resolve conflicts themselves. Here it might lead to
erroneous behavior with e.g. ``khal``, since there are now two events with
diff --git a/scripts/dpkg.Dockerfile b/scripts/dpkg.Dockerfile
index 78c8aab..09d9f24 100644
--- a/scripts/dpkg.Dockerfile
+++ b/scripts/dpkg.Dockerfile
@@ -9,7 +9,7 @@ ARG distrover
RUN apt-get update
RUN apt-get install -y build-essential fakeroot debhelper git
RUN apt-get install -y python3-all python3-pip
-RUN apt-get install -y ruby ruby-dev
+RUN apt-get install -y ruby ruby-dev
RUN apt-get install -y python-all python-pip
RUN gem install fpm
diff --git a/scripts/make_travisconf.py b/scripts/make_travisconf.py
index 15f872c..afca282 100644
--- a/scripts/make_travisconf.py
+++ b/scripts/make_travisconf.py
@@ -17,14 +17,11 @@ cfg['git'] = {
}
cfg['branches'] = {
- 'only': ['auto', 'master', '/^.*-maintenance$/']
+ 'only': ['auto', 'next', 'master', '/^.*-maintenance$/']
}
cfg['install'] = """
. scripts/travis-install.sh
-pip install -U pip setuptools
-pip install wheel
-make -e install-dev
make -e install-$BUILD
""".strip().splitlines()
diff --git a/setup.cfg b/setup.cfg
index 4635543..ec67785 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -9,6 +9,8 @@ addopts = --tb=short
# E731: Use a def instead of lambda expr
# E743: Ambiguous function definition
ignore = E731, E743
+# E503: Line break occurred before a binary operator
+extend-ignore = W503
select = C,E,F,W,B,B9
exclude = .eggs, tests/storage/servers/owncloud/, tests/storage/servers/nextcloud/, tests/storage/servers/baikal/, build/
application-package-names = tests,vdirsyncer
diff --git a/setup.py b/setup.py
index 552165f..c9b986c 100644
--- a/setup.py
+++ b/setup.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
'''
Vdirsyncer synchronizes calendars and contacts.
@@ -18,14 +17,7 @@ requirements = [
# https://github.com/pimutils/vdirsyncer/issues/478
'click-threading>=0.2',
- # !=2.9.0: https://github.com/kennethreitz/requests/issues/2930
- #
- # >=2.4.1: https://github.com/shazow/urllib3/pull/444
- # Without the above pull request, `verify=False` also disables fingerprint
- # validation. This is *not* what we want, and it's not possible to
- # replicate vdirsyncer's current behavior (verifying fingerprints without
- # verifying against CAs) with older versions of urllib3.
- 'requests >=2.4.1, !=2.9.0',
+ 'requests >=2.20.0',
# https://github.com/sigmavirus24/requests-toolbelt/pull/28
# And https://github.com/sigmavirus24/requests-toolbelt/issues/54
diff --git a/test-requirements.txt b/test-requirements.txt
index d05994c..feb39a6 100644
--- a/test-requirements.txt
+++ b/test-requirements.txt
@@ -1,4 +1,4 @@
-hypothesis>=3.1,<4.0
+hypothesis>=5.0.0
pytest
pytest-localserver
pytest-subtesthack
diff --git a/tests/__init__.py b/tests/__init__.py
index 9103d74..6948552 100644
--- a/tests/__init__.py
+++ b/tests/__init__.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
'''
Test suite for vdirsyncer.
'''
@@ -21,7 +20,7 @@ def assert_item_equals(a, b):
assert normalize_item(a) == normalize_item(b)
-VCARD_TEMPLATE = u'''BEGIN:VCARD
+VCARD_TEMPLATE = '''BEGIN:VCARD
VERSION:3.0
FN:Cyrus Daboo
N:Daboo;Cyrus;;;
@@ -37,7 +36,7 @@ X-SOMETHING:{r}
UID:{uid}
END:VCARD'''
-TASK_TEMPLATE = u'''BEGIN:VCALENDAR
+TASK_TEMPLATE = '''BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//dmfs.org//mimedir.icalendar//EN
BEGIN:VTODO
@@ -52,7 +51,7 @@ END:VTODO
END:VCALENDAR'''
-BARE_EVENT_TEMPLATE = u'''BEGIN:VEVENT
+BARE_EVENT_TEMPLATE = '''BEGIN:VEVENT
DTSTART:19970714T170000Z
DTEND:19970715T035959Z
SUMMARY:Bastille Day Party
@@ -61,10 +60,10 @@ UID:{uid}
END:VEVENT'''
-EVENT_TEMPLATE = u'''BEGIN:VCALENDAR
+EVENT_TEMPLATE = '''BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//hacksw/handcal//NONSGML v1.0//EN
-''' + BARE_EVENT_TEMPLATE + u'''
+''' + BARE_EVENT_TEMPLATE + '''
END:VCALENDAR'''
EVENT_WITH_TIMEZONE_TEMPLATE = '''BEGIN:VCALENDAR
@@ -90,7 +89,7 @@ END:VTIMEZONE
END:VCALENDAR'''
-SIMPLE_TEMPLATE = u'''BEGIN:FOO
+SIMPLE_TEMPLATE = '''BEGIN:FOO
UID:{uid}
X-SOMETHING:{r}
HAHA:YES
diff --git a/tests/conftest.py b/tests/conftest.py
index eb8ffac..afd5aff 100644
--- a/tests/conftest.py
+++ b/tests/conftest.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
'''
General-purpose fixtures for vdirsyncer's testsuite.
'''
@@ -34,8 +33,7 @@ settings.register_profile("ci", settings(
))
settings.register_profile("deterministic", settings(
derandomize=True,
- perform_health_check=False,
- suppress_health_check=[HealthCheck.too_slow],
+ suppress_health_check=HealthCheck.all(),
))
if os.environ.get('DETERMINISTIC_TESTS', 'false').lower() == 'true':
diff --git a/tests/storage/__init__.py b/tests/storage/__init__.py
index ecb8b36..9add313 100644
--- a/tests/storage/__init__.py
+++ b/tests/storage/__init__.py
@@ -1,5 +1,3 @@
-# -*- coding: utf-8 -*-
-
import random
import uuid
@@ -31,7 +29,7 @@ def format_item(item_template, uid=None):
return Item(item_template.format(r=r, uid=uid or r))
-class StorageTests(object):
+class StorageTests:
storage_class = None
supports_collections = True
supports_metadata = True
@@ -173,10 +171,10 @@ class StorageTests(object):
_, etag = s.get(href)
info[href] = etag
- assert dict(
- (href, etag) for href, item, etag
+ assert {
+ href: etag for href, item, etag
in s.get_multi(href for href, etag in info.items())
- ) == info
+ } == info
def test_repr(self, s, get_storage_args):
assert self.storage_class.__name__ in repr(s)
@@ -191,10 +189,10 @@ class StorageTests(object):
s.upload(get_item())
collections.add(s.collection)
- actual = set(
+ actual = {
c['collection'] for c in
self.storage_class.discover(**get_storage_args(collection=None))
- )
+ }
assert actual >= collections
@@ -212,7 +210,7 @@ class StorageTests(object):
)
href = s.upload(get_item())[0]
- assert href in set(href for href, etag in s.list())
+ assert href in {href for href, etag in s.list()}
def test_discover_collection_arg(self, requires_collections,
get_storage_args):
@@ -255,7 +253,7 @@ class StorageTests(object):
monkeypatch.setattr('vdirsyncer.utils.generate_href', lambda x: x)
- uid = u'test @ foo ät bar град сатану'
+ uid = 'test @ foo ät bar град сатану'
collection = 'test @ foo ät bar'
s = self.storage_class(**get_storage_args(collection=collection))
@@ -286,12 +284,12 @@ class StorageTests(object):
try:
s.set_meta('color', None)
assert not s.get_meta('color')
- s.set_meta('color', u'#ff0000')
- assert s.get_meta('color') == u'#ff0000'
+ s.set_meta('color', '#ff0000')
+ assert s.get_meta('color') == '#ff0000'
except exceptions.UnsupportedMetadataError:
pass
- for x in (u'hello world', u'hello wörld'):
+ for x in ('hello world', 'hello wörld'):
s.set_meta('displayname', x)
rv = s.get_meta('displayname')
assert rv == x
@@ -315,7 +313,7 @@ class StorageTests(object):
pytest.skip('This storage instance doesn\'t support iCalendar.')
uid = str(uuid.uuid4())
- item = Item(textwrap.dedent(u'''
+ item = Item(textwrap.dedent('''
BEGIN:VCALENDAR
VERSION:2.0
BEGIN:VEVENT
diff --git a/tests/storage/conftest.py b/tests/storage/conftest.py
index 90333ad..dcb42f6 100644
--- a/tests/storage/conftest.py
+++ b/tests/storage/conftest.py
@@ -1,5 +1,3 @@
-# -*- coding: utf-8 -*-
-
import pytest
import uuid
diff --git a/tests/storage/dav/__init__.py b/tests/storage/dav/__init__.py
index 77109e8..8886f73 100644
--- a/tests/storage/dav/__init__.py
+++ b/tests/storage/dav/__init__.py
@@ -1,5 +1,3 @@
-# -*- coding: utf-8 -*-
-
import uuid
import os
@@ -27,7 +25,7 @@ class DAVStorageTests(ServerMixin, StorageTests):
@pytest.mark.skipif(dav_server == 'radicale',
reason='Radicale is very tolerant.')
def test_dav_broken_item(self, s):
- item = Item(u'HAHA:YES')
+ item = Item('HAHA:YES')
with pytest.raises((exceptions.Error, requests.exceptions.HTTPError)):
s.upload(item)
assert not list(s.list())
@@ -50,7 +48,7 @@ class DAVStorageTests(ServerMixin, StorageTests):
monkeypatch.setattr(s, '_get_href',
lambda item: item.ident + s.fileext)
- item = get_item(uid=u'град сатану' + str(uuid.uuid4()))
+ item = get_item(uid='град сатану' + str(uuid.uuid4()))
href, etag = s.upload(item)
item2, etag2 = s.get(href)
assert_item_equals(item, item2)
diff --git a/tests/storage/dav/test_caldav.py b/tests/storage/dav/test_caldav.py
index 3063bbd..1d3f2fa 100644
--- a/tests/storage/dav/test_caldav.py
+++ b/tests/storage/dav/test_caldav.py
@@ -1,5 +1,3 @@
-# -*- coding: utf-8 -*-
-
import datetime
from textwrap import dedent
@@ -64,7 +62,7 @@ class TestCalDAVStorage(DAVStorageTests):
s = self.storage_class(start_date=start_date, end_date=end_date,
**get_storage_args())
- too_old_item = format_item(dedent(u'''
+ too_old_item = format_item(dedent('''
BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//hacksw/handcal//NONSGML v1.0//EN
@@ -78,7 +76,7 @@ class TestCalDAVStorage(DAVStorageTests):
END:VCALENDAR
''').strip())
- too_new_item = format_item(dedent(u'''
+ too_new_item = format_item(dedent('''
BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//hacksw/handcal//NONSGML v1.0//EN
@@ -92,7 +90,7 @@ class TestCalDAVStorage(DAVStorageTests):
END:VCALENDAR
''').strip())
- good_item = format_item(dedent(u'''
+ good_item = format_item(dedent('''
BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//hacksw/handcal//NONSGML v1.0//EN
@@ -140,13 +138,13 @@ class TestCalDAVStorage(DAVStorageTests):
task = s.upload(format_item(TASK_TEMPLATE))[0]
s.item_types = ('VTODO', 'VEVENT')
- def l():
- return set(href for href, etag in s.list())
+ def hrefs():
+ return {href for href, etag in s.list()}
- assert l() == {event, task}
+ assert hrefs() == {event, task}
s.item_types = ('VTODO',)
- assert l() == {task}
+ assert hrefs() == {task}
s.item_types = ('VEVENT',)
- assert l() == {event}
+ assert hrefs() == {event}
s.item_types = ()
- assert l() == {event, task}
+ assert hrefs() == {event, task}
diff --git a/tests/storage/dav/test_carddav.py b/tests/storage/dav/test_carddav.py
index 7aedaac..e15e047 100644
--- a/tests/storage/dav/test_carddav.py
+++ b/tests/storage/dav/test_carddav.py
@@ -1,5 +1,3 @@
-# -*- coding: utf-8 -*-
-
import pytest
from vdirsyncer.storage.dav import CardDAVStorage
diff --git a/tests/storage/etesync/test_main.py b/tests/storage/etesync/test_main.py
index 9add484..2045646 100644
--- a/tests/storage/etesync/test_main.py
+++ b/tests/storage/etesync/test_main.py
@@ -1,5 +1,3 @@
-# -*- coding: utf-8 -*-
-
import shutil
import os
import sys
diff --git a/tests/storage/servers/__init__.py b/tests/storage/servers/__init__.py
index 40a96af..e69de29 100644
--- a/tests/storage/servers/__init__.py
+++ b/tests/storage/servers/__init__.py
@@ -1 +0,0 @@
-# -*- coding: utf-8 -*-
diff --git a/tests/storage/servers/davical/__init__.py b/tests/storage/servers/davical/__init__.py
index 25eaee1..a402ba2 100644
--- a/tests/storage/servers/davical/__init__.py
+++ b/tests/storage/servers/davical/__init__.py
@@ -14,7 +14,7 @@ except KeyError as e:
@pytest.mark.flaky(reruns=5)
-class ServerMixin(object):
+class ServerMixin:
@pytest.fixture
def davical_args(self):
if self.storage_class.fileext == '.ics':
diff --git a/tests/storage/servers/fastmail/__init__.py b/tests/storage/servers/fastmail/__init__.py
index a421f92..6471ef3 100644
--- a/tests/storage/servers/fastmail/__init__.py
+++ b/tests/storage/servers/fastmail/__init__.py
@@ -3,7 +3,7 @@ import os
import pytest
-class ServerMixin(object):
+class ServerMixin:
@pytest.fixture
def get_storage_args(self, slow_create_collection):
@@ -14,9 +14,9 @@ class ServerMixin(object):
}
if self.storage_class.fileext == '.ics':
- args['url'] = 'https://caldav.messagingengine.com/'
+ args['url'] = 'https://caldav.fastmail.com/'
elif self.storage_class.fileext == '.vcf':
- args['url'] = 'https://carddav.messagingengine.com/'
+ args['url'] = 'https://carddav.fastmail.com/'
else:
raise RuntimeError()
diff --git a/tests/storage/servers/icloud/__init__.py b/tests/storage/servers/icloud/__init__.py
index f814490..04a0049 100644
--- a/tests/storage/servers/icloud/__init__.py
+++ b/tests/storage/servers/icloud/__init__.py
@@ -3,7 +3,7 @@ import os
import pytest
-class ServerMixin(object):
+class ServerMixin:
@pytest.fixture
def get_storage_args(self, item_type, slow_create_collection):
diff --git a/tests/storage/servers/mysteryshack/__init__.py b/tests/storage/servers/mysteryshack/__init__.py
index b5e7478..617c154 100644
--- a/tests/storage/servers/mysteryshack/__init__.py
+++ b/tests/storage/servers/mysteryshack/__init__.py
@@ -1,5 +1,3 @@
-# -*- coding: utf-8 -*-
-
import os
import subprocess
import time
@@ -28,7 +26,7 @@ def wait():
return False
-class ServerMixin(object):
+class ServerMixin:
@pytest.fixture(scope='session')
def setup_mysteryshack_server(self, xprocess):
def preparefunc(cwd):
diff --git a/tests/storage/servers/radicale/__init__.py b/tests/storage/servers/radicale/__init__.py
index 66b1407..6e4ae29 100644
--- a/tests/storage/servers/radicale/__init__.py
+++ b/tests/storage/servers/radicale/__init__.py
@@ -1,5 +1,3 @@
-# -*- coding: utf-8 -*-
-
import logging
import pytest
@@ -14,7 +12,7 @@ import wsgi_intercept.requests_intercept
logger = logging.getLogger(__name__)
-class ServerMixin(object):
+class ServerMixin:
@pytest.fixture(autouse=True)
def setup(self, request, tmpdir):
diff --git a/tests/storage/servers/skip/__init__.py b/tests/storage/servers/skip/__init__.py
index 0c8b392..081a41e 100644
--- a/tests/storage/servers/skip/__init__.py
+++ b/tests/storage/servers/skip/__init__.py
@@ -1,7 +1,7 @@
import pytest
-class ServerMixin(object):
+class ServerMixin:
@pytest.fixture
def get_storage_args(self):
diff --git a/tests/storage/servers/xandikos/__init__.py b/tests/storage/servers/xandikos/__init__.py
index 570d87f..899564b 100644
--- a/tests/storage/servers/xandikos/__init__.py
+++ b/tests/storage/servers/xandikos/__init__.py
@@ -6,7 +6,7 @@ import wsgi_intercept
import wsgi_intercept.requests_intercept
-class ServerMixin(object):
+class ServerMixin:
@pytest.fixture
def get_storage_args(self, request, tmpdir, slow_create_collection):
tmpdir.mkdir('xandikos')
diff --git a/tests/storage/test_filesystem.py b/tests/storage/test_filesystem.py
index 39a4880..e8a3d71 100644
--- a/tests/storage/test_filesystem.py
+++ b/tests/storage/test_filesystem.py
@@ -1,5 +1,3 @@
-# -*- coding: utf-8 -*-
-
import subprocess
import pytest
@@ -32,8 +30,8 @@ class TestFilesystemStorage(StorageTests):
def test_broken_data(self, tmpdir):
s = self.storage_class(str(tmpdir), '.txt')
- class BrokenItem(object):
- raw = u'Ц, Ш, Л, ж, Д, З, Ю'.encode('utf-8')
+ class BrokenItem:
+ raw = 'Ц, Ш, Л, ж, Д, З, Ю'.encode()
uid = 'jeezus'
ident = uid
with pytest.raises(TypeError):
@@ -42,13 +40,13 @@ class TestFilesystemStorage(StorageTests):
def test_ident_with_slash(self, tmpdir):
s = self.storage_class(str(tmpdir), '.txt')
- s.upload(Item(u'UID:a/b/c'))
+ s.upload(Item('UID:a/b/c'))
item_file, = tmpdir.listdir()
assert '/' not in item_file.basename and item_file.isfile()
def test_too_long_uid(self, tmpdir):
s = self.storage_class(str(tmpdir), '.txt')
- item = Item(u'UID:' + u'hue' * 600)
+ item = Item('UID:' + 'hue' * 600)
href, etag = s.upload(item)
assert item.uid not in href
@@ -60,27 +58,27 @@ class TestFilesystemStorage(StorageTests):
monkeypatch.setattr(subprocess, 'call', check_call_mock)
s = self.storage_class(str(tmpdir), '.txt', post_hook=None)
- s.upload(Item(u'UID:a/b/c'))
+ s.upload(Item('UID:a/b/c'))
def test_post_hook_active(self, tmpdir, monkeypatch):
calls = []
exe = 'foo'
- def check_call_mock(l, *args, **kwargs):
+ def check_call_mock(call, *args, **kwargs):
calls.append(True)
- assert len(l) == 2
- assert l[0] == exe
+ assert len(call) == 2
+ assert call[0] == exe
monkeypatch.setattr(subprocess, 'call', check_call_mock)
s = self.storage_class(str(tmpdir), '.txt', post_hook=exe)
- s.upload(Item(u'UID:a/b/c'))
+ s.upload(Item('UID:a/b/c'))
assert calls
def test_ignore_git_dirs(self, tmpdir):
tmpdir.mkdir('.git').mkdir('foo')
tmpdir.mkdir('a')
tmpdir.mkdir('b')
- assert set(c['collection'] for c
- in self.storage_class.discover(str(tmpdir))) == {'a', 'b'}
+ assert {c['collection'] for c
+ in self.storage_class.discover(str(tmpdir))} == {'a', 'b'}
diff --git a/tests/storage/test_http.py b/tests/storage/test_http.py
index da14d5d..5e63a8f 100644
--- a/tests/storage/test_http.py
+++ b/tests/storage/test_http.py
@@ -1,5 +1,3 @@
-# -*- coding: utf-8 -*-
-
import pytest
from requests import Response
@@ -14,25 +12,25 @@ def test_list(monkeypatch):
collection_url = 'http://127.0.0.1/calendar/collection.ics'
items = [
- (u'BEGIN:VEVENT\n'
- u'SUMMARY:Eine Kurzinfo\n'
- u'DESCRIPTION:Beschreibung des Termines\n'
- u'END:VEVENT'),
- (u'BEGIN:VEVENT\n'
- u'SUMMARY:Eine zweite Küèrzinfo\n'
- u'DESCRIPTION:Beschreibung des anderen Termines\n'
- u'BEGIN:VALARM\n'
- u'ACTION:AUDIO\n'
- u'TRIGGER:19980403T120000\n'
- u'ATTACH;FMTTYPE=audio/basic:http://host.com/pub/ssbanner.aud\n'
- u'REPEAT:4\n'
- u'DURATION:PT1H\n'
- u'END:VALARM\n'
- u'END:VEVENT')
+ ('BEGIN:VEVENT\n'
+ 'SUMMARY:Eine Kurzinfo\n'
+ 'DESCRIPTION:Beschreibung des Termines\n'
+ 'END:VEVENT'),
+ ('BEGIN:VEVENT\n'
+ 'SUMMARY:Eine zweite Küèrzinfo\n'
+ 'DESCRIPTION:Beschreibung des anderen Termines\n'
+ 'BEGIN:VALARM\n'
+ 'ACTION:AUDIO\n'
+ 'TRIGGER:19980403T120000\n'
+ 'ATTACH;FMTTYPE=audio/basic:http://host.com/pub/ssbanner.aud\n'
+ 'REPEAT:4\n'
+ 'DURATION:PT1H\n'
+ 'END:VALARM\n'
+ 'END:VEVENT')
]
responses = [
- u'\n'.join([u'BEGIN:VCALENDAR'] + items + [u'END:VCALENDAR'])
+ '\n'.join(['BEGIN:VCALENDAR'] + items + ['END:VCALENDAR'])
] * 2
def get(self, method, url, *a, **kw):
@@ -58,8 +56,8 @@ def test_list(monkeypatch):
assert etag2 == etag
found_items[normalize_item(item)] = href
- expected = set(normalize_item(u'BEGIN:VCALENDAR\n' + x + '\nEND:VCALENDAR')
- for x in items)
+ expected = {normalize_item('BEGIN:VCALENDAR\n' + x + '\nEND:VCALENDAR')
+ for x in items}
assert set(found_items) == expected
diff --git a/tests/storage/test_http_with_singlefile.py b/tests/storage/test_http_with_singlefile.py
index 48c4587..6480a52 100644
--- a/tests/storage/test_http_with_singlefile.py
+++ b/tests/storage/test_http_with_singlefile.py
@@ -1,5 +1,3 @@
-# -*- coding: utf-8 -*-
-
import pytest
from requests import Response
@@ -21,7 +19,7 @@ class CombinedStorage(Storage):
if kwargs.get('collection', None) is not None:
raise ValueError()
- super(CombinedStorage, self).__init__(**kwargs)
+ super().__init__(**kwargs)
self.url = url
self.path = path
self._reader = vdirsyncer.storage.http.HttpStorage(url=url)
diff --git a/tests/storage/test_memory.py b/tests/storage/test_memory.py
index 77b2cdb..417db1b 100644
--- a/tests/storage/test_memory.py
+++ b/tests/storage/test_memory.py
@@ -1,5 +1,3 @@
-# -*- coding: utf-8 -*-
-
import pytest
from vdirsyncer.storage.memory import MemoryStorage
diff --git a/tests/storage/test_singlefile.py b/tests/storage/test_singlefile.py
index 87eae1f..54ef020 100644
--- a/tests/storage/test_singlefile.py
+++ b/tests/storage/test_singlefile.py
@@ -1,5 +1,3 @@
-# -*- coding: utf-8 -*-
-
import pytest
from vdirsyncer.storage.singlefile import SingleFileStorage
diff --git a/tests/system/cli/conftest.py b/tests/system/cli/conftest.py
index e6876af..43e4b79 100644
--- a/tests/system/cli/conftest.py
+++ b/tests/system/cli/conftest.py
@@ -1,5 +1,3 @@
-# -*- coding: utf-8 -*-
-
from textwrap import dedent
from click.testing import CliRunner
@@ -9,7 +7,7 @@ import pytest
import vdirsyncer.cli as cli
-class _CustomRunner(object):
+class _CustomRunner:
def __init__(self, tmpdir):
self.tmpdir = tmpdir
self.cfg = tmpdir.join('config')
diff --git a/tests/system/cli/test_config.py b/tests/system/cli/test_config.py
index 98de91a..734e1ee 100644
--- a/tests/system/cli/test_config.py
+++ b/tests/system/cli/test_config.py
@@ -23,7 +23,7 @@ def read_config(tmpdir, monkeypatch):
def test_read_config(read_config):
- errors, c = read_config(u'''
+ errors, c = read_config('''
[general]
status_path = "/tmp/status/"
@@ -59,7 +59,7 @@ def test_read_config(read_config):
def test_missing_collections_param(read_config):
with pytest.raises(exceptions.UserError) as excinfo:
- read_config(u'''
+ read_config('''
[general]
status_path = "/tmp/status/"
@@ -79,7 +79,7 @@ def test_missing_collections_param(read_config):
def test_invalid_section_type(read_config):
with pytest.raises(exceptions.UserError) as excinfo:
- read_config(u'''
+ read_config('''
[general]
status_path = "/tmp/status/"
@@ -92,7 +92,7 @@ def test_invalid_section_type(read_config):
def test_missing_general_section(read_config):
with pytest.raises(exceptions.UserError) as excinfo:
- read_config(u'''
+ read_config('''
[pair my_pair]
a = "my_a"
b = "my_b"
@@ -114,7 +114,7 @@ def test_missing_general_section(read_config):
def test_wrong_general_section(read_config):
with pytest.raises(exceptions.UserError) as excinfo:
- read_config(u'''
+ read_config('''
[general]
wrong = true
''')
@@ -128,7 +128,7 @@ def test_wrong_general_section(read_config):
def test_invalid_storage_name(read_config):
with pytest.raises(exceptions.UserError) as excinfo:
- read_config(u'''
+ read_config('''
[general]
status_path = "{base}/status/"
@@ -140,7 +140,7 @@ def test_invalid_storage_name(read_config):
def test_invalid_collections_arg(read_config):
with pytest.raises(exceptions.UserError) as excinfo:
- read_config(u'''
+ read_config('''
[general]
status_path = "/tmp/status/"
@@ -165,7 +165,7 @@ def test_invalid_collections_arg(read_config):
def test_duplicate_sections(read_config):
with pytest.raises(exceptions.UserError) as excinfo:
- read_config(u'''
+ read_config('''
[general]
status_path = "/tmp/status/"
diff --git a/tests/system/cli/test_repair.py b/tests/system/cli/test_repair.py
index 7573801..cad41f6 100644
--- a/tests/system/cli/test_repair.py
+++ b/tests/system/cli/test_repair.py
@@ -1,5 +1,3 @@
-# encoding: utf-8
-
from textwrap import dedent
import pytest
diff --git a/tests/system/cli/test_sync.py b/tests/system/cli/test_sync.py
index e8ddca9..97e21e8 100644
--- a/tests/system/cli/test_sync.py
+++ b/tests/system/cli/test_sync.py
@@ -1,5 +1,3 @@
-# -*- coding: utf-8 -*-
-
import json
import sys
from textwrap import dedent
@@ -257,17 +255,17 @@ def test_multiple_pairs(tmpdir, runner):
result = runner.invoke(['discover'])
assert not result.exception
- assert set(result.output.splitlines()) > set([
+ assert set(result.output.splitlines()) > {
'Discovering collections for pair bambaz',
'Discovering collections for pair foobar'
- ])
+ }
result = runner.invoke(['sync'])
assert not result.exception
- assert set(result.output.splitlines()) == set([
+ assert set(result.output.splitlines()) == {
'Syncing bambaz',
'Syncing foobar',
- ])
+ }
# XXX: https://github.com/pimutils/vdirsyncer/issues/617
@@ -277,17 +275,17 @@ def test_multiple_pairs(tmpdir, runner):
st.text(
st.characters(
blacklist_characters=set(
- u'./\x00' # Invalid chars on POSIX filesystems
+ './\x00' # Invalid chars on POSIX filesystems
),
# Surrogates can't be encoded to utf-8 in Python
- blacklist_categories=set(['Cs'])
+ blacklist_categories={'Cs'}
),
min_size=1,
max_size=50
),
min_size=1
))
-@example(collections=[u'persönlich'])
+@example(collections=['persönlich'])
@example(collections={'a', 'A'})
@example(collections={'\ufffe'})
def test_create_collections(subtest, collections):
@@ -322,8 +320,8 @@ def test_create_collections(subtest, collections):
)
assert not result.exception, result.output
- assert set(x.basename for x in tmpdir.join('foo').listdir()) == \
- set(x.basename for x in tmpdir.join('bar').listdir())
+ assert {x.basename for x in tmpdir.join('foo').listdir()} == \
+ {x.basename for x in tmpdir.join('bar').listdir()}
def test_ident_conflict(tmpdir, runner):
diff --git a/tests/system/utils/test_main.py b/tests/system/utils/test_main.py
index d25b0d0..10bfde9 100644
--- a/tests/system/utils/test_main.py
+++ b/tests/system/utils/test_main.py
@@ -1,5 +1,3 @@
-# -*- coding: utf-8 -*-
-
import sys
import logging
@@ -20,7 +18,7 @@ def test_get_storage_init_args():
from vdirsyncer.storage.memory import MemoryStorage
all, required = utils.get_storage_init_args(MemoryStorage)
- assert all == set(['fileext', 'collection', 'read_only', 'instance_name'])
+ assert all == {'fileext', 'collection', 'read_only', 'instance_name'}
assert not required
diff --git a/tests/unit/cli/test_discover.py b/tests/unit/cli/test_discover.py
index 6f71e85..bc6bd96 100644
--- a/tests/unit/cli/test_discover.py
+++ b/tests/unit/cli/test_discover.py
@@ -1,5 +1,3 @@
-# -*- coding: utf-8 -*-
-
import pytest
from vdirsyncer.cli.discover import expand_collections
diff --git a/tests/unit/cli/test_fetchparams.py b/tests/unit/cli/test_fetchparams.py
index a156985..2d28507 100644
--- a/tests/unit/cli/test_fetchparams.py
+++ b/tests/unit/cli/test_fetchparams.py
@@ -1,5 +1,3 @@
-# -*- coding: utf-8 -*-
-
import hypothesis.strategies as st
from hypothesis import given
@@ -23,7 +21,7 @@ def mystrategy(monkeypatch):
def value_cache(monkeypatch):
_cache = {}
- class FakeContext(object):
+ class FakeContext:
fetched_params = _cache
def find_object(self, _):
diff --git a/tests/unit/sync/test_sync.py b/tests/unit/sync/test_sync.py
index ca96f71..4e9651f 100644
--- a/tests/unit/sync/test_sync.py
+++ b/tests/unit/sync/test_sync.py
@@ -1,5 +1,3 @@
-# -*- coding: utf-8 -*-
-
from copy import deepcopy
import hypothesis.strategies as st
@@ -32,7 +30,7 @@ def empty_storage(x):
def items(s):
- return set(x[1].raw for x in s.items.values())
+ return {x[1].raw for x in s.items.values()}
def test_irrelevant_status():
@@ -49,7 +47,7 @@ def test_missing_status():
a = MemoryStorage()
b = MemoryStorage()
status = {}
- item = Item(u'asdf')
+ item = Item('asdf')
a.upload(item)
b.upload(item)
sync(a, b, status)
@@ -62,8 +60,8 @@ def test_missing_status_and_different_items():
b = MemoryStorage()
status = {}
- item1 = Item(u'UID:1\nhaha')
- item2 = Item(u'UID:1\nhoho')
+ item1 = Item('UID:1\nhaha')
+ item2 = Item('UID:1\nhoho')
a.upload(item1)
b.upload(item2)
with pytest.raises(SyncConflict):
@@ -79,8 +77,8 @@ def test_read_only_and_prefetch():
b.read_only = True
status = {}
- item1 = Item(u'UID:1\nhaha')
- item2 = Item(u'UID:2\nhoho')
+ item1 = Item('UID:1\nhaha')
+ item2 = Item('UID:2\nhoho')
a.upload(item1)
a.upload(item2)
@@ -152,22 +150,22 @@ def test_upload_and_update():
b = MemoryStorage(fileext='.b')
status = {}
- item = Item(u'UID:1') # new item 1 in a
+ item = Item('UID:1') # new item 1 in a
a.upload(item)
sync(a, b, status)
assert items(b) == items(a) == {item.raw}
- item = Item(u'UID:1\nASDF:YES') # update of item 1 in b
+ item = Item('UID:1\nASDF:YES') # update of item 1 in b
b.update('1.b', item, b.get('1.b')[1])
sync(a, b, status)
assert items(b) == items(a) == {item.raw}
- item2 = Item(u'UID:2') # new item 2 in b
+ item2 = Item('UID:2') # new item 2 in b
b.upload(item2)
sync(a, b, status)
assert items(b) == items(a) == {item.raw, item2.raw}
- item2 = Item(u'UID:2\nASDF:YES') # update of item 2 in a
+ item2 = Item('UID:2\nASDF:YES') # update of item 2 in a
a.update('2.a', item2, a.get('2.a')[1])
sync(a, b, status)
assert items(b) == items(a) == {item.raw, item2.raw}
@@ -178,9 +176,9 @@ def test_deletion():
b = MemoryStorage(fileext='.b')
status = {}
- item = Item(u'UID:1')
+ item = Item('UID:1')
a.upload(item)
- item2 = Item(u'UID:2')
+ item2 = Item('UID:2')
a.upload(item2)
sync(a, b, status)
b.delete('1.b', b.get('1.b')[1])
@@ -215,7 +213,7 @@ def test_insert_hash():
def test_already_synced():
a = MemoryStorage(fileext='.a')
b = MemoryStorage(fileext='.b')
- item = Item(u'UID:1')
+ item = Item('UID:1')
a.upload(item)
b.upload(item)
status = {
@@ -243,14 +241,14 @@ def test_already_synced():
def test_conflict_resolution_both_etags_new(winning_storage):
a = MemoryStorage()
b = MemoryStorage()
- item = Item(u'UID:1')
+ item = Item('UID:1')
href_a, etag_a = a.upload(item)
href_b, etag_b = b.upload(item)
status = {}
sync(a, b, status)
assert status
- item_a = Item(u'UID:1\nitem a')
- item_b = Item(u'UID:1\nitem b')
+ item_a = Item('UID:1\nitem a')
+ item_b = Item('UID:1\nitem b')
a.update(href_a, item_a, etag_a)
b.update(href_b, item_b, etag_b)
with pytest.raises(SyncConflict):
@@ -264,13 +262,13 @@ def test_conflict_resolution_both_etags_new(winning_storage):
def test_updated_and_deleted():
a = MemoryStorage()
b = MemoryStorage()
- href_a, etag_a = a.upload(Item(u'UID:1'))
+ href_a, etag_a = a.upload(Item('UID:1'))
status = {}
sync(a, b, status, force_delete=True)
(href_b, etag_b), = b.list()
b.delete(href_b, etag_b)
- updated = Item(u'UID:1\nupdated')
+ updated = Item('UID:1\nupdated')
a.update(href_a, updated, etag_a)
sync(a, b, status, force_delete=True)
@@ -280,8 +278,8 @@ def test_updated_and_deleted():
def test_conflict_resolution_invalid_mode():
a = MemoryStorage()
b = MemoryStorage()
- item_a = Item(u'UID:1\nitem a')
- item_b = Item(u'UID:1\nitem b')
+ item_a = Item('UID:1\nitem a')
+ item_b = Item('UID:1\nitem b')
a.upload(item_a)
b.upload(item_b)
with pytest.raises(ValueError):
@@ -291,7 +289,7 @@ def test_conflict_resolution_invalid_mode():
def test_conflict_resolution_new_etags_without_changes():
a = MemoryStorage()
b = MemoryStorage()
- item = Item(u'UID:1')
+ item = Item('UID:1')
href_a, etag_a = a.upload(item)
href_b, etag_b = b.upload(item)
status = {'1': (href_a, 'BOGUS_a', href_b, 'BOGUS_b')}
@@ -326,7 +324,7 @@ def test_uses_get_multi(monkeypatch):
a = MemoryStorage()
b = MemoryStorage()
- item = Item(u'UID:1')
+ item = Item('UID:1')
expected_href, etag = a.upload(item)
sync(a, b, {})
@@ -336,8 +334,8 @@ def test_uses_get_multi(monkeypatch):
def test_empty_storage_dataloss():
a = MemoryStorage()
b = MemoryStorage()
- a.upload(Item(u'UID:1'))
- a.upload(Item(u'UID:2'))
+ a.upload(Item('UID:1'))
+ a.upload(Item('UID:2'))
status = {}
sync(a, b, status)
with pytest.raises(StorageEmpty):
@@ -350,22 +348,22 @@ def test_empty_storage_dataloss():
def test_no_uids():
a = MemoryStorage()
b = MemoryStorage()
- a.upload(Item(u'ASDF'))
- b.upload(Item(u'FOOBAR'))
+ a.upload(Item('ASDF'))
+ b.upload(Item('FOOBAR'))
status = {}
sync(a, b, status)
- assert items(a) == items(b) == {u'ASDF', u'FOOBAR'}
+ assert items(a) == items(b) == {'ASDF', 'FOOBAR'}
def test_changed_uids():
a = MemoryStorage()
b = MemoryStorage()
- href_a, etag_a = a.upload(Item(u'UID:A-ONE'))
- href_b, etag_b = b.upload(Item(u'UID:B-ONE'))
+ href_a, etag_a = a.upload(Item('UID:A-ONE'))
+ href_b, etag_b = b.upload(Item('UID:B-ONE'))
status = {}
sync(a, b, status)
- a.update(href_a, Item(u'UID:A-TWO'), etag_a)
+ a.update(href_a, Item('UID:A-TWO'), etag_a)
sync(a, b, status)
@@ -383,8 +381,8 @@ def test_partial_sync_revert():
a = MemoryStorage(instance_name='a')
b = MemoryStorage(instance_name='b')
status = {}
- a.upload(Item(u'UID:1'))
- b.upload(Item(u'UID:2'))
+ a.upload(Item('UID:1'))
+ b.upload(Item('UID:2'))
b.read_only = True
sync(a, b, status, partial_sync='revert')
@@ -418,13 +416,13 @@ def test_ident_conflict(sync_inbetween):
a = MemoryStorage()
b = MemoryStorage()
status = {}
- href_a, etag_a = a.upload(Item(u'UID:aaa'))
- href_b, etag_b = a.upload(Item(u'UID:bbb'))
+ href_a, etag_a = a.upload(Item('UID:aaa'))
+ href_b, etag_b = a.upload(Item('UID:bbb'))
if sync_inbetween:
sync(a, b, status)
- a.update(href_a, Item(u'UID:xxx'), etag_a)
- a.update(href_b, Item(u'UID:xxx'), etag_b)
+ a.update(href_a, Item('UID:xxx'), etag_a)
+ a.update(href_b, Item('UID:xxx'), etag_b)
with pytest.raises(IdentConflict):
sync(a, b, status)
@@ -441,7 +439,7 @@ def test_moved_href():
a = MemoryStorage()
b = MemoryStorage()
status = {}
- href, etag = a.upload(Item(u'UID:haha'))
+ href, etag = a.upload(Item('UID:haha'))
sync(a, b, status)
b.items['lol'] = b.items.pop('haha')
@@ -476,26 +474,26 @@ def test_bogus_etag_change():
a = MemoryStorage()
b = MemoryStorage()
status = {}
- href_a, etag_a = a.upload(Item(u'UID:ASDASD'))
+ href_a, etag_a = a.upload(Item('UID:ASDASD'))
sync(a, b, status)
assert len(status) == len(list(a.list())) == len(list(b.list())) == 1
(href_b, etag_b), = b.list()
- a.update(href_a, Item(u'UID:ASDASD'), etag_a)
- b.update(href_b, Item(u'UID:ASDASD\nACTUALCHANGE:YES'), etag_b)
+ a.update(href_a, Item('UID:ASDASD'), etag_a)
+ b.update(href_b, Item('UID:ASDASD\nACTUALCHANGE:YES'), etag_b)
b.delete = b.update = b.upload = blow_up
sync(a, b, status)
assert len(status) == 1
- assert items(a) == items(b) == {u'UID:ASDASD\nACTUALCHANGE:YES'}
+ assert items(a) == items(b) == {'UID:ASDASD\nACTUALCHANGE:YES'}
def test_unicode_hrefs():
a = MemoryStorage()
b = MemoryStorage()
status = {}
- href, etag = a.upload(Item(u'UID:äää'))
+ href, etag = a.upload(Item('UID:äää'))
sync(a, b, status)
@@ -565,7 +563,7 @@ class SyncMachine(RuleBasedStateMachine):
uid=uid_strategy,
etag=st.text())
def upload(self, storage, uid, etag):
- item = Item(u'UID:{}'.format(uid))
+ item = Item('UID:{}'.format(uid))
storage.items[uid] = (etag, item)
@rule(storage=Storage, href=st.text())
diff --git a/tests/unit/test_metasync.py b/tests/unit/test_metasync.py
index 0b1ab95..ae6d94c 100644
--- a/tests/unit/test_metasync.py
+++ b/tests/unit/test_metasync.py
@@ -1,5 +1,3 @@
-# -*- coding: utf-8 -*-
-
import hypothesis.strategies as st
from hypothesis import example, given
@@ -130,7 +128,7 @@ metadata = st.dictionaries(keys, values)
status=metadata, keys=st.sets(keys),
conflict_resolution=st.just('a wins') | st.just('b wins')
)
-@example(a={u'0': u'0'}, b={}, status={u'0': u'0'}, keys={u'0'},
+@example(a={'0': '0'}, b={}, status={'0': '0'}, keys={'0'},
conflict_resolution='a wins')
@example(a={'0': '0'}, b={'0': '1'}, status={'0': '0'}, keys={'0'},
conflict_resolution='a wins')
@@ -144,9 +142,9 @@ def test_fuzzing(a, b, status, keys, conflict_resolution):
b = _get_storage(b, 'B')
winning_storage = (a if conflict_resolution == 'a wins' else b)
- expected_values = dict((key, winning_storage.get_meta(key))
- for key in keys
- if key not in status)
+ expected_values = {key: winning_storage.get_meta(key)
+ for key in keys
+ if key not in status}
metasync(a, b, status,
keys=keys, conflict_resolution=conflict_resolution)
diff --git a/tests/unit/test_repair.py b/tests/unit/test_repair.py
index 0ba726e..5467c54 100644
--- a/tests/unit/test_repair.py
+++ b/tests/unit/test_repair.py
@@ -1,4 +1,4 @@
-from hypothesis import given, settings
+from hypothesis import HealthCheck, given, settings
import pytest
@@ -11,17 +11,18 @@ from vdirsyncer.vobject import Item
@given(uid=uid_strategy)
-@settings(perform_health_check=False) # Using the random module for UIDs
+# Using the random module for UIDs:
+@settings(suppress_health_check=HealthCheck.all())
def test_repair_uids(uid):
s = MemoryStorage()
s.items = {
'one': (
'asdf',
- Item(u'BEGIN:VCARD\nFN:Hans\nUID:{}\nEND:VCARD'.format(uid))
+ Item('BEGIN:VCARD\nFN:Hans\nUID:{}\nEND:VCARD'.format(uid))
),
'two': (
'asdf',
- Item(u'BEGIN:VCARD\nFN:Peppi\nUID:{}\nEND:VCARD'.format(uid))
+ Item('BEGIN:VCARD\nFN:Peppi\nUID:{}\nEND:VCARD'.format(uid))
)
}
@@ -35,10 +36,11 @@ def test_repair_uids(uid):
@given(uid=uid_strategy.filter(lambda x: not href_safe(x)))
-@settings(perform_health_check=False) # Using the random module for UIDs
+# Using the random module for UIDs:
+@settings(suppress_health_check=HealthCheck.all())
def test_repair_unsafe_uids(uid):
s = MemoryStorage()
- item = Item(u'BEGIN:VCARD\nUID:{}\nEND:VCARD'.format(uid))
+ item = Item('BEGIN:VCARD\nUID:{}\nEND:VCARD'.format(uid))
href, etag = s.upload(item)
assert s.get(href)[0].uid == uid
assert not href_safe(uid)
diff --git a/tests/unit/utils/test_vobject.py b/tests/unit/utils/test_vobject.py
index cfb52d1..84d87a8 100644
--- a/tests/unit/utils/test_vobject.py
+++ b/tests/unit/utils/test_vobject.py
@@ -1,5 +1,3 @@
-# -*- coding: utf-8 -*-
-
from textwrap import dedent
import hypothesis.strategies as st
@@ -21,10 +19,10 @@ _simple_split = [
VCARD_TEMPLATE.format(r=678, uid=678)
]
-_simple_joined = u'\r\n'.join(
- [u'BEGIN:VADDRESSBOOK'] +
- _simple_split +
- [u'END:VADDRESSBOOK\r\n']
+_simple_joined = '\r\n'.join(
+ ['BEGIN:VADDRESSBOOK']
+ + _simple_split
+ + ['END:VADDRESSBOOK\r\n']
)
@@ -39,10 +37,10 @@ def test_split_collection_simple(benchmark):
def test_split_collection_multiple_wrappers(benchmark):
- joined = u'\r\n'.join(
- u'BEGIN:VADDRESSBOOK\r\n' +
- x +
- u'\r\nEND:VADDRESSBOOK\r\n'
+ joined = '\r\n'.join(
+ 'BEGIN:VADDRESSBOOK\r\n'
+ + x
+ + '\r\nEND:VADDRESSBOOK\r\n'
for x in _simple_split
)
given = benchmark(lambda: list(vobject.split_collection(joined)))
@@ -105,32 +103,32 @@ def test_split_collection_timezones():
]
timezone = (
- u'BEGIN:VTIMEZONE\r\n'
- u'TZID:/mozilla.org/20070129_1/Asia/Tokyo\r\n'
- u'X-LIC-LOCATION:Asia/Tokyo\r\n'
- u'BEGIN:STANDARD\r\n'
- u'TZOFFSETFROM:+0900\r\n'
- u'TZOFFSETTO:+0900\r\n'
- u'TZNAME:JST\r\n'
- u'DTSTART:19700101T000000\r\n'
- u'END:STANDARD\r\n'
- u'END:VTIMEZONE'
+ 'BEGIN:VTIMEZONE\r\n'
+ 'TZID:/mozilla.org/20070129_1/Asia/Tokyo\r\n'
+ 'X-LIC-LOCATION:Asia/Tokyo\r\n'
+ 'BEGIN:STANDARD\r\n'
+ 'TZOFFSETFROM:+0900\r\n'
+ 'TZOFFSETTO:+0900\r\n'
+ 'TZNAME:JST\r\n'
+ 'DTSTART:19700101T000000\r\n'
+ 'END:STANDARD\r\n'
+ 'END:VTIMEZONE'
)
- full = u'\r\n'.join(
- [u'BEGIN:VCALENDAR'] +
- items +
- [timezone, u'END:VCALENDAR']
+ full = '\r\n'.join(
+ ['BEGIN:VCALENDAR']
+ + items
+ + [timezone, 'END:VCALENDAR']
)
- given = set(normalize_item(item)
- for item in vobject.split_collection(full))
- expected = set(
- normalize_item(u'\r\n'.join((
- u'BEGIN:VCALENDAR', item, timezone, u'END:VCALENDAR'
+ given = {normalize_item(item)
+ for item in vobject.split_collection(full)}
+ expected = {
+ normalize_item('\r\n'.join((
+ 'BEGIN:VCALENDAR', item, timezone, 'END:VCALENDAR'
)))
for item in items
- )
+ }
assert given == expected
@@ -148,20 +146,20 @@ def test_split_contacts():
def test_hash_item():
a = EVENT_TEMPLATE.format(r=1, uid=1)
- b = u'\n'.join(line for line in a.splitlines()
- if u'PRODID' not in line)
+ b = '\n'.join(line for line in a.splitlines()
+ if 'PRODID' not in line)
assert vobject.hash_item(a) == vobject.hash_item(b)
def test_multiline_uid(benchmark):
- a = (u'BEGIN:FOO\r\n'
- u'UID:123456789abcd\r\n'
- u' efgh\r\n'
- u'END:FOO\r\n')
- assert benchmark(lambda: vobject.Item(a).uid) == u'123456789abcdefgh'
+ a = ('BEGIN:FOO\r\n'
+ 'UID:123456789abcd\r\n'
+ ' efgh\r\n'
+ 'END:FOO\r\n')
+ assert benchmark(lambda: vobject.Item(a).uid) == '123456789abcdefgh'
-complex_uid_item = dedent(u'''
+complex_uid_item = dedent('''
BEGIN:VCALENDAR
BEGIN:VTIMEZONE
TZID:Europe/Rome
@@ -202,9 +200,9 @@ complex_uid_item = dedent(u'''
def test_multiline_uid_complex(benchmark):
assert benchmark(lambda: vobject.Item(complex_uid_item).uid) == (
- u'040000008200E00074C5B7101A82E008000000005'
- u'0AAABEEF50DCF001000000062548482FA830A46B9'
- u'EA62114AC9F0EF'
+ '040000008200E00074C5B7101A82E008000000005'
+ '0AAABEEF50DCF001000000062548482FA830A46B9'
+ 'EA62114AC9F0EF'
)
diff --git a/vdirsyncer/__init__.py b/vdirsyncer/__init__.py
index 45eaaa3..84dbb69 100644
--- a/vdirsyncer/__init__.py
+++ b/vdirsyncer/__init__.py
@@ -1,9 +1,7 @@
-# -*- coding: utf-8 -*-
'''
Vdirsyncer synchronizes calendars and contacts.
'''
-from __future__ import print_function
PROJECT_HOME = 'https://github.com/pimutils/vdirsyncer'
BUGTRACKER_HOME = PROJECT_HOME + '/issues'
diff --git a/vdirsyncer/cli/__init__.py b/vdirsyncer/cli/__init__.py
index b87ccbd..116759a 100644
--- a/vdirsyncer/cli/__init__.py
+++ b/vdirsyncer/cli/__init__.py
@@ -1,5 +1,3 @@
-# -*- coding: utf-8 -*-
-
import functools
import logging
import sys
@@ -15,7 +13,7 @@ cli_logger = logging.getLogger(__name__)
click_log.basic_config('vdirsyncer')
-class AppContext(object):
+class AppContext:
def __init__(self):
self.config = None
self.fetched_params = {}
diff --git a/vdirsyncer/cli/config.py b/vdirsyncer/cli/config.py
index 87296d9..643e506 100644
--- a/vdirsyncer/cli/config.py
+++ b/vdirsyncer/cli/config.py
@@ -33,17 +33,17 @@ def _validate_general_section(general_config):
problems = []
if invalid:
- problems.append(u'general section doesn\'t take the parameters: {}'
- .format(u', '.join(invalid)))
+ problems.append('general section doesn\'t take the parameters: {}'
+ .format(', '.join(invalid)))
if missing:
- problems.append(u'general section is missing the parameters: {}'
- .format(u', '.join(missing)))
+ problems.append('general section is missing the parameters: {}'
+ .format(', '.join(missing)))
if problems:
raise exceptions.UserError(
- u'Invalid general section. Copy the example '
- u'config from the repository and edit it: {}'
+ 'Invalid general section. Copy the example '
+ 'config from the repository and edit it: {}'
.format(PROJECT_HOME), problems=problems)
@@ -64,7 +64,7 @@ def _validate_collections_param(collections):
e = ValueError(
'Expected list of format '
'["config_name", "storage_a_name", "storage_b_name"]'
- .format(len(collection)))
+ )
if len(collection) != 3:
raise e
@@ -151,7 +151,7 @@ def _parse_options(items, section=None):
.format(section, key, e))
-class Config(object):
+class Config:
def __init__(self, general, pairs, storages):
self.general = general
self.storages = storages
@@ -209,7 +209,7 @@ class Config(object):
raise exceptions.PairNotFound(e, pair_name=pair_name)
-class PairConfig(object):
+class PairConfig:
def __init__(self, full_config, name, options):
self._config = full_config
self.name = name
@@ -299,7 +299,7 @@ class PairConfig(object):
return partial_sync
-class CollectionConfig(object):
+class CollectionConfig:
def __init__(self, pair, name, config_a, config_b):
self.pair = pair
self._config = pair._config
diff --git a/vdirsyncer/cli/discover.py b/vdirsyncer/cli/discover.py
index 06aecfb..30addc3 100644
--- a/vdirsyncer/cli/discover.py
+++ b/vdirsyncer/cli/discover.py
@@ -1,5 +1,3 @@
-# -*- coding: utf-8 -*-
-
import hashlib
import json
import logging
@@ -224,7 +222,7 @@ def _print_collections(instance_name, get_discovered):
storage = storage_instance_from_config(args, create=False)
displayname = storage.get_meta('displayname')
except Exception:
- displayname = u''
+ displayname = ''
logger.info(' - {}{}'.format(
json.dumps(collection),
diff --git a/vdirsyncer/cli/fetchparams.py b/vdirsyncer/cli/fetchparams.py
index 29e61ae..346a14f 100644
--- a/vdirsyncer/cli/fetchparams.py
+++ b/vdirsyncer/cli/fetchparams.py
@@ -1,5 +1,3 @@
-# -*- coding: utf-8 -*-
-
import logging
import click
diff --git a/vdirsyncer/cli/tasks.py b/vdirsyncer/cli/tasks.py
index 8735b59..da7adc5 100644
--- a/vdirsyncer/cli/tasks.py
+++ b/vdirsyncer/cli/tasks.py
@@ -1,5 +1,3 @@
-# -*- coding: utf-8 -*-
-
import functools
import json
diff --git a/vdirsyncer/cli/utils.py b/vdirsyncer/cli/utils.py
index 27589d4..a76f50e 100644
--- a/vdirsyncer/cli/utils.py
+++ b/vdirsyncer/cli/utils.py
@@ -1,5 +1,3 @@
-# -*- coding: utf-8 -*-
-
import contextlib
import errno
import importlib
@@ -27,7 +25,7 @@ STATUS_PERMISSIONS = 0o600
STATUS_DIR_PERMISSIONS = 0o700
-class _StorageIndex(object):
+class _StorageIndex:
def __init__(self):
self._storages = dict(
caldav='vdirsyncer.storage.dav.CalDAVStorage',
@@ -288,24 +286,24 @@ def handle_storage_init_error(cls, config):
if missing:
problems.append(
- u'{} storage requires the parameters: {}'
- .format(cls.storage_name, u', '.join(missing)))
+ '{} storage requires the parameters: {}'
+ .format(cls.storage_name, ', '.join(missing)))
if invalid:
problems.append(
- u'{} storage doesn\'t take the parameters: {}'
- .format(cls.storage_name, u', '.join(invalid)))
+ '{} storage doesn\'t take the parameters: {}'
+ .format(cls.storage_name, ', '.join(invalid)))
if not problems:
raise e
raise exceptions.UserError(
- u'Failed to initialize {}'.format(config['instance_name']),
+ 'Failed to initialize {}'.format(config['instance_name']),
problems=problems
)
-class WorkerQueue(object):
+class WorkerQueue:
'''
A simple worker-queue setup.
diff --git a/vdirsyncer/exceptions.py b/vdirsyncer/exceptions.py
index 722e7de..5644b54 100644
--- a/vdirsyncer/exceptions.py
+++ b/vdirsyncer/exceptions.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
'''
Contains exception classes used by vdirsyncer. Not all exceptions are here,
only the most commonly used ones.
@@ -14,7 +13,7 @@ class Error(Exception):
raise TypeError('Invalid argument: {}'.format(key))
setattr(self, key, value)
- super(Error, self).__init__(*args)
+ super().__init__(*args)
class UserError(Error, ValueError):
@@ -26,7 +25,7 @@ class UserError(Error, ValueError):
def __str__(self):
msg = Error.__str__(self)
for problem in self.problems or ():
- msg += u'\n - {}'.format(problem)
+ msg += '\n - {}'.format(problem)
return msg
diff --git a/vdirsyncer/http.py b/vdirsyncer/http.py
index cb13ae3..5cb6204 100644
--- a/vdirsyncer/http.py
+++ b/vdirsyncer/http.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
import logging
import requests
@@ -134,7 +133,7 @@ def request(method, url, session=None, latin1_fallback=True,
func = session.request
- logger.debug(u'{} {}'.format(method, url))
+ logger.debug('{} {}'.format(method, url))
logger.debug(kwargs.get('headers', {}))
logger.debug(kwargs.get('data', None))
logger.debug('Sending request...')
diff --git a/vdirsyncer/metasync.py b/vdirsyncer/metasync.py
index ca85c70..875f255 100644
--- a/vdirsyncer/metasync.py
+++ b/vdirsyncer/metasync.py
@@ -16,12 +16,12 @@ class MetaSyncConflict(MetaSyncError):
def metasync(storage_a, storage_b, status, keys, conflict_resolution=None):
def _a_to_b():
- logger.info(u'Copying {} to {}'.format(key, storage_b))
+ logger.info('Copying {} to {}'.format(key, storage_b))
storage_b.set_meta(key, a)
status[key] = a
def _b_to_a():
- logger.info(u'Copying {} to {}'.format(key, storage_a))
+ logger.info('Copying {} to {}'.format(key, storage_a))
storage_a.set_meta(key, b)
status[key] = b
@@ -45,10 +45,10 @@ def metasync(storage_a, storage_b, status, keys, conflict_resolution=None):
a = storage_a.get_meta(key)
b = storage_b.get_meta(key)
s = normalize_meta_value(status.get(key))
- logger.debug(u'Key: {}'.format(key))
- logger.debug(u'A: {}'.format(a))
- logger.debug(u'B: {}'.format(b))
- logger.debug(u'S: {}'.format(s))
+ logger.debug('Key: {}'.format(key))
+ logger.debug('A: {}'.format(a))
+ logger.debug('B: {}'.format(b))
+ logger.debug('S: {}'.format(s))
if a != s and b != s:
_resolve_conflict()
diff --git a/vdirsyncer/repair.py b/vdirsyncer/repair.py
index 0a775ee..6c8b257 100644
--- a/vdirsyncer/repair.py
+++ b/vdirsyncer/repair.py
@@ -1,5 +1,3 @@
-# -*- coding: utf-8 -*-
-
import logging
from os.path import basename
@@ -17,7 +15,7 @@ def repair_storage(storage, repair_unsafe_uid):
all_hrefs = list(storage.list())
for i, (href, _) in enumerate(all_hrefs):
item, etag = storage.get(href)
- logger.info(u'[{}/{}] Processing {}'
+ logger.info('[{}/{}] Processing {}'
.format(i, len(all_hrefs), href))
try:
diff --git a/vdirsyncer/storage/__init__.py b/vdirsyncer/storage/__init__.py
index 5dd1829..5547ab9 100644
--- a/vdirsyncer/storage/__init__.py
+++ b/vdirsyncer/storage/__init__.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
'''
There are storage classes which control the access to one vdir-collection and
offer basic CRUD-ish methods for modifying those collections. The exact
diff --git a/vdirsyncer/storage/base.py b/vdirsyncer/storage/base.py
index 89fe919..7dfcbdd 100644
--- a/vdirsyncer/storage/base.py
+++ b/vdirsyncer/storage/base.py
@@ -1,5 +1,3 @@
-# -*- coding: utf-8 -*-
-
import contextlib
import functools
@@ -20,7 +18,7 @@ class StorageMeta(type):
def __init__(cls, name, bases, d):
for method in ('update', 'upload', 'delete'):
setattr(cls, method, mutating_storage_method(getattr(cls, method)))
- return super(StorageMeta, cls).__init__(name, bases, d)
+ return super().__init__(name, bases, d)
class Storage(metaclass=StorageMeta):
@@ -116,7 +114,7 @@ class Storage(metaclass=StorageMeta):
return '<{}(**{})>'.format(
self.__class__.__name__,
- dict((x, getattr(self, x)) for x in self._repr_attributes)
+ {x: getattr(self, x) for x in self._repr_attributes}
)
def list(self):
diff --git a/vdirsyncer/storage/dav.py b/vdirsyncer/storage/dav.py
index 47ccf8b..a3becb7 100644
--- a/vdirsyncer/storage/dav.py
+++ b/vdirsyncer/storage/dav.py
@@ -1,5 +1,3 @@
-# -*- coding: utf-8 -*-
-
import datetime
import logging
import urllib.parse as urlparse
@@ -140,7 +138,7 @@ def _fuzzy_matches_mimetype(strict, weak):
return False
-class Discover(object):
+class Discover:
_namespace = None
_resourcetype = None
_homeset_xml = None
@@ -349,7 +347,7 @@ class CardDiscover(Discover):
_well_known_uri = '/.well-known/carddav'
-class DAVSession(object):
+class DAVSession:
'''
A helper class to connect to DAV servers.
'''
@@ -423,7 +421,7 @@ class DAVStorage(Storage):
self.session, kwargs = \
self.session_class.init_and_remaining_args(**kwargs)
- super(DAVStorage, self).__init__(**kwargs)
+ super().__init__(**kwargs)
import inspect
__init__.__signature__ = inspect.signature(session_class.__init__)
@@ -483,7 +481,7 @@ class DAVStorage(Storage):
.format(href))
continue
- raw = raw.text or u''
+ raw = raw.text or ''
if isinstance(raw, bytes):
raw = raw.decode(response.encoding)
@@ -617,7 +615,7 @@ class DAVStorage(Storage):
headers = self.session.get_default_headers()
headers['Depth'] = '1'
- data = '''
+ data = b'''
@@ -625,7 +623,7 @@ class DAVStorage(Storage):
- '''.encode('utf-8')
+ '''
# We use a PROPFIND request instead of addressbook-query due to issues
# with Zimbra. See https://github.com/pimutils/vdirsyncer/issues/83
@@ -643,7 +641,7 @@ class DAVStorage(Storage):
except KeyError:
raise exceptions.UnsupportedMetadataError()
- xpath = '{%s}%s' % (namespace, tagname)
+ xpath = '{{{}}}{}'.format(namespace, tagname)
data = '''
@@ -668,7 +666,7 @@ class DAVStorage(Storage):
text = normalize_meta_value(getattr(prop, 'text', None))
if text:
return text
- return u''
+ return ''
def set_meta(self, key, value):
try:
@@ -676,7 +674,7 @@ class DAVStorage(Storage):
except KeyError:
raise exceptions.UnsupportedMetadataError()
- lxml_selector = '{%s}%s' % (namespace, tagname)
+ lxml_selector = '{{{}}}{}'.format(namespace, tagname)
element = etree.Element(lxml_selector)
element.text = normalize_meta_value(value)
@@ -730,7 +728,7 @@ class CalDAVStorage(DAVStorage):
def __init__(self, start_date=None, end_date=None,
item_types=(), **kwargs):
- super(CalDAVStorage, self).__init__(**kwargs)
+ super().__init__(**kwargs)
if not isinstance(item_types, (list, tuple)):
raise exceptions.UserError('item_types must be a list.')
@@ -774,9 +772,8 @@ class CalDAVStorage(DAVStorage):
timefilter=timefilter)
else:
if start is not None and end is not None:
- for x in CalDAVStorage._get_list_filters(('VTODO', 'VEVENT'),
- start, end):
- yield x
+ yield from CalDAVStorage._get_list_filters(('VTODO', 'VEVENT'),
+ start, end)
def list(self):
caldavfilters = list(self._get_list_filters(
@@ -792,8 +789,7 @@ class CalDAVStorage(DAVStorage):
# instead?
#
# See https://github.com/dmfs/tasks/issues/118 for backstory.
- for x in DAVStorage.list(self):
- yield x
+ yield from DAVStorage.list(self)
data = '''
(etag, item)
self.metadata = {}
self.fileext = fileext
- super(MemoryStorage, self).__init__(**kwargs)
+ super().__init__(**kwargs)
def _get_href(self, item):
return item.ident + self.fileext
diff --git a/vdirsyncer/storage/singlefile.py b/vdirsyncer/storage/singlefile.py
index 1e13f20..5a56aef 100644
--- a/vdirsyncer/storage/singlefile.py
+++ b/vdirsyncer/storage/singlefile.py
@@ -1,5 +1,3 @@
-# -*- coding: utf-8 -*-
-
import collections
import contextlib
import functools
@@ -41,7 +39,7 @@ class SingleFileStorage(Storage):
_last_etag = None
def __init__(self, path, encoding='utf-8', **kwargs):
- super(SingleFileStorage, self).__init__(**kwargs)
+ super().__init__(**kwargs)
path = os.path.abspath(expand_path(path))
checkfile(path, create=False)
@@ -70,9 +68,10 @@ class SingleFileStorage(Storage):
args['path'] = subpath
collection_end = (
- placeholder_pos +
- 2 + # length of '%s'
- len(subpath) - len(path)
+ placeholder_pos
+ + 2 # length of '%s'
+ + len(subpath)
+ - len(path)
)
collection = subpath[placeholder_pos:collection_end]
args['collection'] = collection
@@ -162,10 +161,11 @@ class SingleFileStorage(Storage):
def _write(self):
if self._last_etag is not None and \
self._last_etag != get_etag_from_file(self.path):
- raise exceptions.PreconditionFailed(
- 'Some other program modified the file {r!}. Re-run the '
+ raise exceptions.PreconditionFailed((
+ 'Some other program modified the file {!r}. Re-run the '
'synchronization and make sure absolutely no other program is '
- 'writing into the same file.'.format(self.path))
+ 'writing into the same file.'
+ ).format(self.path))
text = join_collection(
item.raw for item, etag in self._items.values()
)
diff --git a/vdirsyncer/sync/__init__.py b/vdirsyncer/sync/__init__.py
index e899868..bdb945d 100644
--- a/vdirsyncer/sync/__init__.py
+++ b/vdirsyncer/sync/__init__.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
'''
The `sync` function in `vdirsyncer.sync` can be called on two instances of
`Storage` to synchronize them. Apart from the defined errors, this is the only
@@ -24,7 +23,7 @@ from .exceptions import BothReadOnly, IdentAlreadyExists, PartialSync, \
sync_logger = logging.getLogger(__name__)
-class _StorageInfo(object):
+class _StorageInfo:
'''A wrapper class that holds prefetched items, the status and other
things.'''
def __init__(self, storage, status):
@@ -74,9 +73,9 @@ class _StorageInfo(object):
new_meta = self.status.get_new(ident)
return (
- new_meta.etag != old_meta.etag and # etag changed
+ new_meta.etag != old_meta.etag # etag changed
# item actually changed
- (old_meta.hash is None or new_meta.hash != old_meta.hash)
+ and (old_meta.hash is None or new_meta.hash != old_meta.hash)
)
def set_item_cache(self, ident, item):
@@ -199,7 +198,7 @@ class Upload(Action):
if self.dest.storage.read_only:
href = etag = None
else:
- sync_logger.info(u'Copying (uploading) item {} to {}'
+ sync_logger.info('Copying (uploading) item {} to {}'
.format(self.ident, self.dest.storage))
href, etag = self.dest.storage.upload(self.item)
assert href is not None
@@ -221,7 +220,7 @@ class Update(Action):
if self.dest.storage.read_only:
meta = ItemMetadata(hash=self.item.hash)
else:
- sync_logger.info(u'Copying (updating) item {} to {}'
+ sync_logger.info('Copying (updating) item {} to {}'
.format(self.ident, self.dest.storage))
meta = self.dest.status.get_new(self.ident)
meta.etag = \
@@ -238,7 +237,7 @@ class Delete(Action):
def _run_impl(self, a, b):
meta = self.dest.status.get_new(self.ident)
if not self.dest.storage.read_only:
- sync_logger.info(u'Deleting item {} from {}'
+ sync_logger.info('Deleting item {} from {}'
.format(self.ident, self.dest.storage))
self.dest.storage.delete(meta.href, meta.etag)
@@ -251,14 +250,14 @@ class ResolveConflict(Action):
def run(self, a, b, conflict_resolution, partial_sync):
with self.auto_rollback(a, b):
- sync_logger.info(u'Doing conflict resolution for item {}...'
+ sync_logger.info('Doing conflict resolution for item {}...'
.format(self.ident))
meta_a = a.status.get_new(self.ident)
meta_b = b.status.get_new(self.ident)
if meta_a.hash == meta_b.hash:
- sync_logger.info(u'...same content on both sides.')
+ sync_logger.info('...same content on both sides.')
elif conflict_resolution is None:
raise SyncConflict(ident=self.ident, href_a=meta_a.href,
href_b=meta_b.href)
diff --git a/vdirsyncer/sync/status.py b/vdirsyncer/sync/status.py
index 4278c45..2544680 100644
--- a/vdirsyncer/sync/status.py
+++ b/vdirsyncer/sync/status.py
@@ -313,7 +313,7 @@ class SqliteStatus(_StatusBase):
return self._get_by_href_impl(*a, **kw)
-class SubStatus(object):
+class SubStatus:
def __init__(self, parent, side):
self.parent = parent
assert side in 'ab'
diff --git a/vdirsyncer/utils.py b/vdirsyncer/utils.py
index f3b5d43..5559ec3 100644
--- a/vdirsyncer/utils.py
+++ b/vdirsyncer/utils.py
@@ -1,5 +1,3 @@
-# -*- coding: utf-8 -*-
-
import functools
import os
import sys
@@ -154,7 +152,7 @@ def checkfile(path, create=False):
.format(path))
-class cached_property(object):
+class cached_property:
'''A read-only @property that is only evaluated once. Only usable on class
instances' methods.
'''
@@ -212,8 +210,7 @@ def open_graphical_browser(url, new=0, autoraise=True):
emulator.
'''
import webbrowser
- cli_names = set(['www-browser', 'links', 'links2', 'elinks', 'lynx',
- 'w3m'])
+ cli_names = {'www-browser', 'links', 'links2', 'elinks', 'lynx', 'w3m'}
if webbrowser._tryorder is None: # Python 3.7
webbrowser.register_standard_browsers()
diff --git a/vdirsyncer/vobject.py b/vdirsyncer/vobject.py
index d97a057..521e97c 100644
--- a/vdirsyncer/vobject.py
+++ b/vdirsyncer/vobject.py
@@ -1,5 +1,3 @@
-# -*- coding: utf-8 -*-
-
import hashlib
from itertools import chain, tee
@@ -34,7 +32,7 @@ IGNORE_PROPS = (
)
-class Item(object):
+class Item:
'''Immutable wrapper class for VCALENDAR (VEVENT, VTODO) and
VCARD'''
@@ -117,7 +115,7 @@ def normalize_item(item, ignore_props=IGNORE_PROPS):
del x[prop]
x.props.sort()
- return u'\r\n'.join(filter(bool, (line.strip() for line in x.props)))
+ return '\r\n'.join(filter(bool, (line.strip() for line in x.props)))
def _strip_timezones(item):
@@ -146,16 +144,16 @@ def split_collection(text):
for item in chain(items.values(), ungrouped_items):
item.subcomponents.extend(inline)
- yield u'\r\n'.join(item.dump_lines())
+ yield '\r\n'.join(item.dump_lines())
def _split_collection_impl(item, main, inline, items, ungrouped_items):
- if item.name == u'VTIMEZONE':
+ if item.name == 'VTIMEZONE':
inline.append(item)
- elif item.name == u'VCARD':
+ elif item.name == 'VCARD':
ungrouped_items.append(item)
- elif item.name in (u'VTODO', u'VEVENT', u'VJOURNAL'):
- uid = item.get(u'UID', u'')
+ elif item.name in ('VTODO', 'VEVENT', 'VJOURNAL'):
+ uid = item.get('UID', '')
wrapper = _Component(main.name, main.props[:], [])
if uid.strip():
@@ -164,7 +162,7 @@ def _split_collection_impl(item, main, inline, items, ungrouped_items):
ungrouped_items.append(wrapper)
wrapper.subcomponents.append(item)
- elif item.name in (u'VCALENDAR', u'VADDRESSBOOK'):
+ elif item.name in ('VCALENDAR', 'VADDRESSBOOK'):
if item.name == 'VCALENDAR':
del item['METHOD']
for subitem in item.subcomponents:
@@ -176,10 +174,10 @@ def _split_collection_impl(item, main, inline, items, ungrouped_items):
_default_join_wrappers = {
- u'VCALENDAR': u'VCALENDAR',
- u'VEVENT': u'VCALENDAR',
- u'VTODO': u'VCALENDAR',
- u'VCARD': u'VADDRESSBOOK'
+ 'VCALENDAR': 'VCALENDAR',
+ 'VEVENT': 'VCALENDAR',
+ 'VTODO': 'VCALENDAR',
+ 'VCARD': 'VADDRESSBOOK'
}
@@ -207,16 +205,16 @@ def join_collection(items, wrappers=_default_join_wrappers):
if wrapper_type is not None:
lines = chain(*(
- [u'BEGIN:{}'.format(wrapper_type)],
+ ['BEGIN:{}'.format(wrapper_type)],
# XXX: wrapper_props is a list of lines (with line-wrapping), so
# filtering out duplicate lines will almost certainly break
# multiline-values. Since the only props we usually need to
# support are PRODID and VERSION, I don't care.
uniq(wrapper_props),
lines,
- [u'END:{}'.format(wrapper_type)]
+ ['END:{}'.format(wrapper_type)]
))
- return u''.join(line + u'\r\n' for line in lines)
+ return ''.join(line + '\r\n' for line in lines)
def _get_item_type(components, wrappers):
@@ -237,7 +235,7 @@ def _get_item_type(components, wrappers):
raise ValueError('Not sure how to join components.')
-class _Component(object):
+class _Component:
'''
Raw outline of the components.
@@ -277,10 +275,10 @@ class _Component(object):
rv = []
try:
for _i, line in enumerate(lines):
- if line.startswith(u'BEGIN:'):
- c_name = line[len(u'BEGIN:'):].strip().upper()
+ if line.startswith('BEGIN:'):
+ c_name = line[len('BEGIN:'):].strip().upper()
stack.append(cls(c_name, [], []))
- elif line.startswith(u'END:'):
+ elif line.startswith('END:'):
component = stack.pop()
if stack:
stack[-1].subcomponents.append(component)
@@ -301,16 +299,14 @@ class _Component(object):
return rv[0]
def dump_lines(self):
- yield u'BEGIN:{}'.format(self.name)
- for line in self.props:
- yield line
+ yield 'BEGIN:{}'.format(self.name)
+ yield from self.props
for c in self.subcomponents:
- for line in c.dump_lines():
- yield line
- yield u'END:{}'.format(self.name)
+ yield from c.dump_lines()
+ yield 'END:{}'.format(self.name)
def __delitem__(self, key):
- prefix = (u'{}:'.format(key), u'{};'.format(key))
+ prefix = ('{}:'.format(key), '{};'.format(key))
new_lines = []
lineiter = iter(self.props)
while True:
@@ -323,7 +319,7 @@ class _Component(object):
break
for line in lineiter:
- if not line.startswith((u' ', u'\t')):
+ if not line.startswith((' ', '\t')):
new_lines.append(line)
break
@@ -331,9 +327,9 @@ class _Component(object):
def __setitem__(self, key, val):
assert isinstance(val, str)
- assert u'\n' not in val
+ assert '\n' not in val
del self[key]
- line = u'{}:{}'.format(key, val)
+ line = '{}:{}'.format(key, val)
self.props.append(line)
def __contains__(self, obj):
@@ -360,7 +356,7 @@ class _Component(object):
raise KeyError()
for line in iterlines:
- if line.startswith((u' ', u'\t')):
+ if line.startswith((' ', '\t')):
rv += line[1:]
else:
break
@@ -375,8 +371,8 @@ class _Component(object):
def __eq__(self, other):
return (
- isinstance(other, type(self)) and
- self.name == other.name and
- self.props == other.props and
- self.subcomponents == other.subcomponents
+ isinstance(other, type(self))
+ and self.name == other.name
+ and self.props == other.props
+ and self.subcomponents == other.subcomponents
)