Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

format and lint code #885

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 0 additions & 4 deletions .codeclimate.yml

This file was deleted.

4 changes: 2 additions & 2 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,8 @@ There are some requirements for pull requests:
* 100% test coverage also for new features is expected.
* After running `./scripts/test`, you will see the test coverage results in the output
* You can also open the HTML report at: `./htmlcov/index.html`
* Code is formatted with [autopep8](https://github.com/hhatto/autopep8). Run `./scripts/format`
* No [pylint](https://www.pylint.org/) errors. Run `./scripts/lint` (or `pylint icloudpd`)
* Code is formatted with [ruff](https://github.com/astral-sh/ruff). Run `./scripts/format`
* No lint errors. Run `./scripts/lint`
* If you've added or changed any command-line options,
please update the [Usage](README.md#usage) section in the README.md.
* Make sure your change is documented in the
Expand Down
10 changes: 5 additions & 5 deletions binary_dist/src/icloud/__main__.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import os, sys, subprocess
sys.exit(subprocess.call([
os.path.join(os.path.dirname(__file__), "icloud"),
*sys.argv[1:]
]))
import os
import subprocess
import sys

sys.exit(subprocess.call([os.path.join(os.path.dirname(__file__), "icloud"), *sys.argv[1:]]))
10 changes: 5 additions & 5 deletions binary_dist/src/icloudpd/__main__.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import os, sys, subprocess
sys.exit(subprocess.call([
os.path.join(os.path.dirname(__file__), "icloudpd"),
*sys.argv[1:]
]))
import os
import subprocess
import sys

sys.exit(subprocess.call([os.path.join(os.path.dirname(__file__), "icloudpd"), *sys.argv[1:]]))
14 changes: 7 additions & 7 deletions docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,18 @@
# -- Project information -----------------------------------------------------
# https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information

project = 'icloudpd'
copyright = '2024, Contributors'
author = 'Contributors'
release = '1.20.3'
project = "icloudpd"
copyright = "2024, Contributors"
author = "Contributors"
release = "1.20.3"

# -- General configuration ---------------------------------------------------
# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration

extensions = ["myst_parser"]

templates_path = ['_templates']
exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store']
templates_path = ["_templates"]
exclude_patterns = ["_build", "Thumbs.db", ".DS_Store"]

html_title = "icloudpd 1.20.3"
language = "en"
Expand All @@ -26,5 +26,5 @@
# -- Options for HTML output -------------------------------------------------
# https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output

html_theme = 'furo'
html_theme = "furo"
# html_static_path = ['_static']
31 changes: 29 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -61,9 +61,8 @@ test = [
"freezegun==1.2.2",
"vcrpy==4.4.0",
"pytest-cov==4.1.0",
"pylint==2.17.5",
"ruff==0.5.0",
"coveralls==3.3.1",
"autopep8==2.0.2",
"pytest-timeout==2.1.0",
"pytest-xdist==3.3.1",
"mypy==1.10.0",
Expand Down Expand Up @@ -103,3 +102,31 @@ exclude = ["starters"]
[[tool.mypy.overrides]]
module = ['piexif.*', 'vcr.*']
ignore_missing_imports = true

[tool.ruff]
line-length = 100
extend-exclude = [ "src/pyicloud_ipd" ]

[tool.ruff.format]
docstring-code-format = true

[tool.ruff.lint]
select = [
# pycodestyle
"E",
# Pyflakes
"F",
# pyupgrade
"UP",
# flake8-bugbear
"B",
# flake8-simplify
"SIM",
# isort
"I",
]
ignore = [
# long lines
"E501",
]

6 changes: 4 additions & 2 deletions scripts/format
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
#!/bin/bash
set -euo pipefail
echo "Running autopep8..."
autopep8 -r --in-place --aggressive --aggressive src/ --exclude src/pyicloud_ipd
echo "Formatting..."
# autopep8 -r --in-place --aggressive --aggressive src/ --exclude src/pyicloud_ipd
ruff check --select I --fix
ruff format
4 changes: 2 additions & 2 deletions scripts/lint
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#!/bin/bash
set -euo pipefail
echo "Running pylint..."
python3 -m pylint src --ignore-paths src/icloud,src/pyicloud_ipd,src/starters
echo "Linting..."
ruff check --ignore "E402"
80 changes: 36 additions & 44 deletions src/icloudpd/authentication.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@

import logging
import sys
from typing import Callable, Dict, Optional, Sequence, Tuple
from typing import Callable, Dict, Optional, Tuple

import click
import pyicloud_ipd
from pyicloud_ipd.base import PyiCloudService
from pyicloud_ipd.file_match import FileMatchPolicy
from pyicloud_ipd.raw_policy import RawTreatmentPolicy
Expand All @@ -18,19 +18,23 @@


def authenticator(
logger: logging.Logger,
domain: str,
filename_cleaner: Callable[[str], str],
lp_filename_generator: Callable[[str], str],
raw_policy:RawTreatmentPolicy,
file_match_policy: FileMatchPolicy,
password_providers: Dict[str, Tuple[Callable[[str], Optional[str]], Callable[[str, str], None]]]) -> Callable[[str, Optional[str], bool, Optional[str]], PyiCloudService]:
logger: logging.Logger,
domain: str,
filename_cleaner: Callable[[str], str],
lp_filename_generator: Callable[[str], str],
raw_policy: RawTreatmentPolicy,
file_match_policy: FileMatchPolicy,
password_providers: Dict[
str, Tuple[Callable[[str], Optional[str]], Callable[[str, str], None]]
],
) -> Callable[[str, Optional[str], bool, Optional[str]], PyiCloudService]:
"""Wraping authentication with domain context"""

def authenticate_(
username:str,
cookie_directory:Optional[str]=None,
raise_error_on_2sa:bool=False,
client_id:Optional[str]=None,
username: str,
cookie_directory: Optional[str] = None,
raise_error_on_2sa: bool = False,
client_id: Optional[str] = None,
) -> PyiCloudService:
"""Authenticate with iCloud username and password"""
logger.debug("Authenticating...")
Expand All @@ -46,7 +50,8 @@
domain,
raw_policy,
file_match_policy,
username, _password,
username,
_password,
cookie_directory=cookie_directory,
client_id=client_id,
)
Expand All @@ -55,7 +60,7 @@

if not icloud:
raise NotImplementedError("None of providers gave password")

if _valid_password:
# save valid password to all providers
for _, _pair in password_providers.items():
Expand All @@ -64,21 +69,18 @@

if icloud.requires_2fa:
if raise_error_on_2sa:
raise TwoStepAuthRequiredError(
"Two-factor authentication is required"
)
raise TwoStepAuthRequiredError("Two-factor authentication is required")
logger.info("Two-factor authentication is required (2fa)")
request_2fa(icloud, logger)

elif icloud.requires_2sa:
if raise_error_on_2sa:
raise TwoStepAuthRequiredError(
"Two-step authentication is required"
)
raise TwoStepAuthRequiredError("Two-step authentication is required")
logger.info("Two-step authentication is required (2sa)")
request_2sa(icloud, logger)

return icloud

return authenticate_


Expand All @@ -89,20 +91,14 @@
device_index: int = 0
if devices_count > 0:
for i, device in enumerate(devices):
# pylint: disable-msg=consider-using-f-string
print(
" %s: %s" %
(i, device.get(
"deviceName", "SMS to %s" %
device.get("phoneNumber"))))
# pylint: enable-msg=consider-using-f-string
number = device["phoneNumber"]
alt_name = f"SMS to {number}"
name = device.get("deviceName", alt_name)
print(f" {i}: {name}")
Dismissed Show dismissed Hide dismissed

device_index = click.prompt(
"Please choose an option:",
default="0",
type=click.IntRange(
0,
devices_count - 1))
"Please choose an option:", default="0", type=click.IntRange(0, devices_count - 1)
)

device = devices[device_index]
if not icloud.send_verification_code(device):
Expand Down Expand Up @@ -135,11 +131,10 @@
print(f" {i}: {device.obfuscated_number}")

index_str = f"..{devices_count - 1}" if devices_count > 1 else ""
code:int = click.prompt(
code: int = click.prompt(
f"Please enter two-factor authentication code or device index (0{index_str}) to send SMS with a code",
type=click.IntRange(
0,
999999))
type=click.IntRange(0, 999999),
)

if code < devices_count:
# need to send code
Expand All @@ -149,9 +144,8 @@
sys.exit(1)
code = click.prompt(
"Please enter two-factor authentication code that you received over SMS",
type=click.IntRange(
100000,
999999))
type=click.IntRange(100000, 999999),
)
if not icloud.validate_2fa_code_sms(device.id, code):
logger.error("Failed to verify two-factor authentication code")
sys.exit(1)
Expand All @@ -161,10 +155,8 @@
sys.exit(1)
else:
code = click.prompt(
"Please enter two-factor authentication code",
type=click.IntRange(
100000,
999999))
"Please enter two-factor authentication code", type=click.IntRange(100000, 999999)
)
if not icloud.validate_2fa_code(str(code)):
logger.error("Failed to verify two-factor authentication code")
sys.exit(1)
Expand Down
43 changes: 20 additions & 23 deletions src/icloudpd/autodelete.py
Original file line number Diff line number Diff line change
@@ -1,37 +1,41 @@
"""
Delete any files found in "Recently Deleted"
"""

