Skip to content

Commit 1a61826

Browse files
remove local retries during downloads
1 parent c433a6b commit 1a61826

File tree

4 files changed

+58
-109
lines changed

4 files changed

+58
-109
lines changed

src/icloudpd/base.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1238,6 +1238,10 @@ def should_break(counter: Counter) -> bool:
12381238
logger.debug("Retrying...")
12391239
# these errors we can safely retry
12401240
continue
1241+
except OSError as error:
1242+
logger.error("IOError during file operations: %s", error)
1243+
dump_responses(logger.debug, captured_responses)
1244+
return 1
12411245
except Exception:
12421246
dump_responses(logger.debug, captured_responses)
12431247
raise

src/icloudpd/download.py

Lines changed: 23 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,8 @@
1212
from tzlocal import get_localzone
1313

1414
# Import the constants object so that we can mock WAIT_SECONDS in tests
15-
from icloudpd import constants
1615
from pyicloud_ipd.asset_version import AssetVersion, calculate_version_filename
1716
from pyicloud_ipd.base import PyiCloudService
18-
from pyicloud_ipd.exceptions import PyiCloudAPIResponseException
1917
from pyicloud_ipd.services.photos import PhotoAsset
2018
from pyicloud_ipd.version_size import VersionSize
2119

@@ -128,75 +126,29 @@ def download_media(
128126
partial(download_response_to_path_dry_run, logger) if dry_run else download_response_to_path
129127
)
130128

131-
retries = 0
132-
while True:
133-
try:
134-
append_mode = os.path.exists(temp_download_path)
135-
current_size = os.path.getsize(temp_download_path) if append_mode else 0
136-
if append_mode:
137-
logger.debug(f"Resuming downloading of {download_path} from {current_size}")
138-
139-
photo_response = photo.download(icloud.photos.session, version.url, current_size)
140-
if photo_response.ok:
141-
return download_local(
142-
photo_response, temp_download_path, append_mode, download_path, photo.created
143-
)
144-
else:
145-
# Use the standard original filename generator for error logging
146-
from icloudpd.base import lp_filename_original as simple_lp_filename_generator
147-
148-
# Get the proper filename using filename_builder
149-
base_filename = filename_builder(photo)
150-
version_filename = calculate_version_filename(
151-
base_filename, version, size, simple_lp_filename_generator, photo.item_type
152-
)
153-
logger.error(
154-
"Could not find URL to download %s for size %s",
155-
version_filename,
156-
size.value,
157-
)
158-
break
159-
160-
except PyiCloudAPIResponseException as ex:
161-
if "Invalid global session" in str(ex):
162-
error_filename = filename_builder(photo)
163-
logger.error(
164-
"Could not download %s. Please try again later.",
165-
error_filename,
166-
)
167-
168-
raise
169-
else:
170-
# short circuiting 0 retries
171-
if retries == constants.MAX_RETRIES:
172-
break
173-
# you end up here when p.e. throttling by Apple happens
174-
wait_time = (retries + 1) * constants.WAIT_SECONDS
175-
# Get the proper filename for error messages
176-
error_filename = filename_builder(photo)
177-
logger.error(
178-
"Error downloading %s, retrying after %s seconds...", error_filename, wait_time
179-
)
180-
time.sleep(wait_time)
181-
182-
except OSError:
183-
logger.error(
184-
"IOError while writing file to %s. "
185-
+ "You might have run out of disk space, or the file "
186-
+ "might be too large for your OS. "
187-
+ "Skipping this file...",
188-
download_path,
189-
)
190-
break
191-
retries = retries + 1
192-
if retries >= constants.MAX_RETRIES:
193-
break
194-
if retries >= constants.MAX_RETRIES:
195-
# Get the proper filename for error messages
196-
error_filename = filename_builder(photo)
129+
append_mode = os.path.exists(temp_download_path)
130+
current_size = os.path.getsize(temp_download_path) if append_mode else 0
131+
if append_mode:
132+
logger.debug(f"Resuming downloading of {download_path} from {current_size}")
133+
134+
photo_response = photo.download(icloud.photos.session, version.url, current_size)
135+
if photo_response.ok:
136+
return download_local(
137+
photo_response, temp_download_path, append_mode, download_path, photo.created
138+
)
139+
else:
140+
# Use the standard original filename generator for error logging
141+
from icloudpd.base import lp_filename_original as simple_lp_filename_generator
142+
143+
# Get the proper filename using filename_builder
144+
base_filename = filename_builder(photo)
145+
version_filename = calculate_version_filename(
146+
base_filename, version, size, simple_lp_filename_generator, photo.item_type
147+
)
197148
logger.error(
198-
"Could not download %s. Please try again later.",
199-
error_filename,
149+
"Could not find URL to download %s for size %s",
150+
version_filename,
151+
size.value,
200152
)
201153

202-
return False
154+
return False

tests/test_download_photos.py

