feat: Add validate_series_key() validator for key-based identification (Task 4.6)
- Add validate_series_key() function that validates URL-safe, lowercase, hyphen-separated series keys (e.g., 'attack-on-titan') - Add validate_series_key_or_folder() for backward compatibility during transition from folder-based to key-based identification - Create comprehensive test suite with 99 test cases for all validators - Update infrastructure.md with validation utilities documentation - Mark Task 4.6 as complete in instructions.md Test: conda run -n AniWorld python -m pytest tests/unit/test_validators.py -v All 99 validator tests pass, 718 total unit tests pass
This commit is contained in:
@@ -438,6 +438,107 @@ def validate_series_name(name: str) -> str:
|
||||
return name.strip()
|
||||
|
||||
|
||||
def validate_series_key(key: str) -> str:
|
||||
"""
|
||||
Validate series key format.
|
||||
|
||||
Series keys are unique, provider-assigned, URL-safe identifiers.
|
||||
They should be lowercase, use hyphens for word separation, and contain
|
||||
only alphanumeric characters and hyphens.
|
||||
|
||||
Valid examples:
|
||||
- "attack-on-titan"
|
||||
- "one-piece"
|
||||
- "naruto"
|
||||
|
||||
Invalid examples:
|
||||
- "Attack On Titan" (uppercase, spaces)
|
||||
- "attack_on_titan" (underscores)
|
||||
- "attack on titan" (spaces)
|
||||
- "" (empty)
|
||||
|
||||
Args:
|
||||
key: Series key to validate
|
||||
|
||||
Returns:
|
||||
Validated key (trimmed)
|
||||
|
||||
Raises:
|
||||
ValueError: If key is invalid
|
||||
"""
|
||||
if not key or not isinstance(key, str):
|
||||
raise ValueError("Series key must be a non-empty string")
|
||||
|
||||
key = key.strip()
|
||||
|
||||
if not key:
|
||||
raise ValueError("Series key cannot be empty")
|
||||
|
||||
if len(key) > 255:
|
||||
raise ValueError("Series key must be 255 characters or less")
|
||||
|
||||
# Key must be lowercase, alphanumeric with hyphens only
|
||||
# Pattern: starts with letter/number, can contain letters, numbers, hyphens
|
||||
# Cannot start or end with hyphen, no consecutive hyphens
|
||||
if not re.match(r'^[a-z0-9]+(?:-[a-z0-9]+)*$', key):
|
||||
raise ValueError(
|
||||
"Series key must be lowercase, URL-safe, and use hyphens "
|
||||
"for word separation (e.g., 'attack-on-titan'). "
|
||||
"No spaces, underscores, or uppercase letters allowed."
|
||||
)
|
||||
|
||||
return key
|
||||
|
||||
|
||||
def validate_series_key_or_folder(
|
||||
identifier: str, allow_folder: bool = True
|
||||
) -> tuple[str, bool]:
|
||||
"""
|
||||
Validate an identifier that could be either a series key or folder.
|
||||
|
||||
This function provides backward compatibility during the transition
|
||||
from folder-based to key-based identification.
|
||||
|
||||
Args:
|
||||
identifier: The identifier to validate (key or folder)
|
||||
allow_folder: Whether to allow folder-style identifiers (default: True)
|
||||
|
||||
Returns:
|
||||
Tuple of (validated_identifier, is_key) where is_key indicates
|
||||
whether the identifier is a valid key format.
|
||||
|
||||
Raises:
|
||||
ValueError: If identifier is empty or invalid
|
||||
"""
|
||||
if not identifier or not isinstance(identifier, str):
|
||||
raise ValueError("Identifier must be a non-empty string")
|
||||
|
||||
identifier = identifier.strip()
|
||||
|
||||
if not identifier:
|
||||
raise ValueError("Identifier cannot be empty")
|
||||
|
||||
# Try to validate as key first
|
||||
try:
|
||||
validate_series_key(identifier)
|
||||
return identifier, True
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
# If not a valid key, check if folder format is allowed
|
||||
if not allow_folder:
|
||||
raise ValueError(
|
||||
f"Invalid series key format: '{identifier}'. "
|
||||
"Keys must be lowercase with hyphens (e.g., 'attack-on-titan')."
|
||||
)
|
||||
|
||||
# Validate as folder (more permissive)
|
||||
if len(identifier) > 1000:
|
||||
raise ValueError("Identifier too long (max 1000 characters)")
|
||||
|
||||
return identifier, False
|
||||
|
||||
|
||||
def validate_backup_name(name: str) -> str:
|
||||
"""
|
||||
Validate backup file name.
|
||||
|
||||
Reference in New Issue
Block a user