import datetime
import logging
import os
from typing import Sequence, Set
from tzlocal import get_localzone
from icloudpd.paths import local_download_path

from pyicloud_ipd.services.photos import PhotoLibrary
from pyicloud_ipd.utils import disambiguate_filenames
from pyicloud_ipd.version_size import AssetVersionSize, VersionSize
from tzlocal import get_localzone

from icloudpd.paths import local_download_path


def delete_file(logger: logging.Logger, path: str) -> bool:
""" Actual deletion of files """
"""Actual deletion of files"""
os.remove(path)
logger.info("Deleted %s", path)
return True


def delete_file_dry_run(logger: logging.Logger, path: str) -> bool:
""" Dry run deletion of files """
"""Dry run deletion of files"""
logger.info("[DRY RUN] Would delete %s", path)
return True


def autodelete_photos(
logger: logging.Logger,
dry_run: bool,
library_object: PhotoLibrary,
folder_structure: str,
directory: str,
_sizes: Sequence[AssetVersionSize]) -> None:
logger: logging.Logger,
dry_run: bool,
library_object: PhotoLibrary,
folder_structure: str,
directory: str,
_sizes: Sequence[AssetVersionSize],
) -> None:
"""
Scans the "Recently Deleted" folder and deletes any matching files
from the download directory.
Expand All @@ -45,9 +49,7 @@ def autodelete_photos(
try:
created_date = media.created.astimezone(get_localzone())
except (ValueError, OSError):
logger.error(
"Could not convert media created date to local timezone %s",
media.created)
logger.error("Could not convert media created date to local timezone %s", media.created)
created_date = media.created

if folder_structure.lower() == "none":
Expand All @@ -57,8 +59,7 @@ def autodelete_photos(
date_path = folder_structure.format(created_date)
except ValueError: # pragma: no cover
# This error only seems to happen in Python 2
logger.error(
"Photo created date was not valid (%s)", created_date)
logger.error("Photo created date was not valid (%s)", created_date)
# e.g. ValueError: year=5 is before 1900
# (https://github.com/icloud-photos-downloader/icloud_photos_downloader/issues/122)
# Just use the Unix epoch
Expand All @@ -67,18 +68,14 @@ def autodelete_photos(

download_dir = os.path.join(directory, date_path)

paths:Set[str] = set({})
_size:VersionSize
paths: Set[str] = set({})
_size: VersionSize
for _size, _version in disambiguate_filenames(media.versions, _sizes).items():
if _size in [AssetVersionSize.ALTERNATIVE, AssetVersionSize.ADJUSTED]:
paths.add(os.path.normpath(
local_download_path(
_version.filename, download_dir)))
paths.add(os.path.normpath(local_download_path(_version.filename, download_dir)))
for _size, _version in media.versions.items():
if _size not in [AssetVersionSize.ALTERNATIVE, AssetVersionSize.ADJUSTED]:
paths.add(os.path.normpath(
local_download_path(
_version.filename, download_dir)))
paths.add(os.path.normpath(local_download_path(_version.filename, download_dir)))
for path in paths:
if os.path.exists(path):
logger.debug("Deleting %s...", path)
Expand Down
Loading
Loading