Merge remote-tracking branch 'origin/main' into feat/331-collections-pr1
# Conflicts: # database/duplicate_copies.py # database/models.py # py/api/duplicate_files.py # tests/test_duplicate_image_categories.py
This commit is contained in:
@@ -34,6 +34,11 @@ try:
|
||||
except ImportError:
|
||||
from utils.parallel import map_parallel
|
||||
|
||||
try:
|
||||
from ...utils import exit_signal
|
||||
except ImportError:
|
||||
from utils import exit_signal
|
||||
|
||||
try:
|
||||
from ...database.pair_ingestion import blank_positive, ingest_resolved_pair
|
||||
from ...database.run_attribution import (
|
||||
@@ -118,6 +123,7 @@ def _collect_media_files(output_dirs, extensions):
|
||||
if not os.path.isdir(root):
|
||||
continue
|
||||
for current, dirnames, filenames in os.walk(root, followlinks=False):
|
||||
exit_signal.checkpoint() # #376: stop between directories at exit
|
||||
depth = 0 if current == root else len(Path(current).relative_to(root).parts)
|
||||
dirnames[:] = sorted(
|
||||
d
|
||||
|
||||
@@ -31,6 +31,7 @@ from .inspection_service import CurrentFileChanged, inspect_current_file
|
||||
try:
|
||||
from ...database.execution_history import HistoryEpochChanged
|
||||
from ...database.history_gallery import read_history_gallery
|
||||
from ...database.run_attribution import recorded_output_lookup
|
||||
from ...database.history_reads import (
|
||||
HistoryCaptureChanged,
|
||||
OutputPosition,
|
||||
@@ -42,6 +43,7 @@ try:
|
||||
except ImportError:
|
||||
from database.execution_history import HistoryEpochChanged
|
||||
from database.history_gallery import read_history_gallery
|
||||
from database.run_attribution import recorded_output_lookup
|
||||
from database.history_reads import (
|
||||
HistoryCaptureChanged,
|
||||
OutputPosition,
|
||||
@@ -728,6 +730,9 @@ class HistoryRoutesMixin:
|
||||
"library",
|
||||
{"status": "unavailable" if saved_unavailable else "none"},
|
||||
),
|
||||
recorded=recorded_output_lookup(
|
||||
db, close=True, reference=receipt["reference"]
|
||||
),
|
||||
)
|
||||
_reauthorize_current_target(resolved, scope)
|
||||
identity = {
|
||||
|
||||
@@ -62,6 +62,7 @@ try:
|
||||
from ...database.image_favorites import MAX_KEY_LENGTH
|
||||
from ...database.library import display_title
|
||||
from ...database.models import normalize_image_path
|
||||
from ...database.run_attribution import recorded_output_lookup
|
||||
from ...utils.card_seed import card_seed, header_params, parsed_positive
|
||||
from ...utils.parallel import map_parallel
|
||||
from ...utils.json_strict import dumps_strict
|
||||
@@ -83,6 +84,7 @@ except ImportError:
|
||||
from database.image_favorites import MAX_KEY_LENGTH
|
||||
from database.library import display_title
|
||||
from database.models import normalize_image_path
|
||||
from database.run_attribution import recorded_output_lookup
|
||||
from utils.card_seed import card_seed, header_params, parsed_positive
|
||||
from utils.parallel import map_parallel
|
||||
from utils.json_strict import dumps_strict
|
||||
@@ -3803,6 +3805,7 @@ class ImageRoutesMixin:
|
||||
image_tags=self._inspection_image_tags(
|
||||
roots[index], Path(relative).parts
|
||||
),
|
||||
recorded=recorded_output_lookup(self.db),
|
||||
)
|
||||
except CurrentFileChanged:
|
||||
return None
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
import os
|
||||
import stat
|
||||
from pathlib import Path
|
||||
from typing import Callable
|
||||
from typing import Any, Callable
|
||||
|
||||
try:
|
||||
from ...utils.prompt_inspector import (
|
||||
@@ -100,18 +100,23 @@ def inspect_current_file(
|
||||
saved: dict | None,
|
||||
library: dict,
|
||||
image_tags: Callable[[int, int], dict] | None = None,
|
||||
recorded: Callable[[Path], Any] | None = None,
|
||||
) -> dict:
|
||||
"""Current-file evidence read between two equal stats of *path*.
|
||||
|
||||
*image_tags*, when given, is called once with that stable
|
||||
``(st_size, st_mtime_ns)`` and its facet is returned as ``image_tags``
|
||||
(spec amendment S1: tags of a byte record verified at exactly that stat).
|
||||
*recorded*, when given, is asked within the same stat window for what
|
||||
recorded run history knows about *path* (``RecordedOutput`` or None: the
|
||||
save node that wrote it and the texts PromptManager recorded, #386).
|
||||
"""
|
||||
before = _current_file_facts(path)
|
||||
try:
|
||||
inspection = read_inspection_file(path)
|
||||
except MetadataReadError:
|
||||
inspection = None
|
||||
run = recorded(path) if recorded is not None and inspection is not None else None
|
||||
after = _current_file_facts(path)
|
||||
fields = ("st_dev", "st_ino", "st_mode", "st_size", "st_mtime_ns", "st_ctime_ns")
|
||||
if any(getattr(before, key) != getattr(after, key) for key in fields):
|
||||
@@ -129,9 +134,15 @@ def inspect_current_file(
|
||||
profile = (
|
||||
PREVIEW_INSPECTION_PROFILE if _in_host_temp(path) else INSPECTION_PROFILE
|
||||
)
|
||||
# The file name anchors on the saver that wrote it (#381).
|
||||
# The file name anchors on the saver that wrote it (#381); recorded run
|
||||
# history names that saver when the file alone cannot (#386).
|
||||
evidence = inspect_prompt_evidence(
|
||||
inspection.metadata, role_saved, profile=profile, file_name=path.name
|
||||
inspection.metadata,
|
||||
role_saved,
|
||||
profile=profile,
|
||||
file_name=path.name,
|
||||
recorded_saver_id=run.saver_id if run is not None else None,
|
||||
recorded_texts=run.texts if run is not None else None,
|
||||
)
|
||||
return {
|
||||
"file": {
|
||||
|
||||
+16
-1
@@ -47,6 +47,11 @@ import time
|
||||
import uuid
|
||||
from pathlib import PurePosixPath, PureWindowsPath
|
||||
|
||||
try:
|
||||
from ...utils import exit_signal
|
||||
except ImportError: # tests import the package top-level
|
||||
from utils import exit_signal
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
# Start and finish order: wall-clock times can tie (coarse Windows clocks).
|
||||
_sequence = itertools.count()
|
||||
@@ -195,11 +200,21 @@ class Job:
|
||||
self.counters = dict.fromkeys(groups, 0)
|
||||
self.outcomes = {group: [] for group in groups}
|
||||
self.log = []
|
||||
self.cancelled = False
|
||||
self._cancel_requested = False
|
||||
self.last_event = None
|
||||
self.task = None
|
||||
self._subscribers = set()
|
||||
|
||||
@property
|
||||
def cancelled(self):
|
||||
"""Cancel was requested, or the interpreter is exiting (#376): every
|
||||
check a job already makes between files also stops it at exit."""
|
||||
return self._cancel_requested or exit_signal.requested()
|
||||
|
||||
@cancelled.setter
|
||||
def cancelled(self, value):
|
||||
self._cancel_requested = bool(value)
|
||||
|
||||
@property
|
||||
def record_changing(self):
|
||||
return self.admission == "records"
|
||||
|
||||
@@ -92,6 +92,11 @@ try:
|
||||
except ImportError: # tests import the package top-level
|
||||
from utils.parallel import map_parallel, note_refusal, refused_at_shutdown
|
||||
|
||||
try:
|
||||
from ...utils.exit_signal import ExitRequested
|
||||
except ImportError: # tests import the package top-level
|
||||
from utils.exit_signal import ExitRequested
|
||||
|
||||
# The placeholder frame a video without a preview is answered with (JPEG
|
||||
# bytes, never written to disk); written previews follow the settings.
|
||||
PLACEHOLDER_SIZE = (thumbnail_settings.DEFAULT_EDGE, thumbnail_settings.DEFAULT_EDGE)
|
||||
@@ -460,6 +465,8 @@ class AutoThumbnailer:
|
||||
def _run(self):
|
||||
try:
|
||||
self._drain()
|
||||
except ExitRequested:
|
||||
pass # #376: the interpreter is exiting; queued files are dropped
|
||||
except Exception:
|
||||
self._logger.warning("The automatic preview worker stopped", exc_info=True)
|
||||
finally:
|
||||
|
||||
Reference in New Issue
Block a user