Lines changed: 19 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -423,14 +423,18 @@ def test_handle_io_error(self) -> None:
423423
f"Downloading the first original photo to {data_dir} ...",
424424
result.output,
425425
)
426+
# self.assertIn(
427+
# "IOError while writing file to "
428+
# f"{os.path.join(data_dir, os.path.normpath('2018/07/31/IMG_7409.JPG'))}. "
429+
# "You might have run out of disk space, or the file might "
430+
# "be too large for your OS. Skipping this file...",
431+
# result.output,
432+
# )
426433
self.assertIn(
427-
"IOError while writing file to "
428-
f"{os.path.join(data_dir, os.path.normpath('2018/07/31/IMG_7409.JPG'))}. "
429-
"You might have run out of disk space, or the file might "
430-
"be too large for your OS. Skipping this file...",
434+
"IOError",
431435
result.output,
432436
)
433-
assert result.exit_code == 0
437+
assert result.exit_code == 1
434438

435439
def test_handle_session_error_during_download(self) -> None:
436440
base_dir = os.path.join(self.fixtures_path, inspect.stack()[0][3])
@@ -495,10 +499,10 @@ def mocked_authenticate(self: PyiCloudService) -> None:
495499
"retry count",
496500
)
497501

498-
self.assertIn(
499-
"Could not download IMG_7409.JPG. Please try again later.",
500-
result.output,
501-
)
502+
# self.assertIn(
503+
# "Could not download IMG_7409.JPG. Please try again later.",
504+
# result.output,
505+
# )
502506

503507
# Make sure we only call sleep 4 times (skip the first retry)
504508
self.assertEqual(
@@ -1702,20 +1706,16 @@ def mock_raise_response_error(_arg: Any, _session: Any, _size: Any) -> NoReturn:
17021706
)
17031707

17041708
# Error msg should be repeated 5 times
1705-
self.assertEqual(
1706-
result.output.count("Error downloading"),
1707-
constants.MAX_RETRIES,
1708-
"retry count",
1709-
)
1709+
self.assertIn("INTERNAL_ERROR", result.output)
17101710

1711-
self.assertIn(
1712-
"Could not download IMG_7409.JPG. Please try again later.",
1713-
result.output,
1714-
)
1711+
# self.assertIn(
1712+
# "Could not download IMG_7409.JPG. Please try again later.",
1713+
# result.output,
1714+
# )
17151715

17161716
# Make sure we only call sleep 4 times (skip the first retry)
17171717
self.assertEqual(sleep_mock.call_count, constants.MAX_RETRIES, "sleep count")
1718-
self.assertEqual(result.exit_code, 0, "Exit Code")
1718+
self.assertEqual(result.exit_code, 1, "Exit Code")
17191719

17201720
def test_handle_internal_error_during_photo_iteration(self) -> None:
17211721
base_dir = os.path.join(self.fixtures_path, inspect.stack()[0][3])

tests/test_download_photos_id.py

Lines changed: 12 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -416,13 +416,10 @@ def test_handle_io_error_name_id7(self) -> None:
416416
result.output,
417417
)
418418
self.assertIn(
419-
"IOError while writing file to "
420-
f"{os.path.join(data_dir, os.path.normpath('2018/07/31/IMG_7409_QVk2Yyt.JPG'))}. "
421-
"You might have run out of disk space, or the file might "
422-
"be too large for your OS. Skipping this file...",
419+
"IOError",
423420
result.output,
424421
)
425-
assert result.exit_code == 0
422+
assert result.exit_code == 1
426423

427424
def test_handle_session_error_during_download_name_id7(self) -> None:
428425
base_dir = os.path.join(self.fixtures_path, inspect.stack()[0][3])
@@ -487,10 +484,10 @@ def mocked_authenticate(self: PyiCloudService) -> None:
487484
"retry count",
488485
)
489486

490-
self.assertIn(
491-
"Could not download IMG_7409_QVk2Yyt.JPG. Please try again later.",
492-
result.output,
493-
)
487+
# self.assertIn(
488+
# "Could not download IMG_7409_QVk2Yyt.JPG. Please try again later.",
489+
# result.output,
490+
# )
494491

495492
# Make sure we only call sleep 4 times (skip the first retry)
496493
self.assertEqual(
@@ -1622,20 +1619,16 @@ def mock_raise_response_error(_arg: Any, _session: Any, _size: Any) -> NoReturn:
16221619
)
16231620

16241621
# Error msg should be repeated 5 times
1625-
self.assertEqual(
1626-
result.output.count("Error downloading"),
1627-
constants.MAX_RETRIES,
1628-
"retry count",
1629-
)
1622+
self.assertIn("INTERNAL_ERROR", result.output)
16301623

1631-
self.assertIn(
1632-
"Could not download IMG_7409_QVk2Yyt.JPG. Please try again later.",
1633-
result.output,
1634-
)
1624+
# self.assertIn(
1625+
# "Could not download IMG_7409_QVk2Yyt.JPG. Please try again later.",
1626+
# result.output,
1627+
# )
16351628

16361629
# Make sure we only call sleep 4 times (skip the first retry)
16371630
self.assertEqual(sleep_mock.call_count, constants.MAX_RETRIES, "sleep count")
1638-
self.assertEqual(result.exit_code, 0, "Exit Code")
1631+
self.assertEqual(result.exit_code, 1, "Exit Code")
16391632

16401633
def test_handle_internal_error_during_photo_iteration_name_id7(self) -> None:
16411634
base_dir = os.path.join(self.fixtures_path, inspect.stack()[0][3])

0 commit comments

Comments
 (0)