apply isort

This commit is contained in:
samschott 2024-07-27 11:02:34 +02:00
parent 77f5370b2e
commit 533809e0e0
No known key found for this signature in database
GPG Key ID: 455100A147F0A99C
62 changed files with 490 additions and 509 deletions

View File

@ -1,6 +1,5 @@
import warnings
__version__ = "1.9.4"
__author__ = "Sam Schott"
__url__ = "https://maestral.app"

View File

@ -1,5 +1,4 @@
from .cli import main
if __name__ == "__main__":
main(prog_name="maestral")

View File

@ -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):

View File

@ -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")

View File

@ -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.

View File

@ -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.")

View File

@ -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, "")

View File

@ -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

View File

@ -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()

View File

@ -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)]

View File

@ -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")

View File

@ -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)

View File

@ -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:

View File

@ -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

View File

@ -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",

View File

@ -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"

View File

@ -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]]

View File

@ -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

View File

@ -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 ============================================================================

View File

@ -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)

View File

@ -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:

View File

@ -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")

View File

@ -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

View File

@ -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")

View File

@ -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",

View File

@ -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

View File

@ -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

View File

@ -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"]

View File

@ -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",

View File

@ -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"]

View File

@ -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"]

View File

@ -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

View File

@ -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",

View File

@ -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",

View File

@ -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]]

View File

@ -9,7 +9,6 @@ import platform
from os import path as osp
from typing import Optional
__all__ = [
"get_log_path",
"get_cache_path",

View File

@ -4,7 +4,6 @@ from __future__ import annotations
# system imports
import hashlib
from typing import BinaryIO, Union
_WritableBuffer = Union[bytes, bytearray]

View File

@ -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",

View File

@ -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

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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]]]]]

View File

@ -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:

View File

@ -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)

View File

@ -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)

View File

@ -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": {

View File

@ -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):

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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 =============================================================

View File

@ -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

View File

@ -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,
)

View File

@ -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

View File

@ -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():

View File

@ -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:

View File

@ -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:

View File

@ -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",

View File

@ -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,
)

View File

@ -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:

View File

@ -2,7 +2,6 @@ import pytest
from maestral.utils import get_newer_version
releases = (
"0.6.1",
"0.7.0",