From 533809e0e047c7bac8e2f96723e33410e0c2e7dc Mon Sep 17 00:00:00 2001 From: samschott Date: Sat, 27 Jul 2024 11:02:34 +0200 Subject: [PATCH] apply isort --- src/maestral/__init__.py | 1 - src/maestral/__main__.py | 1 - src/maestral/autostart.py | 17 +-- src/maestral/cli/cli_core.py | 25 ++-- src/maestral/cli/cli_info.py | 18 +-- src/maestral/cli/cli_main.py | 22 ++-- src/maestral/cli/cli_maintenance.py | 16 +-- src/maestral/cli/cli_settings.py | 4 +- src/maestral/cli/common.py | 8 +- src/maestral/cli/core.py | 8 +- src/maestral/cli/dialogs.py | 4 +- src/maestral/cli/output.py | 6 +- src/maestral/cli/utils.py | 2 +- src/maestral/client.py | 86 ++++++------- src/maestral/config/__init__.py | 3 +- src/maestral/config/main.py | 3 +- src/maestral/config/user.py | 9 +- src/maestral/constants.py | 8 +- src/maestral/core.py | 3 +- src/maestral/daemon.py | 36 +++--- src/maestral/database/core.py | 3 +- src/maestral/database/orm.py | 4 +- src/maestral/database/query.py | 2 +- src/maestral/database/types.py | 3 +- src/maestral/errorhandling.py | 59 +++++---- src/maestral/fsevents/__init__.py | 5 +- src/maestral/fsevents/polling.py | 14 +-- src/maestral/keyring.py | 15 +-- src/maestral/logging.py | 5 +- src/maestral/main.py | 86 ++++++------- src/maestral/manager.py | 39 +++--- src/maestral/models.py | 19 +-- src/maestral/notify.py | 10 +- src/maestral/sync.py | 149 +++++++++++------------ src/maestral/utils/__init__.py | 3 +- src/maestral/utils/appdirs.py | 1 - src/maestral/utils/hashing.py | 1 - src/maestral/utils/integration.py | 9 +- src/maestral/utils/path.py | 16 +-- tests/linked/conftest.py | 3 +- tests/linked/integration/conftest.py | 9 +- tests/linked/integration/test_main.py | 15 ++- tests/linked/integration/test_sync.py | 43 ++++--- tests/linked/lock.py | 4 +- tests/linked/unit/conftest.py | 7 +- tests/linked/unit/test_client.py | 5 +- tests/offline/config/conftest.py | 2 +- tests/offline/config/test_user.py | 4 +- tests/offline/conftest.py | 10 +- tests/offline/test_clean_local_events.py | 10 +- tests/offline/test_cli.py | 9 +- tests/offline/test_client.py | 15 ++- tests/offline/test_daemon.py | 13 +- tests/offline/test_errorhandling.py | 68 ++++++----- tests/offline/test_event_handler.py | 4 +- tests/offline/test_keyring.py | 10 +- tests/offline/test_main.py | 3 +- tests/offline/test_manager.py | 7 +- tests/offline/test_sync.py | 5 +- tests/offline/utils/test_appdirs.py | 13 +- tests/offline/utils/test_path.py | 16 +-- tests/offline/utils/test_utils.py | 1 - 62 files changed, 490 insertions(+), 509 deletions(-) diff --git a/src/maestral/__init__.py b/src/maestral/__init__.py index 89d742df..b8ec640a 100644 --- a/src/maestral/__init__.py +++ b/src/maestral/__init__.py @@ -1,6 +1,5 @@ import warnings - __version__ = "1.9.4" __author__ = "Sam Schott" __url__ = "https://maestral.app" diff --git a/src/maestral/__main__.py b/src/maestral/__main__.py index cb37ed56..ad3f9c9c 100644 --- a/src/maestral/__main__.py +++ b/src/maestral/__main__.py @@ -1,5 +1,4 @@ from .cli import main - if __name__ == "__main__": main(prog_name="maestral") diff --git a/src/maestral/autostart.py b/src/maestral/autostart.py index f817159a..8cff17b4 100644 --- a/src/maestral/autostart.py +++ b/src/maestral/autostart.py @@ -11,26 +11,29 @@ neither support pip installed packages nor multiple configurations. from __future__ import annotations +import configparser + # system imports import os import os.path as osp +import plistlib import re import shutil import stat import subprocess -import plistlib -import configparser import sys -from pathlib import Path from enum import Enum +from pathlib import Path from typing import Any -from importlib_metadata import files, PackageNotFoundError + +from importlib_metadata import PackageNotFoundError, files + +from .constants import BUNDLE_ID, ENV, FROZEN, IS_LINUX, IS_MACOS +from .exceptions import MaestralApiError # local imports -from .utils.appdirs import get_home_dir, get_conf_path, get_data_path +from .utils.appdirs import get_conf_path, get_data_path, get_home_dir from .utils.integration import cat -from .constants import BUNDLE_ID, ENV, IS_LINUX, IS_MACOS, FROZEN -from .exceptions import MaestralApiError class SupportedImplementations(Enum): diff --git a/src/maestral/cli/cli_core.py b/src/maestral/cli/cli_core.py index 9c0a2c3c..e153603f 100644 --- a/src/maestral/cli/cli_core.py +++ b/src/maestral/cli/cli_core.py @@ -7,21 +7,20 @@ from os import path as osp from typing import TYPE_CHECKING import click - from rich.console import Console, ConsoleRenderable -from .dialogs import select_path, select, confirm, prompt, select_multiple -from .output import warn, ok, info, echo, RichDateField, rich_table +from ..core import FolderMetadata, SharedLinkMetadata +from ..utils.path import delete from .common import ( - convert_api_errors, check_for_fatal_errors, config_option, + convert_api_errors, existing_config_option, inject_proxy, ) -from .core import DropboxPath, CliException -from ..core import FolderMetadata, SharedLinkMetadata -from ..utils.path import delete +from .core import CliException, DropboxPath +from .dialogs import confirm, prompt, select, select_multiple, select_path +from .output import RichDateField, echo, info, ok, rich_table, warn if TYPE_CHECKING: from ..daemon import MaestralProxy @@ -37,7 +36,7 @@ def stop_daemon_with_cli_feedback(config_name: str) -> None: """Wrapper around :meth:`daemon.stop_maestral_daemon_process` with command line feedback.""" - from ..daemon import stop_maestral_daemon_process, Stop + from ..daemon import Stop, stop_maestral_daemon_process echo("Stopping Maestral...", nl=False) res = stop_maestral_daemon_process(config_name) @@ -165,13 +164,13 @@ def link_dialog(m: MaestralProxy | Maestral) -> None: @convert_api_errors def start(foreground: bool, verbose: bool, config_name: str) -> None: from ..daemon import ( + CommunicationError, MaestralProxy, + Start, + is_running, start_maestral_daemon, start_maestral_daemon_process, wait_for_startup, - is_running, - Start, - CommunicationError, ) if is_running(config_name): @@ -262,9 +261,9 @@ def stop(config_name: str) -> None: def gui(config_name: str) -> None: import termios - from packaging.version import Version - from packaging.requirements import Requirement from importlib_metadata import entry_points, requires, version + from packaging.requirements import Requirement + from packaging.version import Version # Find all entry points for "maestral_gui" registered by other packages. gui_entry_points = entry_points(group="maestral_gui") diff --git a/src/maestral/cli/cli_info.py b/src/maestral/cli/cli_info.py index b9b6ff3c..cf8bc3a7 100644 --- a/src/maestral/cli/cli_info.py +++ b/src/maestral/cli/cli_info.py @@ -1,24 +1,24 @@ from __future__ import annotations -import sys import os +import sys import time from datetime import datetime from typing import TYPE_CHECKING, Tuple import click +from rich.columns import Columns from rich.console import Console, ConsoleRenderable +from rich.filesize import decimal +from rich.progress import BarColumn, DownloadColumn, Progress, TaskID, TextColumn from rich.table import Column from rich.text import Text -from rich.columns import Columns -from rich.filesize import decimal -from rich.progress import Progress, TextColumn, BarColumn, DownloadColumn, TaskID -from .output import echo, RichDateField, rich_table -from .common import convert_api_errors, check_for_fatal_errors, inject_proxy -from .core import DropboxPath +from ..core import DeletedMetadata, FileMetadata, FolderMetadata from ..models import SyncDirection, SyncEvent, SyncStatus -from ..core import FileMetadata, FolderMetadata, DeletedMetadata +from .common import check_for_fatal_errors, convert_api_errors, inject_proxy +from .core import DropboxPath +from .output import RichDateField, echo, rich_table if TYPE_CHECKING: from ..main import Maestral @@ -283,13 +283,13 @@ def ls(m: Maestral, long: bool, dropbox_path: str, include_deleted: bool) -> Non help="Remove config files without a linked account.", ) def config_files(clean: bool) -> None: - from ..daemon import is_running from ..config import ( MaestralConfig, MaestralState, list_configs, remove_configuration, ) + from ..daemon import is_running if clean: # Clean up stale config files. diff --git a/src/maestral/cli/cli_main.py b/src/maestral/cli/cli_main.py index e7ac4535..fe9dc8f2 100755 --- a/src/maestral/cli/cli_main.py +++ b/src/maestral/cli/cli_main.py @@ -1,23 +1,23 @@ # external imports import click -# local imports -from .core import OrderedGroup -from .cli_core import start, stop, gui, pause, resume, auth, sharelink -from .cli_info import status, filestatus, activity, history, ls, config_files -from .cli_settings import autostart, excluded, notify, bandwidth_limit +from .. import __version__ +from .cli_core import auth, gui, pause, resume, sharelink, start, stop +from .cli_info import activity, config_files, filestatus, history, ls, status from .cli_maintenance import ( + completion, + config, + diff, + log, move_dir, rebuild_index, - revs, - diff, restore, - log, - config, - completion, + revs, ) +from .cli_settings import autostart, bandwidth_limit, excluded, notify -from .. import __version__ +# local imports +from .core import OrderedGroup @click.group(cls=OrderedGroup, help="Dropbox client for Linux and macOS.") diff --git a/src/maestral/cli/cli_maintenance.py b/src/maestral/cli/cli_maintenance.py index a5f0a933..2cc73082 100644 --- a/src/maestral/cli/cli_maintenance.py +++ b/src/maestral/cli/cli_maintenance.py @@ -1,12 +1,12 @@ from __future__ import annotations -import os -import io import ast +import io import logging +import os import textwrap from os import path as osp -from typing import cast, TYPE_CHECKING +from typing import TYPE_CHECKING, cast import click from click.shell_completion import get_completion_class @@ -14,11 +14,11 @@ from rich.console import Console from rich.text import Text from .cli_core import select_dbx_path_dialog -from .dialogs import confirm, select -from .output import ok, warn, echo, echo_via_pager, RichDateField, rich_table -from .utils import get_term_size from .common import convert_api_errors, existing_config_option, inject_proxy -from .core import DropboxPath, ConfigKey, CliException +from .core import CliException, ConfigKey, DropboxPath +from .dialogs import confirm, select +from .output import RichDateField, echo, echo_via_pager, ok, rich_table, warn +from .utils import get_term_size if TYPE_CHECKING: from ..main import Maestral @@ -404,7 +404,7 @@ instance, setting a boolean config value to 1 will actually set it to True. @inject_proxy(fallback=True, existing_config=True) @convert_api_errors def config_set(m: Maestral, key: str, value: str) -> None: - from ..config.main import KEY_SECTION_MAP, DEFAULTS_CONFIG + from ..config.main import DEFAULTS_CONFIG, KEY_SECTION_MAP section = KEY_SECTION_MAP.get(key, "") diff --git a/src/maestral/cli/cli_settings.py b/src/maestral/cli/cli_settings.py index 0ffe55f4..58c10117 100644 --- a/src/maestral/cli/cli_settings.py +++ b/src/maestral/cli/cli_settings.py @@ -4,9 +4,9 @@ from typing import TYPE_CHECKING import click -from .output import echo, ok from .common import convert_api_errors, existing_config_option, inject_proxy -from .core import DropboxPath, CliException +from .core import CliException, DropboxPath +from .output import echo, ok if TYPE_CHECKING: from ..main import Maestral diff --git a/src/maestral/cli/common.py b/src/maestral/cli/common.py index 2cc2a908..0d89f424 100644 --- a/src/maestral/cli/common.py +++ b/src/maestral/cli/common.py @@ -2,15 +2,15 @@ from __future__ import annotations import functools import sys -from typing import Callable, Any, TypeVar, TYPE_CHECKING -from typing_extensions import ParamSpec +from typing import TYPE_CHECKING, Any, Callable, TypeVar import click +from typing_extensions import ParamSpec +from ..constants import DEFAULT_CONFIG_NAME from .core import ConfigName from .output import warn from .utils import get_term_size -from ..constants import DEFAULT_CONFIG_NAME if TYPE_CHECKING: from ..daemon import MaestralProxy @@ -94,7 +94,7 @@ def inject_proxy( ) -> Callable[[Callable[P, T]], Callable[P, Any]]: def decorator(f: Callable[P, T]) -> Callable[P, Any]: def wrapper(*args: P.args, **kwargs: P.kwargs) -> Any: - from ..daemon import MaestralProxy, CommunicationError + from ..daemon import CommunicationError, MaestralProxy ctx = click.get_current_context() diff --git a/src/maestral/cli/core.py b/src/maestral/cli/core.py index 35f738cf..fe0bbb9a 100644 --- a/src/maestral/cli/core.py +++ b/src/maestral/cli/core.py @@ -15,7 +15,6 @@ from click.shell_completion import CompletionItem from .output import warn - # ==== Custom parameter types ========================================================== # A custom parameter: @@ -63,8 +62,9 @@ class DropboxPath(click.ParamType): incomplete: str, ) -> list[CompletionItem]: from click.shell_completion import CompletionItem - from ..utils import removeprefix + from ..config import MaestralConfig + from ..utils import removeprefix matches: list[str] = [] completions: list[CompletionItem] = [] @@ -126,6 +126,7 @@ class ConfigKey(click.ParamType): incomplete: str, ) -> list[CompletionItem]: from click.shell_completion import CompletionItem + from ..config.main import KEY_SECTION_MAP as KEYS return [CompletionItem(key) for key in KEYS if key.startswith(incomplete)] @@ -154,7 +155,7 @@ class ConfigName(click.ParamType): if value is None: return value - from ..config import validate_config_name, list_configs + from ..config import list_configs, validate_config_name if not self.existing: # accept all valid config names @@ -180,6 +181,7 @@ class ConfigName(click.ParamType): incomplete: str, ) -> list[CompletionItem]: from click.shell_completion import CompletionItem + from ..config import list_configs matches = [conf for conf in list_configs() if conf.startswith(incomplete)] diff --git a/src/maestral/cli/dialogs.py b/src/maestral/cli/dialogs.py index ad367569..0120b0ed 100644 --- a/src/maestral/cli/dialogs.py +++ b/src/maestral/cli/dialogs.py @@ -5,11 +5,11 @@ This module provides interactive commandline dialogs which are based on the from __future__ import annotations -import os import functools +import os from typing import Callable, Sequence, TypeVar -from typing_extensions import ParamSpec +from typing_extensions import ParamSpec P = ParamSpec("P") T = TypeVar("T") diff --git a/src/maestral/cli/output.py b/src/maestral/cli/output.py index 26b97be4..9a0c43f9 100644 --- a/src/maestral/cli/output.py +++ b/src/maestral/cli/output.py @@ -7,14 +7,14 @@ from __future__ import annotations import enum from datetime import datetime -from typing import Iterable, Callable +from typing import Callable, Iterable import click from rich.console import Console, ConsoleOptions, RenderResult from rich.measure import Measurement -from rich.text import Text from rich.style import Style -from rich.table import Table, Column +from rich.table import Column, Table +from rich.text import Text TABLE_STYLE = dict(padding=(0, 2, 0, 0), box=None) diff --git a/src/maestral/cli/utils.py b/src/maestral/cli/utils.py index 5d14535b..2c7394ce 100644 --- a/src/maestral/cli/utils.py +++ b/src/maestral/cli/utils.py @@ -4,9 +4,9 @@ Module to print neatly formatted tables and grids to the terminal. from __future__ import annotations -import sys import os import shutil +import sys def get_term_size() -> os.terminal_size: diff --git a/src/maestral/client.py b/src/maestral/client.py index 8d0957a2..d361db68 100644 --- a/src/maestral/client.py +++ b/src/maestral/client.py @@ -5,84 +5,84 @@ and handles exceptions, chunked uploads or downloads, etc. from __future__ import annotations +import functools + # system imports import os import re import time -import functools -from contextlib import contextmanager, closing +from contextlib import closing, contextmanager from datetime import datetime, timezone from typing import ( + TYPE_CHECKING, + Any, + BinaryIO, Callable, Iterator, Sequence, TypeVar, - Any, - BinaryIO, - overload, cast, - TYPE_CHECKING, + overload, ) -from typing_extensions import ParamSpec, Concatenate # external imports import requests -from dropbox import files, sharing, users, common -from dropbox import Dropbox, create_session, exceptions +from dropbox import Dropbox, common, create_session, exceptions, files, sharing, users +from dropbox.dropbox_client import ( + USER_AUTH, + BadInputException, + RouteErrorResult, + RouteResult, +) from dropbox.oauth import DropboxOAuth2FlowNoRedirect from dropbox.session import API_HOST -from dropbox.dropbox_client import ( - BadInputException, - RouteResult, - RouteErrorResult, - USER_AUTH, -) +from typing_extensions import Concatenate, ParamSpec # local imports from . import __version__ -from .keyring import CredentialStorage -from .logging import scoped_logger +from .config import MaestralState +from .constants import DROPBOX_APP_KEY from .core import ( - AccountType, - Team, Account, - RootInfo, - UserRootInfo, - TeamRootInfo, - FullAccount, - SpaceUsage, - PersonalSpaceUsage, - WriteMode, - Metadata, + AccountType, DeletedMetadata, FileMetadata, FolderMetadata, - ListFolderResult, + FullAccount, LinkAccessLevel, LinkAudience, LinkPermissions, - SharedLinkMetadata, + ListFolderResult, ListSharedLinkResult, -) -from .exceptions import ( - MaestralApiError, - SyncError, - PathError, - NotFoundError, - NotLinkedError, - DataCorruptionError, - DataChangedError, + Metadata, + PersonalSpaceUsage, + RootInfo, + SharedLinkMetadata, + SpaceUsage, + Team, + TeamRootInfo, + UserRootInfo, + WriteMode, ) from .errorhandling import ( + CONNECTION_ERRORS, convert_api_errors, dropbox_to_maestral_error, - CONNECTION_ERRORS, ) -from .config import MaestralState -from .constants import DROPBOX_APP_KEY -from .utils import natural_size, chunks, clamp -from .utils.path import opener_no_symlink, delete +from .exceptions import ( + DataChangedError, + DataCorruptionError, + MaestralApiError, + NotFoundError, + NotLinkedError, + PathError, + SyncError, +) +from .keyring import CredentialStorage +from .logging import scoped_logger +from .utils import chunks, clamp, natural_size from .utils.hashing import DropboxContentHasher, StreamHasher +from .utils.path import delete, opener_no_symlink if TYPE_CHECKING: from .models import SyncEvent diff --git a/src/maestral/config/__init__.py b/src/maestral/config/__init__.py index e4ab4b02..743a1d51 100644 --- a/src/maestral/config/__init__.py +++ b/src/maestral/config/__init__.py @@ -1,10 +1,9 @@ import os from typing import List, TypeVar +from ..utils.appdirs import get_conf_path, get_data_path from .main import MaestralConfig, MaestralState from .user import PersistentMutableSet -from ..utils.appdirs import get_conf_path, get_data_path - __all__ = [ "MaestralConfig", diff --git a/src/maestral/config/main.py b/src/maestral/config/main.py index a32fe06a..3ad0f6cf 100644 --- a/src/maestral/config/main.py +++ b/src/maestral/config/main.py @@ -9,10 +9,9 @@ import threading from packaging.version import Version -from .user import UserConfig, _DefaultsType from .. import __version__ from ..utils.appdirs import get_conf_path, get_data_path - +from .user import UserConfig, _DefaultsType CONFIG_DIR_NAME = "maestral" diff --git a/src/maestral/config/user.py b/src/maestral/config/user.py index ea88f73b..4ca005de 100644 --- a/src/maestral/config/user.py +++ b/src/maestral/config/user.py @@ -11,18 +11,17 @@ config module of the Spyder IDE. from __future__ import annotations import ast +import configparser as cp +import copy +import logging import os import os.path as osp import shutil -import copy -import logging -import configparser as cp from threading import RLock -from typing import Iterator, Any, Dict, TypeVar, MutableSet +from typing import Any, Dict, Iterator, MutableSet, TypeVar from packaging.version import Version - logger = logging.getLogger(__name__) _DefaultsType = Dict[str, Dict[str, Any]] diff --git a/src/maestral/constants.py b/src/maestral/constants.py index e800f19d..b5aa8c1f 100644 --- a/src/maestral/constants.py +++ b/src/maestral/constants.py @@ -3,14 +3,16 @@ This module provides constants used throughout the maestral, the GUI and CLI. It be kept free of memory heavy imports. """ +import pathlib +import platform + # system imports import sys -import platform -import pathlib from enum import Enum -from importlib_metadata import metadata, PackageNotFoundError from typing import ContextManager +from importlib_metadata import PackageNotFoundError, metadata + try: # For Python 3.9 and later. from importlib.resources import as_file, files # type: ignore diff --git a/src/maestral/core.py b/src/maestral/core.py index 0ae2f6f4..261fb00b 100644 --- a/src/maestral/core.py +++ b/src/maestral/core.py @@ -4,10 +4,9 @@ Dataclasses for our internal and external APIs. from __future__ import annotations -from enum import Enum from dataclasses import dataclass from datetime import datetime - +from enum import Enum # ==== user ============================================================================ diff --git a/src/maestral/daemon.py b/src/maestral/daemon.py index 65ba37b2..3f2db62b 100644 --- a/src/maestral/daemon.py +++ b/src/maestral/daemon.py @@ -5,44 +5,45 @@ objects for a running daemon. from __future__ import annotations +import argparse +import enum +import fcntl + # system imports import inspect -import sys import os -import time -import signal -import enum -import threading -import fcntl -import struct -import argparse -import re import pickle +import re +import signal +import struct +import sys +import threading +import time from pprint import pformat from shlex import quote -from typing import Any, Iterable, ContextManager, TYPE_CHECKING from types import TracebackType +from typing import TYPE_CHECKING, Any, ContextManager, Iterable # external imports import Pyro5 -from Pyro5.errors import CommunicationError +from fasteners import InterProcessLock from Pyro5.api import ( Daemon, Proxy, expose, - register_dict_to_class, register_class_to_dict, + register_dict_to_class, ) +from Pyro5.errors import CommunicationError from Pyro5.serializers import serpent -from fasteners import InterProcessLock + +from . import core, exceptions, models +from .constants import ENV, IS_MACOS # local imports from .utils import exc_info_tuple from .utils.appdirs import get_runtime_path from .utils.integration import SystemdNotifier -from .constants import IS_MACOS, ENV -from . import core, models, exceptions - if TYPE_CHECKING: from .main import Maestral @@ -375,8 +376,9 @@ def start_maestral_daemon( """ import asyncio - from .main import Maestral + from .logging import scoped_logger, setup_logging + from .main import Maestral setup_logging(config_name, stderr=log_to_stderr) dlogger = scoped_logger(__name__, config_name) diff --git a/src/maestral/database/core.py b/src/maestral/database/core.py index aaa93ef3..3c3fad90 100644 --- a/src/maestral/database/core.py +++ b/src/maestral/database/core.py @@ -4,9 +4,8 @@ This model defines our core SQLite database interface. from __future__ import annotations -from typing import Any - import sqlite3 +from typing import Any class Database: diff --git a/src/maestral/database/orm.py b/src/maestral/database/orm.py index 40fc830d..681ce673 100644 --- a/src/maestral/database/orm.py +++ b/src/maestral/database/orm.py @@ -9,12 +9,12 @@ memory is constrained. from __future__ import annotations +from typing import Any, Generator, Generic, Optional, TypeVar, Union, cast, overload from weakref import WeakValueDictionary -from typing import Any, Generator, TypeVar, Generic, Union, Optional, cast, overload from .core import Database from .query import Query -from .types import SqlType, SqlEnum +from .types import SqlEnum, SqlType SQLSafeType = Union[str, int, float, None] T = TypeVar("T") diff --git a/src/maestral/database/query.py b/src/maestral/database/query.py index fa1404fd..c4ec92fd 100644 --- a/src/maestral/database/query.py +++ b/src/maestral/database/query.py @@ -6,7 +6,7 @@ queries. from __future__ import annotations import os -from typing import Sequence, Iterator, Any, TYPE_CHECKING +from typing import TYPE_CHECKING, Any, Iterator, Sequence from .types import SqlPath diff --git a/src/maestral/database/types.py b/src/maestral/database/types.py index 25f4acd7..1736a124 100644 --- a/src/maestral/database/types.py +++ b/src/maestral/database/types.py @@ -6,8 +6,7 @@ from __future__ import annotations import os from enum import Enum -from typing import Iterable, TypeVar, Generic, cast - +from typing import Generic, Iterable, TypeVar, cast T = TypeVar("T") ST = TypeVar("ST") diff --git a/src/maestral/errorhandling.py b/src/maestral/errorhandling.py index d8d49d57..89d984fa 100644 --- a/src/maestral/errorhandling.py +++ b/src/maestral/errorhandling.py @@ -5,52 +5,51 @@ exceptions to instances of :exc:`maestral.exceptions.MaestralApiError`. from __future__ import annotations +import contextlib +import errno + # system imports import os -import errno -import contextlib -from typing import Iterator, Union, TypeVar, Callable, Any +from typing import Any, Callable, Iterator, TypeVar, Union # external imports import requests -from dropbox import files, sharing, users, async_, auth, common -from dropbox import exceptions +from dropbox import async_, auth, common, exceptions, files, sharing, users from dropbox.stone_validators import ValidationError # local imports from .exceptions import ( - MaestralApiError, - SyncError, - InsufficientPermissionsError, - PathError, - FileReadError, - InsufficientSpaceError, - FileConflictError, - FolderConflictError, - ConflictError, - UnsupportedFileError, - RestrictedContentError, - NotFoundError, - NotAFolderError, - IsAFolderError, - FileSizeError, - SymlinkError, - OutOfMemoryError, BadInputError, + ConflictError, + CursorResetError, + DataCorruptionError, DropboxAuthError, + DropboxConnectionError, + DropboxServerError, + FileConflictError, + FileReadError, + FileSizeError, + FolderConflictError, + InsufficientPermissionsError, + InsufficientSpaceError, + InvalidDbidError, + IsAFolderError, + MaestralApiError, + NotAFolderError, + NotFoundError, + OutOfMemoryError, + PathError, + PathRootError, + RestrictedContentError, + SharedLinkError, + SymlinkError, + SyncError, TokenExpiredError, TokenRevokedError, - CursorResetError, - DropboxServerError, - InvalidDbidError, - SharedLinkError, - DropboxConnectionError, - PathRootError, - DataCorruptionError, + UnsupportedFileError, ) from .utils.path import fs_max_lengths_for_path - __all__ = [ "CONNECTION_ERRORS", "dropbox_to_maestral_error", diff --git a/src/maestral/fsevents/__init__.py b/src/maestral/fsevents/__init__.py index 34a9b529..0e7b078e 100644 --- a/src/maestral/fsevents/__init__.py +++ b/src/maestral/fsevents/__init__.py @@ -9,13 +9,14 @@ events. from __future__ import annotations -from typing import Type, Union, TYPE_CHECKING +from typing import TYPE_CHECKING, Type, Union from watchdog.utils import platform if TYPE_CHECKING: - from watchdog.observers.inotify import InotifyObserver from watchdog.observers.fsevents import FSEventsObserver + from watchdog.observers.inotify import InotifyObserver + from .polling import OrderedPollingObserver diff --git a/src/maestral/fsevents/polling.py b/src/maestral/fsevents/polling.py index 01cfedbe..107861d4 100644 --- a/src/maestral/fsevents/polling.py +++ b/src/maestral/fsevents/polling.py @@ -59,18 +59,18 @@ into Deleted and Created events by Maestral. # See the License for the specific language governing permissions and # limitations under the License. -from watchdog.observers.polling import PollingEmitter, PollingObserver from watchdog.events import ( - FileDeletedEvent, - FileModifiedEvent, - FileMovedEvent, - FileCreatedEvent, + DirCreatedEvent, DirDeletedEvent, DirModifiedEvent, DirMovedEvent, - DirCreatedEvent, + FileCreatedEvent, + FileDeletedEvent, + FileModifiedEvent, + FileMovedEvent, ) -from watchdog.observers.api import BaseObserver, DEFAULT_OBSERVER_TIMEOUT +from watchdog.observers.api import DEFAULT_OBSERVER_TIMEOUT, BaseObserver +from watchdog.observers.polling import PollingEmitter, PollingObserver from watchdog.utils.dirsnapshot import DirectorySnapshot, DirectorySnapshotDiff diff --git a/src/maestral/keyring.py b/src/maestral/keyring.py index 0c6573d2..39e36c31 100644 --- a/src/maestral/keyring.py +++ b/src/maestral/keyring.py @@ -7,24 +7,25 @@ from __future__ import annotations # system imports from threading import RLock -# external imports -import requests import keyring.backends +import keyring.backends.kwallet import keyring.backends.macOS import keyring.backends.SecretService import keyrings.alt.file -import keyring.backends.kwallet + +# external imports +import requests from keyring.backend import KeyringBackend from keyring.core import load_keyring -from keyring.errors import KeyringLocked, PasswordDeleteError, InitError +from keyring.errors import InitError, KeyringLocked, PasswordDeleteError + +from .cli import output # local imports from .config import MaestralConfig from .exceptions import KeyringAccessError -from .cli import output -from .utils import exc_info_tuple from .logging import scoped_logger - +from .utils import exc_info_tuple __all__ = ["CredentialStorage"] diff --git a/src/maestral/logging.py b/src/maestral/logging.py index 1beab9fa..b43da4e3 100644 --- a/src/maestral/logging.py +++ b/src/maestral/logging.py @@ -2,13 +2,13 @@ from __future__ import annotations -import os import concurrent.futures import logging +import os import time -from logging.handlers import RotatingFileHandler from collections import deque from concurrent.futures import Future, InvalidStateError +from logging.handlers import RotatingFileHandler from typing import Sequence from .config import MaestralConfig @@ -16,7 +16,6 @@ from .utils import sanitize_string from .utils.appdirs import get_log_path from .utils.integration import SystemdNotifier - __all__ = [ "AwaitableHandler", "CachedHandler", diff --git a/src/maestral/main.py b/src/maestral/main.py index f1abe71c..eef6ca0d 100644 --- a/src/maestral/main.py +++ b/src/maestral/main.py @@ -2,27 +2,28 @@ from __future__ import annotations +import asyncio +import difflib +import gc +import logging +import mimetypes + # system imports import os import os.path as osp +import random import shutil import sqlite3 -import time -import asyncio -import random -import gc import tempfile -import mimetypes -import difflib -import logging +import time from asyncio import AbstractEventLoop, Future -from typing import Iterator, Any, Sequence, Collection +from datetime import datetime, timezone +from typing import Any, Collection, Iterator, Sequence # external imports import requests -from watchdog.events import DirDeletedEvent, FileDeletedEvent from packaging.version import Version -from datetime import datetime, timezone +from watchdog.events import DirDeletedEvent, FileDeletedEvent try: from systemd import journal @@ -32,62 +33,61 @@ except ImportError: # local imports from . import __version__ from .client import DropboxClient -from .keyring import CredentialStorage +from .config import MaestralConfig, MaestralState, validate_config_name +from .constants import ( + CONNECTING, + DEFAULT_CONFIG_NAME, + GITHUB_RELEASES_API, + IDLE, + IS_LINUX, + IS_MACOS, + PAUSED, + FileStatus, +) from .core import ( - SharedLinkMetadata, - FullAccount, - PersonalSpaceUsage, - Metadata, FileMetadata, - LinkAudience, + FullAccount, LinkAccessLevel, + LinkAudience, + Metadata, + PersonalSpaceUsage, + SharedLinkMetadata, UpdateCheckResult, ) -from .sync import SyncDirection, SyncEngine, pf_repr -from .manager import SyncManager -from .models import SyncEvent, SyncErrorEntry, SyncStatus -from .notify import MaestralDesktopNotifier +from .database.core import Database +from .errorhandling import CONNECTION_ERRORS, convert_api_errors from .exceptions import ( - MaestralApiError, - NotLinkedError, - NoDropboxDirError, - NotFoundError, BusyError, KeyringAccessError, + MaestralApiError, + NoDropboxDirError, + NotFoundError, + NotLinkedError, UnsupportedFileTypeForDiff, UpdateCheckError, ) -from .errorhandling import convert_api_errors, CONNECTION_ERRORS -from .config import MaestralConfig, MaestralState, validate_config_name +from .keyring import CredentialStorage from .logging import ( + LOG_FMT_SHORT, AwaitableHandler, CachedHandler, scoped_logger, setup_logging, - LOG_FMT_SHORT, ) +from .manager import SyncManager +from .models import SyncErrorEntry, SyncEvent, SyncStatus +from .notify import MaestralDesktopNotifier +from .sync import SyncDirection, SyncEngine, pf_repr from .utils import get_newer_version +from .utils.appdirs import get_cache_path, get_data_path from .utils.path import ( - isdir, + delete, is_child, is_equal_or_child, - to_existing_unnormalized_path, + isdir, normalize, - delete, + to_existing_unnormalized_path, ) -from .utils.appdirs import get_cache_path, get_data_path -from .database.core import Database -from .constants import ( - IS_LINUX, - IS_MACOS, - IDLE, - PAUSED, - CONNECTING, - DEFAULT_CONFIG_NAME, - GITHUB_RELEASES_API, - FileStatus, -) - __all__ = ["Maestral"] diff --git a/src/maestral/manager.py b/src/maestral/manager.py index 90537970..2ae76956 100644 --- a/src/maestral/manager.py +++ b/src/maestral/manager.py @@ -2,52 +2,45 @@ from __future__ import annotations +import ctypes +import errno +import gc + # system imports import os -import errno import time -import gc -import ctypes from contextlib import contextmanager from functools import wraps from queue import Empty, Queue -from threading import Event, RLock, Thread from tempfile import TemporaryDirectory -from typing import Iterator, TypeVar, Callable, Generic, Any -from typing_extensions import ParamSpec, Concatenate +from threading import Event, RLock, Thread +from typing import Any, Callable, Generic, Iterator, TypeVar + +from typing_extensions import Concatenate, ParamSpec # local imports -from . import __url__ -from . import notify +from . import __url__, notify from .client import API_HOST -from .core import TeamRootInfo, UserRootInfo -from .fsevents import Observer, ObserverType from .config import MaestralConfig, MaestralState, PersistentMutableSet from .config.user import UserConfig -from .constants import ( - DISCONNECTED, - CONNECTING, - SYNCING, - IDLE, - PAUSED, - CONNECTED, -) +from .constants import CONNECTED, CONNECTING, DISCONNECTED, IDLE, PAUSED, SYNCING +from .core import TeamRootInfo, UserRootInfo from .exceptions import ( CancelledError, DropboxConnectionError, - MaestralApiError, + DropboxServerError, InotifyError, + MaestralApiError, NoDropboxDirError, PathRootError, - DropboxServerError, ) -from .sync import SyncEngine +from .fsevents import Observer, ObserverType from .logging import scoped_logger from .notify import MaestralDesktopNotifier +from .sync import SyncEngine from .utils import removeprefix from .utils.integration import check_connection, get_inotify_limits -from .utils.path import move, delete, is_equal_or_child, is_child, normalize - +from .utils.path import delete, is_child, is_equal_or_child, move, normalize __all__ = ["SyncManager"] diff --git a/src/maestral/models.py b/src/maestral/models.py index a4602eaa..04650214 100644 --- a/src/maestral/models.py +++ b/src/maestral/models.py @@ -7,29 +7,30 @@ Class instances then represent table rows. from __future__ import annotations +import enum + # system imports import os import time -import enum from typing import TYPE_CHECKING # external imports from watchdog.events import ( - FileSystemEvent, - FileMovedEvent, - DirMovedEvent, EVENT_TYPE_CREATED, EVENT_TYPE_DELETED, - EVENT_TYPE_MOVED, EVENT_TYPE_MODIFIED, + EVENT_TYPE_MOVED, + DirMovedEvent, + FileMovedEvent, + FileSystemEvent, ) # local imports -from .core import Metadata, DeletedMetadata, FileMetadata, FolderMetadata -from .database.orm import Model, Column, NonNullColumn -from .database.types import SqlInt, SqlLargeInt, SqlFloat, SqlString, SqlPath, SqlEnum +from .core import DeletedMetadata, FileMetadata, FolderMetadata, Metadata +from .database.orm import Column, Model, NonNullColumn +from .database.types import SqlEnum, SqlFloat, SqlInt, SqlLargeInt, SqlPath, SqlString +from .exceptions import NotLinkedError, SyncError from .utils.path import normalize -from .exceptions import SyncError, NotLinkedError if TYPE_CHECKING: from .sync import SyncEngine diff --git a/src/maestral/notify.py b/src/maestral/notify.py index 55f93e79..fe9123a6 100644 --- a/src/maestral/notify.py +++ b/src/maestral/notify.py @@ -6,20 +6,20 @@ backend for cross-platform desktop notifications. from __future__ import annotations +import asyncio + # system imports import logging import time -import asyncio from asyncio import AbstractEventLoop -from typing import Callable, Any, cast +from typing import Any, Callable, cast # external imports -from desktop_notifier import DesktopNotifier, Urgency, Button +from desktop_notifier import Button, DesktopNotifier, Urgency # local imports from .config import MaestralConfig -from .constants import APP_NAME, APP_ICON_PATH - +from .constants import APP_ICON_PATH, APP_NAME __all__ = [ "NONE", diff --git a/src/maestral/sync.py b/src/maestral/sync.py index 5fe97746..771ec25b 100644 --- a/src/maestral/sync.py +++ b/src/maestral/sync.py @@ -2,144 +2,137 @@ from __future__ import annotations +import enum + # system imports import errno -import sys +import gc import os import os.path as osp +import random +import sqlite3 +import sys import threading import time -import random import urllib.parse -import enum -import sqlite3 -import gc -from stat import S_ISDIR -from pprint import pformat -from threading import Event, Condition, RLock, current_thread -from concurrent.futures import ThreadPoolExecutor, as_completed -from queue import Queue, Empty from collections import defaultdict +from concurrent.futures import ThreadPoolExecutor, as_completed from contextlib import contextmanager -from tempfile import NamedTemporaryFile from datetime import datetime +from pprint import pformat +from queue import Empty, Queue +from stat import S_ISDIR +from tempfile import NamedTemporaryFile +from threading import Condition, Event, RLock, current_thread from typing import ( Any, - Iterator, - Iterable, - Collection, - Sequence, Callable, + Collection, + Iterable, + Iterator, + Sequence, Type, TypeVar, cast, overload, ) -from typing_extensions import ParamSpec, TypeGuard # external imports import click from pathspec import PathSpec -from watchdog.events import FileSystemEventHandler +from typing_extensions import ParamSpec, TypeGuard from watchdog.events import ( EVENT_TYPE_CREATED, EVENT_TYPE_DELETED, - EVENT_TYPE_MOVED, EVENT_TYPE_MODIFIED, -) -from watchdog.events import ( - DirModifiedEvent, - FileModifiedEvent, + EVENT_TYPE_MOVED, DirCreatedEvent, - FileCreatedEvent, DirDeletedEvent, - FileDeletedEvent, + DirModifiedEvent, DirMovedEvent, + FileCreatedEvent, + FileDeletedEvent, + FileModifiedEvent, FileMovedEvent, FileSystemEvent, + FileSystemEventHandler, FileSystemMovedEvent, ) # local imports from . import notify +from .client import DropboxClient from .config import MaestralConfig, MaestralState +from .constants import ( + EXCLUDED_DIR_NAMES, + EXCLUDED_FILE_NAMES, + FILE_CACHE, + IDLE, + MIGNORE_FILE, +) from .core import ( - Metadata, + DeletedMetadata, FileMetadata, FolderMetadata, - DeletedMetadata, - WriteMode, ListFolderResult, + Metadata, + WriteMode, ) -from .constants import ( - IDLE, - EXCLUDED_FILE_NAMES, - EXCLUDED_DIR_NAMES, - MIGNORE_FILE, - FILE_CACHE, -) +from .database.core import Database +from .database.orm import Manager +from .database.query import AllQuery, AndQuery, MatchQuery, PathTreeQuery, Query +from .errorhandling import convert_api_errors, os_to_maestral_error from .exceptions import ( - SyncError, - CancelledError, - NoDropboxDirError, CacheDirError, - PathError, - NotFoundError, + CancelledError, + DatabaseError, + DataChangedError, FileConflictError, FolderConflictError, - IsAFolderError, - NotAFolderError, - DataChangedError, InvalidDbidError, - DatabaseError, -) -from .errorhandling import os_to_maestral_error, convert_api_errors -from .client import ( - DropboxClient, -) -from .models import ( - SyncEvent, - HashCacheEntry, - IndexEntry, - SyncErrorEntry, - SyncDirection, - SyncStatus, - ItemType, - ChangeType, + IsAFolderError, + NoDropboxDirError, + NotAFolderError, + NotFoundError, + PathError, + SyncError, ) from .logging import scoped_logger -from .utils import removeprefix, sanitize_string, exc_info_tuple -from .utils.caches import LRUCache -from .utils.integration import ( - cpu_usage_percent, - CPU_CORE_COUNT, +from .models import ( + ChangeType, + HashCacheEntry, + IndexEntry, + ItemType, + SyncDirection, + SyncErrorEntry, + SyncEvent, + SyncStatus, ) +from .utils import exc_info_tuple, removeprefix, sanitize_string +from .utils.appdirs import get_data_path +from .utils.caches import LRUCache +from .utils.integration import CPU_CORE_COUNT, cpu_usage_percent from .utils.path import ( - exists, - isfile, - isdir, - getsize, - generate_cc_name, - move, + content_hash, delete, + equal_but_for_unicode_norm, + exists, + generate_cc_name, + get_existing_equivalent_paths, + get_symlink_target, + getsize, is_child, is_equal_or_child, is_fs_case_sensitive, - content_hash, - walk, + isdir, + isfile, + move, normalize, normalize_case, normalize_unicode, - equal_but_for_unicode_norm, - get_existing_equivalent_paths, to_existing_unnormalized_path, - get_symlink_target, + walk, ) -from .database.orm import Manager -from .database.core import Database -from .database.query import PathTreeQuery, MatchQuery, AllQuery, AndQuery, Query -from .utils.appdirs import get_data_path - __all__ = [ "Conflict", diff --git a/src/maestral/utils/__init__.py b/src/maestral/utils/__init__.py index 6b0d883a..fcfcdcad 100644 --- a/src/maestral/utils/__init__.py +++ b/src/maestral/utils/__init__.py @@ -4,13 +4,12 @@ from __future__ import annotations import os from types import TracebackType -from typing import Iterator, TypeVar, Optional, Iterable, Tuple, Type +from typing import Iterable, Iterator, Optional, Tuple, Type, TypeVar from packaging.version import Version from .path import normalize - _N = TypeVar("_N", float, int) _T = TypeVar("_T") _ExecInfoType = Tuple[Type[BaseException], BaseException, Optional[TracebackType]] diff --git a/src/maestral/utils/appdirs.py b/src/maestral/utils/appdirs.py index 64fdd153..e6188a2d 100644 --- a/src/maestral/utils/appdirs.py +++ b/src/maestral/utils/appdirs.py @@ -9,7 +9,6 @@ import platform from os import path as osp from typing import Optional - __all__ = [ "get_log_path", "get_cache_path", diff --git a/src/maestral/utils/hashing.py b/src/maestral/utils/hashing.py index 0ae9965f..4f9144ff 100644 --- a/src/maestral/utils/hashing.py +++ b/src/maestral/utils/hashing.py @@ -4,7 +4,6 @@ from __future__ import annotations # system imports import hashlib - from typing import BinaryIO, Union _WritableBuffer = Union[bytes, bytearray] diff --git a/src/maestral/utils/integration.py b/src/maestral/utils/integration.py index 3fcba470..33bac496 100644 --- a/src/maestral/utils/integration.py +++ b/src/maestral/utils/integration.py @@ -5,16 +5,17 @@ could also be achieved with psutils, but we want to avoid the large dependency. from __future__ import annotations +import logging import os import resource -import requests -import time -import logging import socket +import time from pathlib import Path -from typing import Union, Tuple, Optional +from typing import Optional, Tuple, Union from urllib.parse import urlparse +import requests + __all__ = [ "cat", "get_inotify_limits", diff --git a/src/maestral/utils/path.py b/src/maestral/utils/path.py index 819a4c91..70cfbeb9 100644 --- a/src/maestral/utils/path.py +++ b/src/maestral/utils/path.py @@ -2,24 +2,26 @@ This module contains functions for common path operations. """ +import errno +import fcntl +import itertools + # system imports import os import os.path as osp -import errno -import shutil -import itertools -import unicodedata -import fcntl import platform +import shutil +import unicodedata from stat import S_ISDIR -from typing import List, Optional, Tuple, Callable, Iterator, Iterable, Union +from typing import Callable, Iterable, Iterator, List, Optional, Tuple, Union # third party imports import xattr +from ..constants import IS_LINUX + # local imports from .hashing import DropboxContentHasher -from ..constants import IS_LINUX F_GETPATH = 50 diff --git a/tests/linked/conftest.py b/tests/linked/conftest.py index 1cd65876..9f21e87d 100644 --- a/tests/linked/conftest.py +++ b/tests/linked/conftest.py @@ -1,5 +1,5 @@ -import os import logging +import os import pytest @@ -10,7 +10,6 @@ from maestral.keyring import CredentialStorage from .lock import DropboxTestLock - fsevents_logger = logging.getLogger("fsevents") fsevents_logger.setLevel(logging.DEBUG) diff --git a/tests/linked/integration/conftest.py b/tests/linked/integration/conftest.py index 7938c16c..ad037d91 100644 --- a/tests/linked/integration/conftest.py +++ b/tests/linked/integration/conftest.py @@ -1,17 +1,16 @@ -import os import logging +import os import time import pytest import maestral.manager -from maestral.main import Maestral from maestral.client import DropboxClient from maestral.config import remove_configuration -from maestral.utils.path import generate_cc_name, delete +from maestral.exceptions import DropboxAuthError, NotFoundError +from maestral.main import Maestral from maestral.utils.appdirs import get_home_dir -from maestral.exceptions import NotFoundError, DropboxAuthError - +from maestral.utils.path import delete, generate_cc_name fsevents_logger = logging.getLogger("fsevents") fsevents_logger.setLevel(logging.DEBUG) diff --git a/tests/linked/integration/test_main.py b/tests/linked/integration/test_main.py index 22e46a79..ed454d62 100644 --- a/tests/linked/integration/test_main.py +++ b/tests/linked/integration/test_main.py @@ -1,26 +1,25 @@ from __future__ import annotations -import sys import os import os.path as osp -import time import subprocess +import sys +import time import pytest from dropbox import files -from maestral.main import Maestral +from maestral.constants import IDLE, FileStatus from maestral.core import FileMetadata from maestral.exceptions import ( - NotFoundError, - UnsupportedFileTypeForDiff, - SyncError, InotifyError, + NotFoundError, + SyncError, + UnsupportedFileTypeForDiff, ) -from maestral.constants import FileStatus, IDLE +from maestral.main import Maestral from maestral.utils.integration import get_inotify_limits - if not ("DROPBOX_ACCESS_TOKEN" in os.environ or "DROPBOX_REFRESH_TOKEN" in os.environ): pytest.skip("Requires auth token", allow_module_level=True) diff --git a/tests/linked/integration/test_sync.py b/tests/linked/integration/test_sync.py index e7426c5e..22361443 100644 --- a/tests/linked/integration/test_sync.py +++ b/tests/linked/integration/test_sync.py @@ -1,49 +1,48 @@ from __future__ import annotations -import platform -import sys import os import os.path as osp -import time +import platform import shutil +import sys +import time import timeit from datetime import datetime, timezone -from typing import Union, Mapping, TypeVar, cast +from typing import Mapping, TypeVar, Union, cast import pytest +from dropbox import files from watchdog.events import ( + DirCreatedEvent, + DirDeletedEvent, FileCreatedEvent, FileDeletedEvent, - DirDeletedEvent, - DirCreatedEvent, ) -from dropbox import files -from maestral.main import Maestral from maestral.core import FileMetadata, FolderMetadata -from maestral.models import SyncEvent, SyncDirection +from maestral.errorhandling import convert_api_errors +from maestral.exceptions import ( + FolderConflictError, + InsufficientPermissionsError, + NoDropboxDirError, + PathError, + SymlinkError, + SyncError, +) +from maestral.main import Maestral +from maestral.models import SyncDirection, SyncEvent from maestral.utils.appdirs import get_home_dir from maestral.utils.path import ( delete, - move, + fs_max_lengths_for_path, + get_symlink_target, is_fs_case_sensitive, + move, normalize, normalize_unicode, - fs_max_lengths_for_path, to_existing_unnormalized_path, walk, - get_symlink_target, ) -from maestral.exceptions import ( - PathError, - SymlinkError, - NoDropboxDirError, - InsufficientPermissionsError, - SyncError, - FolderConflictError, -) -from maestral.errorhandling import convert_api_errors - # mypy cannot yet check recursive type definitions... DirTreeType = Mapping[str, Union[str, Mapping[str, Union[str, Mapping[str, str]]]]] diff --git a/tests/linked/lock.py b/tests/linked/lock.py index 3a3d8ac5..4b16d1df 100644 --- a/tests/linked/lock.py +++ b/tests/linked/lock.py @@ -4,10 +4,10 @@ from datetime import datetime, timezone from dropbox import files -from maestral.core import FileMetadata from maestral.client import DropboxClient -from maestral.exceptions import NotFoundError, FileConflictError +from maestral.core import FileMetadata from maestral.errorhandling import convert_api_errors +from maestral.exceptions import FileConflictError, NotFoundError class DropboxTestLock: diff --git a/tests/linked/unit/conftest.py b/tests/linked/unit/conftest.py index e68003c0..9ea98a24 100644 --- a/tests/linked/unit/conftest.py +++ b/tests/linked/unit/conftest.py @@ -1,15 +1,14 @@ -import os import logging +import os import time import pytest -from maestral.main import Maestral from maestral.client import DropboxClient from maestral.config import remove_configuration -from maestral.exceptions import NotFoundError, DropboxAuthError +from maestral.exceptions import DropboxAuthError, NotFoundError from maestral.keyring import CredentialStorage - +from maestral.main import Maestral fsevents_logger = logging.getLogger("fsevents") fsevents_logger.setLevel(logging.DEBUG) diff --git a/tests/linked/unit/test_client.py b/tests/linked/unit/test_client.py index 396b6820..ef971641 100644 --- a/tests/linked/unit/test_client.py +++ b/tests/linked/unit/test_client.py @@ -9,14 +9,13 @@ import maestral.client from maestral.client import DropboxClient from maestral.core import AccountType, FolderMetadata from maestral.exceptions import ( + DataCorruptionError, NotFoundError, PathError, - DataCorruptionError, SharedLinkError, ) -from maestral.utils.path import normalize, content_hash from maestral.utils.hashing import DropboxContentHasher - +from maestral.utils.path import content_hash, normalize if not ("DROPBOX_ACCESS_TOKEN" in os.environ or "DROPBOX_REFRESH_TOKEN" in os.environ): pytest.skip("Requires auth token", allow_module_level=True) diff --git a/tests/offline/config/conftest.py b/tests/offline/config/conftest.py index 4e2e8df8..abd659ac 100644 --- a/tests/offline/config/conftest.py +++ b/tests/offline/config/conftest.py @@ -1,7 +1,7 @@ import pytest from packaging.version import Version -from maestral.config.user import UserConfig +from maestral.config.user import UserConfig DEFAULTS_CONFIG = { "auth": { diff --git a/tests/offline/config/test_user.py b/tests/offline/config/test_user.py index 8bd88445..975961c6 100644 --- a/tests/offline/config/test_user.py +++ b/tests/offline/config/test_user.py @@ -1,11 +1,11 @@ import configparser as cp import pytest - from packaging.version import Version + from maestral.config.user import UserConfig -from .conftest import DEFAULTS_CONFIG, CONF_VERSION +from .conftest import CONF_VERSION, DEFAULTS_CONFIG def test_config_creation(config): diff --git a/tests/offline/conftest.py b/tests/offline/conftest.py index efe3f5fe..b29f5d36 100644 --- a/tests/offline/conftest.py +++ b/tests/offline/conftest.py @@ -1,16 +1,16 @@ +import logging import os import os.path as osp -import logging import pytest -from maestral.main import Maestral -from maestral.sync import SyncEngine -from maestral.fsevents import Observer from maestral.client import DropboxClient from maestral.config import list_configs, remove_configuration -from maestral.daemon import stop_maestral_daemon_process, Stop +from maestral.daemon import Stop, stop_maestral_daemon_process +from maestral.fsevents import Observer from maestral.keyring import CredentialStorage +from maestral.main import Maestral +from maestral.sync import SyncEngine from maestral.utils.appdirs import get_home_dir from maestral.utils.path import delete diff --git a/tests/offline/test_clean_local_events.py b/tests/offline/test_clean_local_events.py index c14cbd3d..27943c79 100644 --- a/tests/offline/test_clean_local_events.py +++ b/tests/offline/test_clean_local_events.py @@ -1,18 +1,18 @@ import pytest from watchdog.events import ( + DirCreatedEvent, + DirDeletedEvent, + DirMovedEvent, FileCreatedEvent, FileDeletedEvent, FileModifiedEvent, FileMovedEvent, - DirCreatedEvent, - DirDeletedEvent, - DirMovedEvent, ) -from maestral.sync import SyncEngine from maestral.client import DropboxClient -from maestral.keyring import CredentialStorage from maestral.config import remove_configuration +from maestral.keyring import CredentialStorage +from maestral.sync import SyncEngine @pytest.fixture diff --git a/tests/offline/test_cli.py b/tests/offline/test_cli.py index ee0f73a3..fe8f800e 100644 --- a/tests/offline/test_cli.py +++ b/tests/offline/test_cli.py @@ -2,15 +2,14 @@ import logging from click.testing import CliRunner -from maestral.main import Maestral -from maestral.cli import main from maestral.autostart import AutoStart -from maestral.notify import level_number_to_name, level_name_to_number -from maestral.daemon import MaestralProxy, start_maestral_daemon_process, Start +from maestral.cli import main +from maestral.daemon import MaestralProxy, Start, start_maestral_daemon_process from maestral.logging import scoped_logger +from maestral.main import Maestral +from maestral.notify import level_name_to_number, level_number_to_name from maestral.utils.appdirs import get_log_path - TEST_TIMEOUT = 60 diff --git a/tests/offline/test_client.py b/tests/offline/test_client.py index 6685ec6c..fcecc957 100644 --- a/tests/offline/test_client.py +++ b/tests/offline/test_client.py @@ -1,23 +1,22 @@ -from datetime import datetime -from datetime import timezone +from datetime import datetime, timezone +from unittest.mock import Mock import pytest import requests -from unittest.mock import Mock +from dropbox import common, files, sharing, team_common, users, users_common from dropbox.oauth import DropboxOAuth2FlowNoRedirect -from dropbox import users, users_common, common, team_common, files, sharing + +from maestral import core from maestral.client import ( DropboxClient, convert_account, convert_full_account, - convert_space_usage, convert_metadata, convert_shared_link_metadata, + convert_space_usage, ) -from maestral.keyring import CredentialStorage -from maestral import core from maestral.exceptions import NotLinkedError - +from maestral.keyring import CredentialStorage # ==== DropboxClient tests ============================================================= diff --git a/tests/offline/test_daemon.py b/tests/offline/test_daemon.py index 52cef6cb..648d63db 100644 --- a/tests/offline/test_daemon.py +++ b/tests/offline/test_daemon.py @@ -1,8 +1,8 @@ -import sys import os -import time import subprocess +import sys import threading +import time import uuid import pytest @@ -10,16 +10,15 @@ from Pyro5.api import Proxy from maestral.daemon import ( CommunicationError, + Lock, MaestralProxy, - start_maestral_daemon_process, - stop_maestral_daemon_process, Start, Stop, - Lock, + start_maestral_daemon_process, + stop_maestral_daemon_process, ) -from maestral.main import Maestral from maestral.exceptions import NotLinkedError - +from maestral.main import Maestral # locking tests diff --git a/tests/offline/test_errorhandling.py b/tests/offline/test_errorhandling.py index 939efb05..71634d40 100644 --- a/tests/offline/test_errorhandling.py +++ b/tests/offline/test_errorhandling.py @@ -5,47 +5,49 @@ import errno import pytest from dropbox import exceptions -from dropbox.files import * from dropbox.async_ import * -from dropbox.users import * -from dropbox.sharing import * from dropbox.auth import * from dropbox.common import * +from dropbox.files import * +from dropbox.sharing import * +from dropbox.users import * -from maestral.exceptions import ( - MaestralApiError, - InvalidDbidError, - DropboxAuthError, - TokenExpiredError, - TokenRevokedError, - CursorResetError, - BadInputError, - OutOfMemoryError, - SharedLinkError, - SyncError, - InsufficientPermissionsError, - InsufficientSpaceError, - PathError, - NotFoundError, - ConflictError, - IsAFolderError, - NotAFolderError, - DropboxServerError, - RestrictedContentError, - UnsupportedFileError, - FileSizeError, - FileReadError, - FileConflictError, - FolderConflictError, - DataCorruptionError, -) -from maestral.exceptions import PathRootError as MPRE from maestral.errorhandling import ( - os_to_maestral_error, dropbox_to_maestral_error, get_lookup_error_msg, - get_write_error_msg, get_session_lookup_error_msg, + get_write_error_msg, + os_to_maestral_error, +) +from maestral.exceptions import ( + BadInputError, + ConflictError, + CursorResetError, + DataCorruptionError, + DropboxAuthError, + DropboxServerError, + FileConflictError, + FileReadError, + FileSizeError, + FolderConflictError, + InsufficientPermissionsError, + InsufficientSpaceError, + InvalidDbidError, + IsAFolderError, + MaestralApiError, + NotAFolderError, + NotFoundError, + OutOfMemoryError, + PathError, +) +from maestral.exceptions import PathRootError as MPRE +from maestral.exceptions import ( + RestrictedContentError, + SharedLinkError, + SyncError, + TokenExpiredError, + TokenRevokedError, + UnsupportedFileError, ) diff --git a/tests/offline/test_event_handler.py b/tests/offline/test_event_handler.py index 928b0acd..3dce7dcb 100644 --- a/tests/offline/test_event_handler.py +++ b/tests/offline/test_event_handler.py @@ -2,14 +2,14 @@ import os from pathlib import Path from watchdog.events import ( - DirModifiedEvent, DirCreatedEvent, + DirModifiedEvent, DirMovedEvent, FileMovedEvent, ) +from maestral.models import ChangeType, ItemType from maestral.sync import SyncDirection, SyncEngine -from maestral.models import ItemType, ChangeType from maestral.utils.path import move diff --git a/tests/offline/test_keyring.py b/tests/offline/test_keyring.py index d7c2911c..5ac7a54b 100644 --- a/tests/offline/test_keyring.py +++ b/tests/offline/test_keyring.py @@ -1,15 +1,15 @@ from unittest import mock import pytest - -from maestral.keyring import CredentialStorage -from maestral.config import remove_configuration, MaestralConfig -from maestral.exceptions import KeyringAccessError from keyring.backend import KeyringBackend -from keyring.errors import KeyringLocked from keyring.backends.SecretService import Keyring as SecretServiceKeyring +from keyring.errors import KeyringLocked from keyrings.alt.file import PlaintextKeyring +from maestral.config import MaestralConfig, remove_configuration +from maestral.exceptions import KeyringAccessError +from maestral.keyring import CredentialStorage + @pytest.fixture def cred_storage(): diff --git a/tests/offline/test_main.py b/tests/offline/test_main.py index 69df9a03..8ad28f61 100644 --- a/tests/offline/test_main.py +++ b/tests/offline/test_main.py @@ -1,9 +1,10 @@ import pytest import requests + import maestral.main -from maestral.main import Maestral from maestral.constants import GITHUB_RELEASES_API from maestral.exceptions import NotLinkedError +from maestral.main import Maestral def test_check_for_updates(m: Maestral) -> None: diff --git a/tests/offline/test_manager.py b/tests/offline/test_manager.py index 0b2f2b5d..2697779f 100644 --- a/tests/offline/test_manager.py +++ b/tests/offline/test_manager.py @@ -2,11 +2,12 @@ import os from unittest import mock import pytest -from maestral.main import Maestral -from maestral.core import FullAccount, TeamRootInfo, UserRootInfo, AccountType + +from maestral.core import AccountType, FullAccount, TeamRootInfo, UserRootInfo from maestral.exceptions import NoDropboxDirError +from maestral.main import Maestral from maestral.utils.appdirs import get_home_dir -from maestral.utils.path import generate_cc_name, delete +from maestral.utils.path import delete, generate_cc_name def fake_linked(m: Maestral, account_info: FullAccount) -> None: diff --git a/tests/offline/test_sync.py b/tests/offline/test_sync.py index 84e67d31..d2b824a3 100644 --- a/tests/offline/test_sync.py +++ b/tests/offline/test_sync.py @@ -1,9 +1,8 @@ from datetime import datetime from queue import Queue -from maestral.sync import ActivityTree, ActivityNode -from maestral.models import SyncEvent, SyncDirection, SyncStatus, ChangeType, ItemType - +from maestral.models import ChangeType, ItemType, SyncDirection, SyncEvent, SyncStatus +from maestral.sync import ActivityNode, ActivityTree EVENT1 = SyncEvent( dbx_path="/d0/file1.txt", diff --git a/tests/offline/utils/test_appdirs.py b/tests/offline/utils/test_appdirs.py index 72c8dedd..ec543234 100644 --- a/tests/offline/utils/test_appdirs.py +++ b/tests/offline/utils/test_appdirs.py @@ -1,14 +1,15 @@ import platform import pytest + from maestral.utils.appdirs import ( - get_home_dir, - get_runtime_path, - get_conf_path, - get_log_path, - get_cache_path, - get_data_path, get_autostart_path, + get_cache_path, + get_conf_path, + get_data_path, + get_home_dir, + get_log_path, + get_runtime_path, ) diff --git a/tests/offline/utils/test_path.py b/tests/offline/utils/test_path.py index da44c24d..a0ef8e8d 100644 --- a/tests/offline/utils/test_path.py +++ b/tests/offline/utils/test_path.py @@ -1,18 +1,18 @@ import os import stat -import xattr import pytest +import xattr -from maestral.utils.path import ( - normalized_path_exists, - get_existing_equivalent_paths, - is_fs_case_sensitive, - is_child, - move, -) from maestral.constants import IS_LINUX from maestral.utils.appdirs import get_home_dir +from maestral.utils.path import ( + get_existing_equivalent_paths, + is_child, + is_fs_case_sensitive, + move, + normalized_path_exists, +) def touch(path: str) -> None: diff --git a/tests/offline/utils/test_utils.py b/tests/offline/utils/test_utils.py index 31965557..ac333970 100644 --- a/tests/offline/utils/test_utils.py +++ b/tests/offline/utils/test_utils.py @@ -2,7 +2,6 @@ import pytest from maestral.utils import get_newer_version - releases = ( "0.6.1", "0.7.0",