Skip to content

Commit 6ac0ced

Browse files
committed
Version 0.7.4
* Add options for mypy --implicit-optional --allow-redefinition --disable-error-code abstract * Fix typings * Install setuptools firstly * Use typing_extensions.Final for python3.7 * Disable attr-defined checking at windows
1 parent f5c30bf commit 6ac0ced

File tree

15 files changed

+140
-67
lines changed

15 files changed

+140
-67
lines changed

.github/workflows/main.yml

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,12 +24,18 @@ jobs:
2424
with:
2525
virtualenvs-create: true
2626
- name: Install dependencies
27-
run: poetry install --no-root
27+
run: |
28+
poetry run pip3 install setuptools
29+
poetry install --no-root
2830
if: steps.cached-poetry-dependencies.outputs.cache-hit != 'true'
2931
- name: Format check with black
3032
run: poetry run black --check .
31-
- name: Typecheck with mypy
32-
run: poetry run mypy -p baidupcs_py --ignore-missing-imports --warn-unreachable
33+
- name: Typecheck with mypy at Windows
34+
run: poetry run mypy -p baidupcs_py --ignore-missing-imports --warn-unreachable --implicit-optional --allow-redefinition --disable-error-code abstract --disable-error-code attr-defined
35+
if: matrix.os == 'windows-latest'
36+
- name: Typecheck with mypy at Linux
37+
run: poetry run mypy -p baidupcs_py --ignore-missing-imports --warn-unreachable --implicit-optional --allow-redefinition --disable-error-code abstract
38+
if: matrix.os == 'ubuntu-latest'
3339
- name: Test with pytest
3440
run: |
3541
poetry run python build.py build_ext --inplace

CHANGELOG.md

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,16 @@
11
# Changelog
22

3-
## v0.7.3 - 2022-10-31
3+
## v0.7.4 - 2022-11-10
4+
5+
### Changed
6+
7+
- 在下载和上传时,让调用者去初始化进度条。
8+
9+
### Updated
10+
11+
- 更新依赖。
12+
13+
## v0.7.3 - 2022-11-09
414

515
### Updated
616

Makefile

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
typecheck:
2-
mypy -p baidupcs_py --ignore-missing-imports --warn-unreachable
2+
mypy -p baidupcs_py \
3+
--ignore-missing-imports \
4+
--warn-unreachable \
5+
--implicit-optional \
6+
--allow-redefinition \
7+
--disable-error-code abstract
38

49
format-check:
510
black --check .
@@ -10,6 +15,8 @@ format:
1015
build-pyx:
1116
python build.py build_ext --inplace
1217

18+
test: build-pyx
19+
pytest -s tests/test_common.py
1320

1421
build: all
1522
rm -fr dist

baidupcs_py/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
from baidupcs_py.baidupcs import BaiduPCS, BaiduPCSApi
22

3-
__version__ = "0.7.3"
3+
__version__ = "0.7.4"

baidupcs_py/app/account.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ def cd(self, remotedir: str = "/"):
110110

111111
assert account
112112

113-
pwd = join_path(account.pwd, remotedir)
113+
pwd = join_path(Path(account.pwd), Path(remotedir))
114114
account = account._replace(pwd=pwd)
115115
self._accounts[self._who] = account
116116

baidupcs_py/commands/log.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,17 @@
1+
from typing import cast
12
import os
23
from pathlib import Path
34

4-
from baidupcs_py.common.log import LogLevels, get_logger as _get_logger
5+
from baidupcs_py.common.log import TLogLevel, LogLevels, get_logger as _get_logger
56
from baidupcs_py.commands.env import LOG_LEVEL, LOG_PATH
67

78

89
def get_logger(name: str):
910
_LOG_PATH = Path(os.getenv("LOG_PATH") or LOG_PATH).expanduser()
10-
_LOG_LEVEL = os.getenv("LOG_LEVEL", LOG_LEVEL).upper()
11+
_LOG_LEVEL: TLogLevel = cast(
12+
TLogLevel,
13+
os.getenv("LOG_LEVEL", LOG_LEVEL).upper(),
14+
)
1115
assert _LOG_LEVEL in LogLevels
1216

1317
return _get_logger(name, filename=_LOG_PATH, level=_LOG_LEVEL)

baidupcs_py/commands/rapid_upload.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
from typing import Optional, List, Dict, Any
22

3+
from pathlib import Path
34
from threading import Semaphore
45
from concurrent.futures import ThreadPoolExecutor, as_completed
56

@@ -176,7 +177,7 @@ def rapid_upload(
176177
content_crc32 = content_crc32 or 0
177178
filename = filename or _filename
178179

179-
remotepath = join_path(remotedir, filename)
180+
remotepath = join_path(Path(remotedir), Path(filename))
180181

181182
assert all(
182183
[slice_md5, content_md5, content_length]

baidupcs_py/commands/server.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ async def handle_request(
6161

6262
remotepath = remotepath.strip("/")
6363

64-
_rp = join_path(_root_dir, remotepath)
64+
_rp = join_path(Path(_root_dir), Path(remotepath))
6565

6666
# Anti path traversal attack
6767
if not _rp.startswith(_root_dir):

baidupcs_py/commands/sync.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -66,12 +66,12 @@ def sync(
6666
fts: List[FromTo] = []
6767
check_list: List[Tuple[str, PcsFile]] = []
6868
all_localpaths = set()
69-
for localpath in walk(localdir):
69+
for localpath in walk(Path(localdir)):
7070
path = localpath[len(localdir) + 1 :]
7171
all_localpaths.add(path)
7272

7373
if path not in all_pcs_files:
74-
fts.append(FromTo(localpath, join_path(remotedir, path)))
74+
fts.append(FromTo(localpath, join_path(Path(remotedir), Path(path))))
7575
else:
7676
check_list.append((localpath, all_pcs_files[path]))
7777

baidupcs_py/commands/upload.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -75,15 +75,15 @@ def from_tos(localpaths: List[str], remotedir: str) -> List[FromTo]:
7575

7676
ft: List[FromTo] = []
7777
for localpath in localpaths:
78-
if not exists(localpath):
78+
if not exists(Path(localpath)):
7979
continue
8080

81-
if is_file(localpath):
81+
if is_file(Path(localpath)):
8282
remotepath = to_remotepath(os.path.basename(localpath), remotedir)
8383
ft.append(FromTo(localpath, remotepath))
8484
else:
8585
parents_num = max(len(Path(localpath).parts) - 1, 0)
86-
for sub_path in walk(localpath):
86+
for sub_path in walk(Path(localpath)):
8787
relative_path = Path(*Path(sub_path).parts[parents_num:]).as_posix()
8888
remotepath = to_remotepath(relative_path, remotedir)
8989
ft.append(FromTo(sub_path, remotepath))

baidupcs_py/common/downloader.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
from typing import Optional, Any, Callable
1+
from typing import Optional, List, Any, Callable
22
from os import PathLike
33
from pathlib import Path
44
from threading import Semaphore
@@ -14,6 +14,10 @@
1414

1515

1616
class MeDownloader(RangeRequestIO):
17+
_executor: ThreadPoolExecutor
18+
_semaphore: Semaphore
19+
_futures: List[Future]
20+
1721
@classmethod
1822
def _set_executor(
1923
cls,

baidupcs_py/common/io.py

Lines changed: 64 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,16 @@
1-
from typing import Optional, List, Tuple, Dict, Union, Any, Callable, Generator, IO
1+
from typing import (
2+
Optional,
3+
List,
4+
Tuple,
5+
Dict,
6+
Union,
7+
Any,
8+
Callable,
9+
Generator,
10+
IO,
11+
cast,
12+
AnyStr,
13+
)
214
from io import BytesIO, UnsupportedOperation
315
from enum import Enum
416
from pathlib import Path
@@ -29,15 +41,15 @@
2941
calu_md5,
3042
calu_crc32_and_md5,
3143
)
32-
from baidupcs_py.common.log import LogLevels, get_logger
44+
from baidupcs_py.common.log import TLogLevel, LogLevels, get_logger
3345

34-
import requests
46+
import requests # type: ignore
3547
from requests import Response
3648

3749
_LOG_LEVEL = os.getenv("LOG_LEVEL", "CRITICAL").upper()
3850
if _LOG_LEVEL not in LogLevels:
3951
_LOG_LEVEL = "CRITICAL"
40-
logger = get_logger(__name__, level=_LOG_LEVEL)
52+
logger = get_logger(__name__, level=cast(TLogLevel, _LOG_LEVEL))
4153

4254
READ_SIZE = 65535
4355

@@ -239,11 +251,17 @@ def __init__(self, io: IO, encrypt_password: bytes, total_origin_len: int):
239251
# Cryptography
240252
#
241253
# Instantiated at each subclass, here is for mypy
242-
self._crypto: Optional[Cryptography] = None
254+
self._crypto: Cryptography
243255

244-
self._total_head = None
256+
self._total_head: bytes
245257
self._total_head_len = len(self.total_head)
246258

259+
def magic_code(self) -> bytes:
260+
raise NotImplementedError()
261+
262+
def block_size(self) -> int:
263+
raise NotImplementedError()
264+
247265
def reset(self):
248266
"""Reset io and crypto"""
249267
self._io.seek(0, 0)
@@ -278,14 +296,14 @@ def total_head(self) -> bytes:
278296
`salt 8bytes`
279297
"""
280298

281-
if self._total_head:
299+
if hasattr(self, "_total_head"):
282300
return self._total_head
283301

284302
assert len(self._salt) == 8
285303

286304
ori_head = padding_key(
287305
BAIDUPCS_PY_CRYPTO_MAGIC_CODE
288-
+ self.MAGIC_CODE
306+
+ self.magic_code()
289307
+ self._salt
290308
+ random_sys_bytes(8)
291309
+ u64_to_u8x8(self._total_origin_len),
@@ -375,6 +393,7 @@ def close(self):
375393

376394

377395
class SimpleEncryptIO(EncryptIO):
396+
378397
MAGIC_CODE = b"\x00"
379398

380399
BLOCK_SIZE = 16 # 16 bytes
@@ -383,6 +402,12 @@ def __init__(self, *args, **kwargs):
383402
super().__init__(*args, **kwargs)
384403
self._crypto = SimpleCryptography(self._encrypt_key + self._nonce_or_iv)
385404

405+
def magic_code(self) -> bytes:
406+
return self.MAGIC_CODE
407+
408+
def block_size(self) -> int:
409+
return self.BLOCK_SIZE
410+
386411

387412
class ChaCha20EncryptIO(EncryptIO):
388413
MAGIC_CODE = b"\x01"
@@ -399,6 +424,12 @@ def reset(self):
399424
def seekable(self) -> bool:
400425
return False
401426

427+
def magic_code(self) -> bytes:
428+
return self.MAGIC_CODE
429+
430+
def block_size(self) -> int:
431+
return self.BLOCK_SIZE
432+
402433

403434
class AES256CBCEncryptIO(EncryptIO):
404435
MAGIC_CODE = b"\x02"
@@ -422,6 +453,12 @@ def __init__(self, *args, **kwargs):
422453

423454
self._need_data_padded = self._total_origin_len != self._encrypted_io_len
424455

456+
def magic_code(self) -> bytes:
457+
return self.MAGIC_CODE
458+
459+
def block_size(self) -> int:
460+
return self.BLOCK_SIZE
461+
425462
def reset(self):
426463
super().reset()
427464
self._origin_io_offset = 0
@@ -677,7 +714,7 @@ def _read_block(self, size: int = -1):
677714
len(self._encrypted_cache), self.BLOCK_SIZE, ceil=False
678715
)
679716
if avail_enc_len > 0:
680-
enc_cn = self._encrypted_cache[:avail_enc_len]
717+
enc_cn = bytes(self._encrypted_cache[:avail_enc_len])
681718
self._encrypted_cache = self._encrypted_cache[avail_enc_len:]
682719
else:
683720
enc_cn = b""
@@ -731,15 +768,15 @@ def _decryptio_version1(
731768
encrypt_password = padding_key(encrypt_password, 32)
732769

733770
if len(total_head) < ENCRYPT_HEAD_LEN:
734-
return
771+
return None
735772

736773
# Version 1
737-
b_mc, magic_code, nonce_or_iv, total_origin_len = parse_head(total_head)
774+
b_mc, magic_code, nonce_or_iv, total_origin_len_ = parse_head(total_head)
738775
b_mc = aes256cbc_decrypt(b_mc, encrypt_password, random_bytes(16, encrypt_password))
739-
total_origin_len = u8x8_to_u64(total_origin_len)
776+
total_origin_len = u8x8_to_u64(total_origin_len_)
740777

741778
if b_mc != BAIDUPCS_PY_CRYPTO_MAGIC_CODE:
742-
return
779+
return None
743780

744781
if magic_code == SimpleEncryptIO.MAGIC_CODE:
745782
return SimpleDecryptIO(io, encrypt_password, b"", total_origin_len)
@@ -748,15 +785,15 @@ def _decryptio_version1(
748785
elif magic_code == AES256CBCEncryptIO.MAGIC_CODE:
749786
return AES256CBCDecryptIO(io, encrypt_password, nonce_or_iv, total_origin_len)
750787
else:
751-
logging.warning(f"Unknown magic_code: {magic_code}")
752-
return
788+
logging.warning(f"Unknown magic_code: {magic_code!r}")
789+
return None
753790

754791

755792
def _decryptio_version3(
756793
total_head: bytes, io: IO, encrypt_password: bytes
757794
) -> Optional[DecryptIO]:
758795
if len(total_head) < PADDED_ENCRYPT_HEAD_WITH_SALT_LEN:
759-
return
796+
return None
760797

761798
enc_head, salt_for_head = (
762799
total_head[:PADDED_ENCRYPT_HEAD_LEN],
@@ -769,25 +806,25 @@ def _decryptio_version3(
769806

770807
head = aes256cbc_decrypt(enc_head, encrypt_key_for_head, iv_for_head)
771808

772-
b_mc, magic_code, padding_salt, total_origin_len = parse_head(head)
773-
total_origin_len = u8x8_to_u64(total_origin_len)
809+
b_mc, magic_code, padding_salt, total_origin_len_ = parse_head(head)
810+
total_origin_len = u8x8_to_u64(total_origin_len_)
774811

775812
salt = padding_salt[:8]
776813
encrypt_key, nonce_or_iv = generate_key_iv(encrypt_password, salt, 32, 16)
777814

778815
if b_mc != BAIDUPCS_PY_CRYPTO_MAGIC_CODE:
779-
return
816+
return None
780817

781-
eio = None
818+
eio: DecryptIO
782819
if magic_code == SimpleEncryptIO.MAGIC_CODE:
783820
eio = SimpleDecryptIO(io, encrypt_key, nonce_or_iv, total_origin_len)
784821
elif magic_code == ChaCha20EncryptIO.MAGIC_CODE:
785822
eio = ChaCha20DecryptIO(io, encrypt_key, nonce_or_iv, total_origin_len)
786823
elif magic_code == AES256CBCEncryptIO.MAGIC_CODE:
787824
eio = AES256CBCDecryptIO(io, encrypt_key, nonce_or_iv, total_origin_len)
788825
else:
789-
logging.warning(f"Unknown magic_code: {magic_code}")
790-
return
826+
logging.warning(f"Unknown magic_code: {magic_code!r}")
827+
return None
791828

792829
eio._total_head_len = PADDED_ENCRYPT_HEAD_WITH_SALT_LEN
793830
return eio
@@ -832,7 +869,7 @@ def __init__(
832869
self._kwargs = kwargs
833870
self._max_chunk_size = max_chunk_size
834871
self._encrypt_password = encrypt_password
835-
self._dio = None
872+
self._dio: Optional[IO] = None
836873
self._has_encrypted = False
837874
self._total_head_len = 0
838875
self._decrypted_count = 0
@@ -906,7 +943,9 @@ def _parse_crypto(self):
906943
self._dio = to_decryptio(BytesIO(raw_data), self._encrypt_password)
907944
self._has_encrypted = isinstance(self._dio, DecryptIO)
908945
self._total_head_len = (
909-
self._dio._total_head_len if self._has_encrypted else 0
946+
cast(DecryptIO, self._dio)._total_head_len
947+
if self._has_encrypted
948+
else 0
910949
)
911950
self._parsed = True
912951

@@ -966,6 +1005,7 @@ def __len__(self) -> int:
9661005

9671006
self._init()
9681007

1008+
assert self._content_length
9691009
return self._content_length - self._total_head_len
9701010

9711011
def read(self, _range: Tuple[int, int]) -> Generator[bytes, None, None]:

0 commit comments

Comments
 (0)