Closed rcook closed 2 weeks ago
Does this happen every time? I've never seen it so far.
Does your script do something weird with descriptors?
@ppolewicz : It does not happen every single time, but it happens often enough that it's distracting. Here's the class from my code that calls into the b2sdk:
from b2sdk.v2 import \
AbstractAction, \
AbstractFileSyncPolicy, \
B2Api, \
DownAndDeletePolicy, \
LocalDeleteAction, \
SqliteAccountInfo, \
SyncPolicyManager
from b2sdk.v2 import ScanPoliciesManager
from b2sdk.v2 import parse_folder
from b2sdk.v2 import Synchronizer, SyncReport
from b2sdk.v2 import KeepOrDeleteMode, CompareVersionMode, NewerFileSyncMode
from pathlib import Path
from time import time
from typing import Generator, Optional
import sys
MAX_WORKERS: int = 10
class IgnoringSyncPolicyManager(SyncPolicyManager):
def __init__(self, policies_manager: ScanPoliciesManager):
self._policies_manager = policies_manager
def get_policy_class(self, sync_type: str, delete: bool, keep_days: bool) -> AbstractFileSyncPolicy:
def make_policy_class():
policies_manager = self._policies_manager
class IgnoringDownAndDeletePolicy(DownAndDeletePolicy):
def _get_hide_delete_actions(self) -> Generator[AbstractAction, None, None]:
def predicate(action):
if isinstance(action, LocalDeleteAction):
return not policies_manager._exclude_file_set.matches(action.relative_name)
return True
yield from filter(predicate, super()._get_hide_delete_actions())
return IgnoringDownAndDeletePolicy
cls = super().get_policy_class(
sync_type=sync_type,
delete=delete,
keep_days=keep_days)
return cls if cls is not DownAndDeletePolicy else make_policy_class()
def run_b2_sync(source_path: Path | str, target_path: Path | str, compare_version_mode: CompareVersionMode, ignore_regex: Optional[str], single_threaded: bool, delete: bool, dry_run: bool) -> None:
def now_millis() -> int:
return int(round(time() * 1000))
info = SqliteAccountInfo()
b2_api = B2Api(info)
source = parse_folder(str(source_path), b2_api)
target = parse_folder(str(target_path), b2_api)
policies_manager = ScanPoliciesManager(
exclude_all_symlinks=True,
exclude_file_regexes=[] if ignore_regex is None else [ignore_regex])
sync_policy_manager = IgnoringSyncPolicyManager(
policies_manager=policies_manager)
keep_or_delete_mode = KeepOrDeleteMode.DELETE if delete else KeepOrDeleteMode.NO_DELETE
synchronizer = Synchronizer(
policies_manager=policies_manager,
sync_policy_manager=sync_policy_manager,
max_workers=1 if single_threaded else MAX_WORKERS,
dry_run=dry_run,
allow_empty_source=True,
compare_version_mode=compare_version_mode,
compare_threshold=0,
newer_file_mode=NewerFileSyncMode.SKIP,
keep_days_or_delete=keep_or_delete_mode)
with SyncReport(sys.stdout, no_progress=False) as reporter:
# Warnings about ignore exception thrown in call to sync_folders
synchronizer.sync_folders(
source_folder=source,
dest_folder=target,
now_millis=now_millis(),
reporter=reporter)
I don't think this code is doing anything particularly strange.
Is this message a feature of Python 3.13? From https://docs.python.org/3/whatsnew/3.13.html:
io The IOBase finalizer now logs any errors raised by the close() method with sys.unraisablehook. Previously, errors were ignored silently by default, and only logged in Python Development Mode or when using a Python debug build. (Contributed by Victor Stinner in gh-62948.)
I observed the message on b2sdk-2.5.1, but not in b2sdk-2.6.0, so I assumed that b2sdk now avoids the issue. BTW I'm using MacOS Sequoia 15.0.1.
@titus8 : Yes, I'm using Python 3.13. I'll update the latest b2sdk. Thanks!
This is the commit where this was fixed: cad8b2ba
I think this is benign since the file is uploaded in its entirety, but it does messed up the output of my script:
This is the offending line of code: https://github.com/Backblaze/b2-sdk-python/blob/master/b2sdk/_internal/stream/wrapper.py#L55
Perhaps it would be as simple as wrapping the call to
self.stream.flush()
and catchingValueError
.