dfdsf
This commit is contained in:
@@ -11,7 +11,7 @@ import sys
|
||||
import inspect
|
||||
from collections.abc import Iterable as IterableABC
|
||||
|
||||
from helper.logger import log, debug
|
||||
from SYS.logger import log, debug
|
||||
from pathlib import Path
|
||||
from typing import Any, Dict, Iterable, List, Optional, Sequence, Set
|
||||
from dataclasses import dataclass, field
|
||||
@@ -149,7 +149,7 @@ class SharedArgs:
|
||||
|
||||
@staticmethod
|
||||
def get_store_choices(config: Optional[Dict[str, Any]] = None) -> List[str]:
|
||||
"""Get list of available storage backend names from FileStorage.
|
||||
"""Get list of available store backend names.
|
||||
|
||||
This method dynamically discovers all configured storage backends
|
||||
instead of using a static list. Should be called when building
|
||||
@@ -162,13 +162,10 @@ class SharedArgs:
|
||||
List of backend names (e.g., ['default', 'test', 'home', 'work'])
|
||||
|
||||
Example:
|
||||
# In a cmdlet that needs dynamic choices
|
||||
from helper.store import FileStorage
|
||||
storage = FileStorage(config)
|
||||
SharedArgs.STORE.choices = SharedArgs.get_store_choices(config)
|
||||
"""
|
||||
try:
|
||||
from helper.store import FileStorage
|
||||
from Store import Store
|
||||
|
||||
# If no config provided, try to load it
|
||||
if config is None:
|
||||
@@ -178,8 +175,8 @@ class SharedArgs:
|
||||
except Exception:
|
||||
return []
|
||||
|
||||
file_storage = FileStorage(config)
|
||||
return file_storage.list_backends()
|
||||
store = Store(config)
|
||||
return store.list_backends()
|
||||
except Exception:
|
||||
# Fallback to empty list if FileStorage isn't available
|
||||
return []
|
||||
@@ -609,7 +606,7 @@ def normalize_hash(hash_hex: Optional[str]) -> Optional[str]:
|
||||
return text.lower() if text else None
|
||||
|
||||
|
||||
def get_hash_for_operation(override_hash: Optional[str], result: Any, field_name: str = "hash_hex") -> Optional[str]:
|
||||
def get_hash_for_operation(override_hash: Optional[str], result: Any, field_name: str = "hash") -> Optional[str]:
|
||||
"""Get normalized hash from override or result object, consolidating common pattern.
|
||||
|
||||
Eliminates repeated pattern: normalize_hash(override) if override else normalize_hash(get_field(result, ...))
|
||||
@@ -617,15 +614,14 @@ def get_hash_for_operation(override_hash: Optional[str], result: Any, field_name
|
||||
Args:
|
||||
override_hash: Hash passed as command argument (takes precedence)
|
||||
result: Object containing hash field (fallback)
|
||||
field_name: Name of hash field in result object (default: "hash_hex")
|
||||
field_name: Name of hash field in result object (default: "hash")
|
||||
|
||||
Returns:
|
||||
Normalized hash string, or None if neither override nor result provides valid hash
|
||||
"""
|
||||
if override_hash:
|
||||
return normalize_hash(override_hash)
|
||||
# Try multiple field names for robustness
|
||||
hash_value = get_field(result, field_name) or getattr(result, field_name, None) or getattr(result, "hash", None) or result.get("file_hash") if isinstance(result, dict) else None
|
||||
hash_value = get_field(result, field_name) or getattr(result, field_name, None) or getattr(result, "hash", None)
|
||||
return normalize_hash(hash_value)
|
||||
|
||||
|
||||
@@ -645,8 +641,8 @@ def fetch_hydrus_metadata(config: Any, hash_hex: str, **kwargs) -> tuple[Optiona
|
||||
- metadata_dict: Dict from Hydrus (first item in metadata list) or None if unavailable
|
||||
- error_code: 0 on success, 1 on any error (suitable for returning from cmdlet execute())
|
||||
"""
|
||||
from helper import hydrus
|
||||
hydrus_wrapper = hydrus
|
||||
from API import HydrusNetwork
|
||||
hydrus_wrapper = HydrusNetwork
|
||||
|
||||
try:
|
||||
client = hydrus_wrapper.get_client(config)
|
||||
@@ -670,24 +666,6 @@ def fetch_hydrus_metadata(config: Any, hash_hex: str, **kwargs) -> tuple[Optiona
|
||||
return meta, 0
|
||||
|
||||
|
||||
def get_origin(obj: Any, default: Optional[str] = None) -> Optional[str]:
|
||||
"""Extract origin field with fallback to store/source field, consolidating common pattern.
|
||||
|
||||
Supports both dict and object access patterns.
|
||||
|
||||
Args:
|
||||
obj: Object (dict or dataclass) with 'store', 'origin', or 'source' field
|
||||
default: Default value if none of the fields are found
|
||||
|
||||
Returns:
|
||||
Store/origin/source string, or default if none exist
|
||||
"""
|
||||
if isinstance(obj, dict):
|
||||
return obj.get("store") or obj.get("origin") or obj.get("source") or default
|
||||
else:
|
||||
return getattr(obj, "store", None) or getattr(obj, "origin", None) or getattr(obj, "source", None) or default
|
||||
|
||||
|
||||
def get_field(obj: Any, field: str, default: Optional[Any] = None) -> Any:
|
||||
"""Extract a field from either a dict or object with fallback default.
|
||||
|
||||
@@ -706,56 +684,19 @@ def get_field(obj: Any, field: str, default: Optional[Any] = None) -> Any:
|
||||
|
||||
Examples:
|
||||
get_field(result, "hash") # From dict or object
|
||||
get_field(result, "origin", "unknown") # With default
|
||||
get_field(result, "table", "unknown") # With default
|
||||
"""
|
||||
# Handle lists by accessing the first element
|
||||
if isinstance(obj, list) and obj:
|
||||
obj = obj[0]
|
||||
|
||||
if isinstance(obj, dict):
|
||||
# Direct lookup first
|
||||
val = obj.get(field, default)
|
||||
if val is not None:
|
||||
return val
|
||||
# Fallback aliases for common fields
|
||||
if field == "path":
|
||||
for alt in ("file_path", "target", "filepath", "file"):
|
||||
v = obj.get(alt)
|
||||
if v:
|
||||
return v
|
||||
if field == "hash":
|
||||
for alt in ("file_hash", "hash_hex"):
|
||||
v = obj.get(alt)
|
||||
if v:
|
||||
return v
|
||||
if field == "store":
|
||||
for alt in ("storage", "storage_source", "origin"):
|
||||
v = obj.get(alt)
|
||||
if v:
|
||||
return v
|
||||
return default
|
||||
return obj.get(field, default)
|
||||
else:
|
||||
# Try direct attribute access first
|
||||
value = getattr(obj, field, None)
|
||||
if value is not None:
|
||||
return value
|
||||
|
||||
# Attribute fallback aliases for common fields
|
||||
if field == "path":
|
||||
for alt in ("file_path", "target", "filepath", "file", "url"):
|
||||
v = getattr(obj, alt, None)
|
||||
if v:
|
||||
return v
|
||||
if field == "hash":
|
||||
for alt in ("file_hash", "hash_hex"):
|
||||
v = getattr(obj, alt, None)
|
||||
if v:
|
||||
return v
|
||||
if field == "store":
|
||||
for alt in ("storage", "storage_source", "origin"):
|
||||
v = getattr(obj, alt, None)
|
||||
if v:
|
||||
return v
|
||||
|
||||
# For PipeObjects, also check the extra field
|
||||
if hasattr(obj, 'extra') and isinstance(obj.extra, dict):
|
||||
@@ -1148,7 +1089,7 @@ def create_pipe_object_result(
|
||||
file_path: str,
|
||||
cmdlet_name: str,
|
||||
title: Optional[str] = None,
|
||||
file_hash: Optional[str] = None,
|
||||
hash_value: Optional[str] = None,
|
||||
is_temp: bool = False,
|
||||
parent_hash: Optional[str] = None,
|
||||
tags: Optional[List[str]] = None,
|
||||
@@ -1165,7 +1106,7 @@ def create_pipe_object_result(
|
||||
file_path: Path to the file
|
||||
cmdlet_name: Name of the cmdlet that created this (e.g., 'download-data', 'screen-shot')
|
||||
title: Human-readable title
|
||||
file_hash: SHA-256 hash of file (for integrity)
|
||||
hash_value: SHA-256 hash of file (for integrity)
|
||||
is_temp: If True, this is a temporary/intermediate artifact
|
||||
parent_hash: Hash of the parent file in the chain (for provenance)
|
||||
tags: List of tags to apply
|
||||
@@ -1183,13 +1124,12 @@ def create_pipe_object_result(
|
||||
|
||||
if title:
|
||||
result['title'] = title
|
||||
if file_hash:
|
||||
result['file_hash'] = file_hash
|
||||
result['hash'] = file_hash
|
||||
if hash_value:
|
||||
result['hash'] = hash_value
|
||||
if is_temp:
|
||||
result['is_temp'] = True
|
||||
if parent_hash:
|
||||
result['parent_id'] = parent_hash # parent_id is the parent's file_hash
|
||||
result['parent_hash'] = parent_hash
|
||||
if tags:
|
||||
result['tags'] = tags
|
||||
|
||||
@@ -1219,17 +1159,17 @@ def mark_as_temp(pipe_object: Dict[str, Any]) -> Dict[str, Any]:
|
||||
return pipe_object
|
||||
|
||||
|
||||
def set_parent_id(pipe_object: Dict[str, Any], parent_hash: str) -> Dict[str, Any]:
|
||||
"""Set the parent_id for provenance tracking.
|
||||
def set_parent_hash(pipe_object: Dict[str, Any], parent_hash: str) -> Dict[str, Any]:
|
||||
"""Set the parent_hash for provenance tracking.
|
||||
|
||||
Args:
|
||||
pipe_object: Result dict
|
||||
parent_hash: Parent file's hash
|
||||
|
||||
Returns:
|
||||
Modified dict with parent_id set to the hash
|
||||
Modified dict with parent_hash set to the hash
|
||||
"""
|
||||
pipe_object['parent_id'] = parent_hash
|
||||
pipe_object['parent_hash'] = parent_hash
|
||||
return pipe_object
|
||||
|
||||
|
||||
@@ -1254,13 +1194,13 @@ def get_pipe_object_hash(pipe_object: Any) -> Optional[str]:
|
||||
"""Extract file hash from PipeObject, dict, or pipeline-friendly object."""
|
||||
if pipe_object is None:
|
||||
return None
|
||||
for attr in ('file_hash', 'hash_hex', 'hash'):
|
||||
for attr in ('hash',):
|
||||
if hasattr(pipe_object, attr):
|
||||
value = getattr(pipe_object, attr)
|
||||
if value:
|
||||
return value
|
||||
if isinstance(pipe_object, dict):
|
||||
for key in ('file_hash', 'hash_hex', 'hash'):
|
||||
for key in ('hash',):
|
||||
value = pipe_object.get(key)
|
||||
if value:
|
||||
return value
|
||||
@@ -1522,13 +1462,12 @@ def coerce_to_pipe_object(value: Any, default_path: Optional[str] = None) -> mod
|
||||
"""
|
||||
# Debug: Print ResultItem details if coming from search_file.py
|
||||
try:
|
||||
from helper.logger import is_debug_enabled, debug
|
||||
from SYS.logger import is_debug_enabled, debug
|
||||
if is_debug_enabled() and hasattr(value, '__class__') and value.__class__.__name__ == 'ResultItem':
|
||||
debug("[ResultItem -> PipeObject conversion]")
|
||||
debug(f" origin={getattr(value, 'origin', None)}")
|
||||
debug(f" title={getattr(value, 'title', None)}")
|
||||
debug(f" target={getattr(value, 'target', None)}")
|
||||
debug(f" hash_hex={getattr(value, 'hash_hex', None)}")
|
||||
debug(f" hash={getattr(value, 'hash', None)}")
|
||||
debug(f" media_kind={getattr(value, 'media_kind', None)}")
|
||||
debug(f" tags={getattr(value, 'tags', None)}")
|
||||
debug(f" tag_summary={getattr(value, 'tag_summary', None)}")
|
||||
@@ -1554,14 +1493,11 @@ def coerce_to_pipe_object(value: Any, default_path: Optional[str] = None) -> mod
|
||||
|
||||
if isinstance(value, dict):
|
||||
# Extract hash and store (canonical identifiers)
|
||||
hash_val = value.get("hash") or value.get("file_hash")
|
||||
# Recognize multiple possible store naming conventions (store, origin, storage, storage_source)
|
||||
store_val = value.get("store") or value.get("origin") or value.get("storage") or value.get("storage_source") or "PATH"
|
||||
# If the store value is embedded under extra, also detect it
|
||||
if not store_val or store_val in ("local", "PATH"):
|
||||
extra_store = None
|
||||
hash_val = value.get("hash")
|
||||
store_val = value.get("store") or "PATH"
|
||||
if not store_val or store_val == "PATH":
|
||||
try:
|
||||
extra_store = value.get("extra", {}).get("store") or value.get("extra", {}).get("storage") or value.get("extra", {}).get("storage_source")
|
||||
extra_store = value.get("extra", {}).get("store")
|
||||
except Exception:
|
||||
extra_store = None
|
||||
if extra_store:
|
||||
@@ -1572,7 +1508,7 @@ def coerce_to_pipe_object(value: Any, default_path: Optional[str] = None) -> mod
|
||||
path_val = value.get("path")
|
||||
if path_val:
|
||||
try:
|
||||
from helper.utils import sha256_file
|
||||
from SYS.utils import sha256_file
|
||||
from pathlib import Path
|
||||
hash_val = sha256_file(Path(path_val))
|
||||
except Exception:
|
||||
@@ -1655,7 +1591,7 @@ def coerce_to_pipe_object(value: Any, default_path: Optional[str] = None) -> mod
|
||||
relationships=rels,
|
||||
is_temp=bool(value.get("is_temp", False)),
|
||||
action=value.get("action"),
|
||||
parent_hash=value.get("parent_hash") or value.get("parent_id"),
|
||||
parent_hash=value.get("parent_hash"),
|
||||
extra=extra,
|
||||
)
|
||||
|
||||
@@ -1671,7 +1607,7 @@ def coerce_to_pipe_object(value: Any, default_path: Optional[str] = None) -> mod
|
||||
|
||||
if path_val and path_val != "unknown":
|
||||
try:
|
||||
from helper.utils import sha256_file
|
||||
from SYS.utils import sha256_file
|
||||
from pathlib import Path
|
||||
path_obj = Path(path_val)
|
||||
hash_val = sha256_file(path_obj)
|
||||
@@ -1714,7 +1650,7 @@ def register_url_with_local_library(pipe_obj: models.PipeObject, config: Dict[st
|
||||
|
||||
try:
|
||||
from config import get_local_storage_path
|
||||
from helper.folder_store import FolderDB
|
||||
from API.folder import API_folder_store
|
||||
|
||||
file_path = get_field(pipe_obj, "path")
|
||||
url_field = get_field(pipe_obj, "url", [])
|
||||
@@ -1735,7 +1671,7 @@ def register_url_with_local_library(pipe_obj: models.PipeObject, config: Dict[st
|
||||
if not storage_path:
|
||||
return False
|
||||
|
||||
with FolderDB(storage_path) as db:
|
||||
with API_folder_store(storage_path) as db:
|
||||
file_hash = db.get_file_hash(path_obj)
|
||||
if not file_hash:
|
||||
return False
|
||||
|
||||
Reference in New Issue
Block a user