mirror of
https://github.com/samsonjs/vdirsyncer.git
synced 2026-04-27 14:57:41 +00:00
ruff: apply auto-fixes
This commit is contained in:
parent
2f548e048d
commit
20cc1247ed
19 changed files with 101 additions and 102 deletions
|
|
@ -20,7 +20,7 @@ copyright = "2014-{}, Markus Unterwaditzer & contributors".format(
|
||||||
release = get_distribution("vdirsyncer").version
|
release = get_distribution("vdirsyncer").version
|
||||||
version = ".".join(release.split(".")[:2]) # The short X.Y version.
|
version = ".".join(release.split(".")[:2]) # The short X.Y version.
|
||||||
|
|
||||||
rst_epilog = ".. |vdirsyncer_version| replace:: %s" % release
|
rst_epilog = f".. |vdirsyncer_version| replace:: {release}"
|
||||||
|
|
||||||
exclude_patterns = ["_build"]
|
exclude_patterns = ["_build"]
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -10,16 +10,15 @@ import aiostream
|
||||||
import pytest
|
import pytest
|
||||||
import pytest_asyncio
|
import pytest_asyncio
|
||||||
|
|
||||||
|
from tests import EVENT_TEMPLATE
|
||||||
|
from tests import TASK_TEMPLATE
|
||||||
|
from tests import VCARD_TEMPLATE
|
||||||
|
from tests import assert_item_equals
|
||||||
|
from tests import normalize_item
|
||||||
from vdirsyncer import exceptions
|
from vdirsyncer import exceptions
|
||||||
from vdirsyncer.storage.base import normalize_meta_value
|
from vdirsyncer.storage.base import normalize_meta_value
|
||||||
from vdirsyncer.vobject import Item
|
from vdirsyncer.vobject import Item
|
||||||
|
|
||||||
from .. import EVENT_TEMPLATE
|
|
||||||
from .. import TASK_TEMPLATE
|
|
||||||
from .. import VCARD_TEMPLATE
|
|
||||||
from .. import assert_item_equals
|
|
||||||
from .. import normalize_item
|
|
||||||
|
|
||||||
|
|
||||||
def get_server_mixin(server_name):
|
def get_server_mixin(server_name):
|
||||||
from . import __name__ as base
|
from . import __name__ as base
|
||||||
|
|
|
||||||
|
|
@ -8,12 +8,11 @@ import aiostream
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from tests import assert_item_equals
|
from tests import assert_item_equals
|
||||||
|
from tests.storage import StorageTests
|
||||||
|
from tests.storage import get_server_mixin
|
||||||
from vdirsyncer import exceptions
|
from vdirsyncer import exceptions
|
||||||
from vdirsyncer.vobject import Item
|
from vdirsyncer.vobject import Item
|
||||||
|
|
||||||
from .. import StorageTests
|
|
||||||
from .. import get_server_mixin
|
|
||||||
|
|
||||||
dav_server = os.environ.get("DAV_SERVER", "skip")
|
dav_server = os.environ.get("DAV_SERVER", "skip")
|
||||||
ServerMixin = get_server_mixin(dav_server)
|
ServerMixin = get_server_mixin(dav_server)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -11,10 +11,10 @@ from aioresponses import aioresponses
|
||||||
from tests import EVENT_TEMPLATE
|
from tests import EVENT_TEMPLATE
|
||||||
from tests import TASK_TEMPLATE
|
from tests import TASK_TEMPLATE
|
||||||
from tests import VCARD_TEMPLATE
|
from tests import VCARD_TEMPLATE
|
||||||
|
from tests.storage import format_item
|
||||||
from vdirsyncer import exceptions
|
from vdirsyncer import exceptions
|
||||||
from vdirsyncer.storage.dav import CalDAVStorage
|
from vdirsyncer.storage.dav import CalDAVStorage
|
||||||
|
|
||||||
from .. import format_item
|
|
||||||
from . import DAVStorageTests
|
from . import DAVStorageTests
|
||||||
from . import dav_server
|
from . import dav_server
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -10,8 +10,8 @@ import aiohttp
|
||||||
import click
|
import click
|
||||||
import click_log
|
import click_log
|
||||||
|
|
||||||
from .. import BUGTRACKER_HOME
|
from vdirsyncer import BUGTRACKER_HOME
|
||||||
from .. import __version__
|
from vdirsyncer import __version__
|
||||||
|
|
||||||
cli_logger = logging.getLogger(__name__)
|
cli_logger = logging.getLogger(__name__)
|
||||||
click_log.basic_config("vdirsyncer")
|
click_log.basic_config("vdirsyncer")
|
||||||
|
|
|
||||||
|
|
@ -8,13 +8,13 @@ from itertools import chain
|
||||||
from typing import IO
|
from typing import IO
|
||||||
from typing import Any
|
from typing import Any
|
||||||
from typing import Generator
|
from typing import Generator
|
||||||
from typing import Tuple
|
|
||||||
|
|
||||||
from .. import PROJECT_HOME
|
from vdirsyncer import PROJECT_HOME
|
||||||
from .. import exceptions
|
from vdirsyncer import exceptions
|
||||||
from ..utils import cached_property
|
from vdirsyncer.utils import cached_property
|
||||||
from ..utils import expand_path
|
from vdirsyncer.utils import expand_path
|
||||||
from ..vobject import Item
|
from vdirsyncer.vobject import Item
|
||||||
|
|
||||||
from .fetchparams import expand_fetch_params
|
from .fetchparams import expand_fetch_params
|
||||||
from .utils import storage_class_from_config
|
from .utils import storage_class_from_config
|
||||||
|
|
||||||
|
|
@ -232,7 +232,7 @@ class PairConfig:
|
||||||
self.name_b: str = options.pop("b")
|
self.name_b: str = options.pop("b")
|
||||||
|
|
||||||
self._partial_sync: str | None = options.pop("partial_sync", None)
|
self._partial_sync: str | None = options.pop("partial_sync", None)
|
||||||
self.metadata: str | Tuple[()] = options.pop("metadata", ())
|
self.metadata: str | tuple[()] = options.pop("metadata", ())
|
||||||
|
|
||||||
self.conflict_resolution = self._process_conflict_resolution_param(
|
self.conflict_resolution = self._process_conflict_resolution_param(
|
||||||
options.pop("conflict_resolution", None)
|
options.pop("conflict_resolution", None)
|
||||||
|
|
@ -338,7 +338,7 @@ def _resolve_conflict_via_command(
|
||||||
if _check_call is None:
|
if _check_call is None:
|
||||||
from subprocess import check_call as _check_call
|
from subprocess import check_call as _check_call
|
||||||
|
|
||||||
from ..vobject import Item
|
from vdirsyncer.vobject import Item
|
||||||
|
|
||||||
dir = tempfile.mkdtemp(prefix="vdirsyncer-conflict.")
|
dir = tempfile.mkdtemp(prefix="vdirsyncer-conflict.")
|
||||||
try:
|
try:
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,8 @@ import sys
|
||||||
import aiohttp
|
import aiohttp
|
||||||
import aiostream
|
import aiostream
|
||||||
|
|
||||||
from .. import exceptions
|
from vdirsyncer import exceptions
|
||||||
|
|
||||||
from .utils import handle_collection_not_found
|
from .utils import handle_collection_not_found
|
||||||
from .utils import handle_storage_init_error
|
from .utils import handle_storage_init_error
|
||||||
from .utils import load_status
|
from .utils import load_status
|
||||||
|
|
|
||||||
|
|
@ -4,9 +4,10 @@ import logging
|
||||||
|
|
||||||
import click
|
import click
|
||||||
|
|
||||||
from .. import exceptions
|
from vdirsyncer import exceptions
|
||||||
from ..utils import expand_path
|
from vdirsyncer.utils import expand_path
|
||||||
from ..utils import synchronized
|
from vdirsyncer.utils import synchronized
|
||||||
|
|
||||||
from . import AppContext
|
from . import AppContext
|
||||||
|
|
||||||
SUFFIX = ".fetch"
|
SUFFIX = ".fetch"
|
||||||
|
|
|
||||||
|
|
@ -4,8 +4,9 @@ import json
|
||||||
|
|
||||||
import aiohttp
|
import aiohttp
|
||||||
|
|
||||||
from .. import exceptions
|
from vdirsyncer import exceptions
|
||||||
from .. import sync
|
from vdirsyncer import sync
|
||||||
|
|
||||||
from .config import CollectionConfig
|
from .config import CollectionConfig
|
||||||
from .discover import DiscoverResult
|
from .discover import DiscoverResult
|
||||||
from .discover import collections_for_pair
|
from .discover import collections_for_pair
|
||||||
|
|
@ -35,10 +36,8 @@ async def prepare_pair(pair_name, collections, config, *, connector):
|
||||||
config_a, config_b = all_collections[collection_name]
|
config_a, config_b = all_collections[collection_name]
|
||||||
except KeyError:
|
except KeyError:
|
||||||
raise exceptions.UserError(
|
raise exceptions.UserError(
|
||||||
"Pair {}: Collection {} not found. These are the "
|
f"Pair {pair_name}: Collection {json.dumps(collection_name)} not found. These are the "
|
||||||
"configured collections:\n{}".format(
|
f"configured collections:\n{list(all_collections)}"
|
||||||
pair_name, json.dumps(collection_name), list(all_collections)
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
collection = CollectionConfig(pair, collection_name, config_a, config_b)
|
collection = CollectionConfig(pair, collection_name, config_a, config_b)
|
||||||
|
|
@ -105,7 +104,7 @@ async def repair_collection(
|
||||||
*,
|
*,
|
||||||
connector: aiohttp.TCPConnector,
|
connector: aiohttp.TCPConnector,
|
||||||
):
|
):
|
||||||
from ..repair import repair_storage
|
from vdirsyncer.repair import repair_storage
|
||||||
|
|
||||||
storage_name, collection = collection, None
|
storage_name, collection = collection, None
|
||||||
if "/" in storage_name:
|
if "/" in storage_name:
|
||||||
|
|
@ -136,7 +135,7 @@ async def repair_collection(
|
||||||
|
|
||||||
|
|
||||||
async def metasync_collection(collection, general, *, connector: aiohttp.TCPConnector):
|
async def metasync_collection(collection, general, *, connector: aiohttp.TCPConnector):
|
||||||
from ..metasync import metasync
|
from vdirsyncer.metasync import metasync
|
||||||
|
|
||||||
pair = collection.pair
|
pair = collection.pair
|
||||||
status_name = get_status_name(pair.name, collection.name)
|
status_name = get_status_name(pair.name, collection.name)
|
||||||
|
|
|
||||||
|
|
@ -11,18 +11,19 @@ from typing import Any
|
||||||
import aiohttp
|
import aiohttp
|
||||||
import click
|
import click
|
||||||
|
|
||||||
from .. import BUGTRACKER_HOME
|
from vdirsyncer import BUGTRACKER_HOME
|
||||||
from .. import DOCS_HOME
|
from vdirsyncer import DOCS_HOME
|
||||||
from .. import exceptions
|
from vdirsyncer import exceptions
|
||||||
from ..storage.base import Storage
|
from vdirsyncer.storage.base import Storage
|
||||||
from ..sync.exceptions import IdentConflict
|
from vdirsyncer.sync.exceptions import IdentConflict
|
||||||
from ..sync.exceptions import PartialSync
|
from vdirsyncer.sync.exceptions import PartialSync
|
||||||
from ..sync.exceptions import StorageEmpty
|
from vdirsyncer.sync.exceptions import StorageEmpty
|
||||||
from ..sync.exceptions import SyncConflict
|
from vdirsyncer.sync.exceptions import SyncConflict
|
||||||
from ..sync.status import SqliteStatus
|
from vdirsyncer.sync.status import SqliteStatus
|
||||||
from ..utils import atomic_write
|
from vdirsyncer.utils import atomic_write
|
||||||
from ..utils import expand_path
|
from vdirsyncer.utils import expand_path
|
||||||
from ..utils import get_storage_init_args
|
from vdirsyncer.utils import get_storage_init_args
|
||||||
|
|
||||||
from . import cli_logger
|
from . import cli_logger
|
||||||
|
|
||||||
STATUS_PERMISSIONS = 0o600
|
STATUS_PERMISSIONS = 0o600
|
||||||
|
|
@ -78,13 +79,11 @@ def handle_cli_error(status_name=None, e=None):
|
||||||
cli_logger.critical(e)
|
cli_logger.critical(e)
|
||||||
except StorageEmpty as e:
|
except StorageEmpty as e:
|
||||||
cli_logger.error(
|
cli_logger.error(
|
||||||
'{status_name}: Storage "{name}" was completely emptied. If you '
|
f'{status_name}: Storage "{e.empty_storage.instance_name}" was completely emptied. If you '
|
||||||
"want to delete ALL entries on BOTH sides, then use "
|
"want to delete ALL entries on BOTH sides, then use "
|
||||||
"`vdirsyncer sync --force-delete {status_name}`. "
|
f"`vdirsyncer sync --force-delete {status_name}`. "
|
||||||
"Otherwise delete the files for {status_name} in your status "
|
f"Otherwise delete the files for {status_name} in your status "
|
||||||
"directory.".format(
|
"directory."
|
||||||
name=e.empty_storage.instance_name, status_name=status_name
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
except PartialSync as e:
|
except PartialSync as e:
|
||||||
cli_logger.error(
|
cli_logger.error(
|
||||||
|
|
|
||||||
|
|
@ -6,11 +6,10 @@ from abc import ABCMeta
|
||||||
from abc import abstractmethod
|
from abc import abstractmethod
|
||||||
from typing import Iterable
|
from typing import Iterable
|
||||||
|
|
||||||
|
from vdirsyncer import exceptions
|
||||||
|
from vdirsyncer.utils import uniq
|
||||||
from vdirsyncer.vobject import Item
|
from vdirsyncer.vobject import Item
|
||||||
|
|
||||||
from .. import exceptions
|
|
||||||
from ..utils import uniq
|
|
||||||
|
|
||||||
|
|
||||||
def mutating_storage_method(f):
|
def mutating_storage_method(f):
|
||||||
"""Wrap a method and fail if the instance is readonly."""
|
"""Wrap a method and fail if the instance is readonly."""
|
||||||
|
|
@ -141,10 +140,7 @@ class Storage(metaclass=StorageMeta):
|
||||||
except ValueError:
|
except ValueError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
return "<{}(**{})>".format(
|
return f"<{self.__class__.__name__}(**{ ({x: getattr(self, x) for x in self._repr_attributes}) })>"
|
||||||
self.__class__.__name__,
|
|
||||||
{x: getattr(self, x) for x in self._repr_attributes},
|
|
||||||
)
|
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
async def list(self) -> list[tuple]:
|
async def list(self) -> list[tuple]:
|
||||||
|
|
|
||||||
|
|
@ -11,16 +11,16 @@ from inspect import signature
|
||||||
import aiohttp
|
import aiohttp
|
||||||
import aiostream
|
import aiostream
|
||||||
|
|
||||||
|
from vdirsyncer import exceptions
|
||||||
|
from vdirsyncer import http
|
||||||
|
from vdirsyncer import utils
|
||||||
from vdirsyncer.exceptions import Error
|
from vdirsyncer.exceptions import Error
|
||||||
|
from vdirsyncer.http import USERAGENT
|
||||||
|
from vdirsyncer.http import prepare_auth
|
||||||
|
from vdirsyncer.http import prepare_client_cert
|
||||||
|
from vdirsyncer.http import prepare_verify
|
||||||
from vdirsyncer.vobject import Item
|
from vdirsyncer.vobject import Item
|
||||||
|
|
||||||
from .. import exceptions
|
|
||||||
from .. import http
|
|
||||||
from .. import utils
|
|
||||||
from ..http import USERAGENT
|
|
||||||
from ..http import prepare_auth
|
|
||||||
from ..http import prepare_client_cert
|
|
||||||
from ..http import prepare_verify
|
|
||||||
from .base import Storage
|
from .base import Storage
|
||||||
from .base import normalize_meta_value
|
from .base import normalize_meta_value
|
||||||
|
|
||||||
|
|
@ -321,7 +321,7 @@ class Discover:
|
||||||
|
|
||||||
class CalDiscover(Discover):
|
class CalDiscover(Discover):
|
||||||
_namespace = "urn:ietf:params:xml:ns:caldav"
|
_namespace = "urn:ietf:params:xml:ns:caldav"
|
||||||
_resourcetype = "{%s}calendar" % _namespace
|
_resourcetype = f"{{{_namespace}}}calendar"
|
||||||
_homeset_xml = b"""
|
_homeset_xml = b"""
|
||||||
<propfind xmlns="DAV:" xmlns:c="urn:ietf:params:xml:ns:caldav">
|
<propfind xmlns="DAV:" xmlns:c="urn:ietf:params:xml:ns:caldav">
|
||||||
<prop>
|
<prop>
|
||||||
|
|
@ -329,13 +329,13 @@ class CalDiscover(Discover):
|
||||||
</prop>
|
</prop>
|
||||||
</propfind>
|
</propfind>
|
||||||
"""
|
"""
|
||||||
_homeset_tag = "{%s}calendar-home-set" % _namespace
|
_homeset_tag = f"{{{_namespace}}}calendar-home-set"
|
||||||
_well_known_uri = "/.well-known/caldav"
|
_well_known_uri = "/.well-known/caldav"
|
||||||
|
|
||||||
|
|
||||||
class CardDiscover(Discover):
|
class CardDiscover(Discover):
|
||||||
_namespace = "urn:ietf:params:xml:ns:carddav"
|
_namespace = "urn:ietf:params:xml:ns:carddav"
|
||||||
_resourcetype: str | None = "{%s}addressbook" % _namespace
|
_resourcetype: str | None = f"{{{_namespace}}}addressbook"
|
||||||
_homeset_xml = b"""
|
_homeset_xml = b"""
|
||||||
<propfind xmlns="DAV:" xmlns:c="urn:ietf:params:xml:ns:carddav">
|
<propfind xmlns="DAV:" xmlns:c="urn:ietf:params:xml:ns:carddav">
|
||||||
<prop>
|
<prop>
|
||||||
|
|
@ -343,7 +343,7 @@ class CardDiscover(Discover):
|
||||||
</prop>
|
</prop>
|
||||||
</propfind>
|
</propfind>
|
||||||
"""
|
"""
|
||||||
_homeset_tag = "{%s}addressbook-home-set" % _namespace
|
_homeset_tag = f"{{{_namespace}}}addressbook-home-set"
|
||||||
_well_known_uri = "/.well-known/carddav"
|
_well_known_uri = "/.well-known/carddav"
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,13 +5,14 @@ import logging
|
||||||
import os
|
import os
|
||||||
import subprocess
|
import subprocess
|
||||||
|
|
||||||
from .. import exceptions
|
from vdirsyncer import exceptions
|
||||||
from ..utils import atomic_write
|
from vdirsyncer.utils import atomic_write
|
||||||
from ..utils import checkdir
|
from vdirsyncer.utils import checkdir
|
||||||
from ..utils import expand_path
|
from vdirsyncer.utils import expand_path
|
||||||
from ..utils import generate_href
|
from vdirsyncer.utils import generate_href
|
||||||
from ..utils import get_etag_from_file
|
from vdirsyncer.utils import get_etag_from_file
|
||||||
from ..vobject import Item
|
from vdirsyncer.vobject import Item
|
||||||
|
|
||||||
from .base import Storage
|
from .base import Storage
|
||||||
from .base import normalize_meta_value
|
from .base import normalize_meta_value
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -12,11 +12,12 @@ from threading import Thread
|
||||||
import aiohttp
|
import aiohttp
|
||||||
import click
|
import click
|
||||||
|
|
||||||
from .. import exceptions
|
from vdirsyncer import exceptions
|
||||||
from ..utils import atomic_write
|
from vdirsyncer.utils import atomic_write
|
||||||
from ..utils import checkdir
|
from vdirsyncer.utils import checkdir
|
||||||
from ..utils import expand_path
|
from vdirsyncer.utils import expand_path
|
||||||
from ..utils import open_graphical_browser
|
from vdirsyncer.utils import open_graphical_browser
|
||||||
|
|
||||||
from . import base
|
from . import base
|
||||||
from . import dav
|
from . import dav
|
||||||
from .google_helpers import _RedirectWSGIApp
|
from .google_helpers import _RedirectWSGIApp
|
||||||
|
|
|
||||||
|
|
@ -6,14 +6,15 @@ import urllib.parse as urlparse
|
||||||
|
|
||||||
import aiohttp
|
import aiohttp
|
||||||
|
|
||||||
from .. import exceptions
|
from vdirsyncer import exceptions
|
||||||
from ..http import USERAGENT
|
from vdirsyncer.http import USERAGENT
|
||||||
from ..http import prepare_auth
|
from vdirsyncer.http import prepare_auth
|
||||||
from ..http import prepare_client_cert
|
from vdirsyncer.http import prepare_client_cert
|
||||||
from ..http import prepare_verify
|
from vdirsyncer.http import prepare_verify
|
||||||
from ..http import request
|
from vdirsyncer.http import request
|
||||||
from ..vobject import Item
|
from vdirsyncer.vobject import Item
|
||||||
from ..vobject import split_collection
|
from vdirsyncer.vobject import split_collection
|
||||||
|
|
||||||
from .base import Storage
|
from .base import Storage
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,8 @@ from __future__ import annotations
|
||||||
|
|
||||||
import random
|
import random
|
||||||
|
|
||||||
from .. import exceptions
|
from vdirsyncer import exceptions
|
||||||
|
|
||||||
from .base import Storage
|
from .base import Storage
|
||||||
from .base import normalize_meta_value
|
from .base import normalize_meta_value
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -8,15 +8,16 @@ import logging
|
||||||
import os
|
import os
|
||||||
from typing import Iterable
|
from typing import Iterable
|
||||||
|
|
||||||
from .. import exceptions
|
from vdirsyncer import exceptions
|
||||||
from ..utils import atomic_write
|
from vdirsyncer.utils import atomic_write
|
||||||
from ..utils import checkfile
|
from vdirsyncer.utils import checkfile
|
||||||
from ..utils import expand_path
|
from vdirsyncer.utils import expand_path
|
||||||
from ..utils import get_etag_from_file
|
from vdirsyncer.utils import get_etag_from_file
|
||||||
from ..utils import uniq
|
from vdirsyncer.utils import uniq
|
||||||
from ..vobject import Item
|
from vdirsyncer.vobject import Item
|
||||||
from ..vobject import join_collection
|
from vdirsyncer.vobject import join_collection
|
||||||
from ..vobject import split_collection
|
from vdirsyncer.vobject import split_collection
|
||||||
|
|
||||||
from .base import Storage
|
from .base import Storage
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
|
||||||
|
|
@ -16,11 +16,11 @@ import contextlib
|
||||||
import itertools
|
import itertools
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
|
from vdirsyncer.exceptions import UserError
|
||||||
from vdirsyncer.storage.base import Storage
|
from vdirsyncer.storage.base import Storage
|
||||||
|
from vdirsyncer.utils import uniq
|
||||||
from vdirsyncer.vobject import Item
|
from vdirsyncer.vobject import Item
|
||||||
|
|
||||||
from ..exceptions import UserError
|
|
||||||
from ..utils import uniq
|
|
||||||
from .exceptions import BothReadOnly
|
from .exceptions import BothReadOnly
|
||||||
from .exceptions import IdentAlreadyExists
|
from .exceptions import IdentAlreadyExists
|
||||||
from .exceptions import PartialSync
|
from .exceptions import PartialSync
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from .. import exceptions
|
from vdirsyncer import exceptions
|
||||||
|
|
||||||
|
|
||||||
class SyncError(exceptions.Error):
|
class SyncError(exceptions.Error):
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue