Files
tfm_ainventory/venv/lib/python3.12/site-packages/wrapt/arguments.py
Daniel Bedeleanu ea49cd6e4a feat(phase1): add image storage utilities
- Create backend/services/image_storage.py with 4 core functions:
  - sanitize_filename(): remove unsafe chars, limit to 255 chars, convert to lowercase
  - get_unique_filename(): handle collisions with UUID suffix (format: {name}_{uuid8}_{variant}.jpg)
  - ensure_image_directories(): create /images/ root and category subdirs on startup
  - save_image(): save bytes to /images/{category}/{filename}, returns relative path
- Create comprehensive test suite (22 tests) covering all functionality
- Integrate ensure_image_directories() into FastAPI startup event
- Directory structure: /images/{category}/{filename}
- Collision handling: auto-suffix with UUID if filename exists
- All tests passing, pathlib.Path for safe operations
2026-04-20 21:57:26 +03:00

60 lines
2.5 KiB
Python

"""The inspect.formatargspec() function was dropped in Python 3.11 but we need
it for when constructing signature changing decorators based on result of
inspect.getfullargspec(). The code here implements inspect.formatargspec() based
on Parameter and Signature from inspect module, which were added in Python 3.6.
Thanks to Cyril Jouve for the implementation.
"""
from typing import Any, Callable, List, Mapping, Optional, Sequence, Tuple
try:
from inspect import Parameter, Signature
except ImportError:
from inspect import formatargspec # type: ignore[attr-defined]
else:
def formatargspec(
args: List[str],
varargs: Optional[str] = None,
varkw: Optional[str] = None,
defaults: Optional[Tuple[Any, ...]] = None,
kwonlyargs: Optional[Sequence[str]] = None,
kwonlydefaults: Optional[Mapping[str, Any]] = None,
annotations: Mapping[str, Any] = {},
formatarg: Callable[[str], str] = str,
formatvarargs: Callable[[str], str] = lambda name: "*" + name,
formatvarkw: Callable[[str], str] = lambda name: "**" + name,
formatvalue: Callable[[Any], str] = lambda value: "=" + repr(value),
formatreturns: Callable[[Any], str] = lambda text: " -> " + text,
formatannotation: Callable[[Any], str] = lambda annot: " -> " + repr(annot),
) -> str:
if kwonlyargs is None:
kwonlyargs = ()
if kwonlydefaults is None:
kwonlydefaults = {}
ndefaults = len(defaults) if defaults else 0
parameters = [
Parameter(
arg,
Parameter.POSITIONAL_OR_KEYWORD,
default=defaults[i] if defaults and i >= 0 else Parameter.empty,
annotation=annotations.get(arg, Parameter.empty),
)
for i, arg in enumerate(args, ndefaults - len(args))
]
if varargs:
parameters.append(Parameter(varargs, Parameter.VAR_POSITIONAL))
parameters.extend(
Parameter(
kwonlyarg,
Parameter.KEYWORD_ONLY,
default=kwonlydefaults.get(kwonlyarg, Parameter.empty),
annotation=annotations.get(kwonlyarg, Parameter.empty),
)
for kwonlyarg in kwonlyargs
)
if varkw:
parameters.append(Parameter(varkw, Parameter.VAR_KEYWORD))
return_annotation = annotations.get("return", Signature.empty)
return str(Signature(parameters, return_annotation=return_annotation))