{"id":"5d507e95c607c3d0","repo":"pypa/pip","slug":"name-name-r-is-not-normalized","errorCode":null,"errorMessage":"Name {name!r} is not normalized","messagePattern":"Name (.+?) is not normalized","errorType":"validation","errorClass":"PylockValidationError","httpStatus":null,"severity":"error","filePath":"src/pip/_vendor/packaging/pylock.py","lineNumber":232,"sourceCode":"    except Exception as e:\n        raise PylockValidationError(e, context=f\"{key}[{len(result)}]\") from e\n    return result\n\n\ndef _get_required_sequence_of_objects(\n    d: Mapping[str, Any], target_item_type: type[_FromMappingProtocolT], key: str\n) -> Sequence[_FromMappingProtocolT]:\n    \"\"\"Get a required list value from the dictionary and convert its items to a\n    dataclass.\"\"\"\n    if (result := _get_sequence_of_objects(d, target_item_type, key)) is None:\n        raise _PylockRequiredKeyError(key)\n    return result\n\n\ndef _validate_normalized_name(name: str) -> NormalizedName:\n    \"\"\"Validate that a string is a NormalizedName.\"\"\"\n    if not is_normalized_name(name):\n        raise PylockValidationError(f\"Name {name!r} is not normalized\")\n    return NormalizedName(name)\n\n\ndef _validate_path_url(path: str | None, url: str | None) -> None:\n    if not path and not url:\n        raise PylockValidationError(\"path or url must be provided\")\n\n\ndef _path_name(path: str | None) -> str | None:\n    if not path:\n        return None\n    # If the path is relative it MAY use POSIX-style path separators explicitly\n    # for portability\n    if \"/\" in path:\n        return path.rsplit(\"/\", 1)[-1]\n    elif \"\\\\\" in path:\n        return path.rsplit(\"\\\\\", 1)[-1]\n    else:","sourceCodeStart":214,"sourceCodeEnd":250,"githubUrl":"https://github.com/pypa/pip/blob/d7d0d0a39494e28ec1c407bd0680e4a4d1067791/src/pip/_vendor/packaging/pylock.py#L214-L250","documentation":"Raised as PylockValidationError by _validate_normalized_name in packaging.pylock when a package 'name' field is not in PEP 503 normalized form (lowercase, runs of [-_.] collapsed to a single '-', no other characters). pylock requires names already normalized so comparisons are unambiguous.","triggerScenarios":"Loading pylock.toml with name = \\\"My_Package\\\" (underscore), name = \\\"MyPackage\\\" (CamelCase), name = \\\"my..package\\\" (double dot). The normalized form would be 'my-package'.","commonSituations":"Generating a lockfile from project metadata without applying canonicalize_name; mixing normalized and raw names across dependencies; copy-pasting a project name from pyproject [project].name into pylock.","solutions":["Normalize the name with packaging.utils.canonicalize_name before writing it to the lockfile.","Regenerate the lockfile with a tool that emits normalized names.","Replace '_', '.', ' ' with '-' and lowercase the string before passing it.","Catch PylockValidationError and report which name failed normalization."],"exampleFix":"# before\nname = \\\"My_Package\\\"\n# after\nname = \\\"my-package\\\"","handlingStrategy":"validation","validationCode":"from packaging.utils import canonicalize_name\n\ndef is_normalized(name: str) -> bool:\n    return canonicalize_name(name) == name","typeGuard":"import re\n_norm_re = re.compile(r'^[a-z0-9]+(-[a-z0-9]+)*$')\n\ndef is_normalized_name(name: str) -> bool:\n    return bool(_norm_re.match(name))","tryCatchPattern":"from packaging.pylock import PylockValidationError\ntry:\n    PylockFile.from_dict(data)\nexcept PylockValidationError as e:\n    if 'not normalized' in str(e):\n        data['name'] = canonicalize_name(data['name'])","preventionTips":["Apply canonicalize_name before writing names into lockfiles.","Use a resolver that emits normalized names.","Validate names with is_normalized_name before from_dict.","Avoid copy-pasting raw project names."],"tags":["pylock","pep503","name-normalization","pep771"],"analyzedSha":"d7d0d0a39494e28ec1c407bd0680e4a4d1067791","analyzedAt":"2026-08-04T20:55:04.259Z","schemaVersion":2}