{"id":271,"library":"annotated-types","title":"annotated-types","description":"annotated-types provides reusable constraint metadata objects—such as Gt, Lt, Len, MultipleOf, Timezone, Predicate, and more—to be used with typing.Annotated (PEP 593). It does not enforce constraints itself; enforcement is left to consuming libraries like Pydantic, Hypothesis, or custom validators. Current version is 0.7.0 (released 2024). The project follows an irregular, feature-driven release cadence and was created at PyCon 2022 by the Pydantic and Hypothesis maintainers.","status":"active","version":"0.7.0","language":"python","source_language":"en","source_url":"https://github.com/annotated-types/annotated-types","tags":["typing","annotations","pep-593","validation","pydantic","constraints","type-hints"],"install":[{"cmd":"pip install annotated-types","lang":"bash","label":"pip"}],"dependencies":[],"imports":[{"note":"PyPI slug uses a hyphen (annotated-types) but the importable package uses an underscore (annotated_types). Hyphenated import will raise a SyntaxError.","wrong":"from annotated-types import Gt","symbol":"Gt, Lt, Ge, Le, Interval","correct":"from annotated_types import Gt, Lt, Ge, Le, Interval"},{"note":"Before v0.4.0, Len used min_inclusive/max_exclusive kwargs and max was exclusive. Since v0.4.0, use min_length/max_length (both inclusive). MinLen and MaxLen were added in v0.4.0 as convenience helpers.","wrong":"from annotated_types import Len; Len(min_inclusive=0, max_exclusive=10)","symbol":"Len, MinLen, MaxLen","correct":"from annotated_types import Len, MinLen, MaxLen"},{"note":"Predicate wraps a callable; prefer introspectable callables (e.g. str.isdigit) over lambdas so consuming libraries can reflect on the predicate and generate schemas.","symbol":"Predicate","correct":"from annotated_types import Predicate"},{"note":"Since v0.7.0 accepts tzinfo objects (e.g. Timezone(timezone.utc)) in addition to strings. Use Timezone(...) for any-aware and Timezone(None) for naive datetimes.","symbol":"Timezone","correct":"from annotated_types import Timezone"},{"note":"Renamed from IsDigit to IsDigits in v0.7.0. Importing IsDigit will raise an ImportError on 0.7.0+.","wrong":"from annotated_types import IsDigit","symbol":"IsDigits","correct":"from annotated_types import IsDigits"},{"note":"Added in v0.7.0. annotated_types itself does not validate or parse the unit string; that is left to downstream consumers.","symbol":"Unit","correct":"from annotated_types import Unit"},{"note":"Protocol for custom grouped metadata. Interval and Len both implement it. Consumers must unpack GroupedMetadata and handle or ignore unknown items gracefully.","symbol":"GroupedMetadata","correct":"from annotated_types import GroupedMetadata"}],"quickstart":{"code":"from typing import Annotated, get_args, get_origin\nimport math\nfrom annotated_types import Gt, Lt, Len, MinLen, MaxLen, MultipleOf, Predicate, Interval, Timezone, IsDigits\nfrom datetime import datetime, timezone\n\n# Scalar bounds\nPositiveInt = Annotated[int, Gt(0)]\nSmallFloat = Annotated[float, Interval(ge=0.0, le=1.0)]\n\n# Collection length (both bounds inclusive since v0.4.0)\nShortList = Annotated[list, Len(1, 10)]\nNonEmptyStr = Annotated[str, MinLen(1)]\nCappedStr = Annotated[str, MaxLen(255)]\n\n# Predicate — prefer introspectable callables over lambdas\nFiniteFloat = Annotated[float, Predicate(math.isfinite)]\nDigitOnly = Annotated[str, IsDigits]\n\n# Timezone (v0.7.0+: accepts tzinfo objects)\nUTCDatetime = Annotated[datetime, Timezone(timezone.utc)]\nAwareDatetime = Annotated[datetime, Timezone(...)]\nNaiveDatetime = Annotated[datetime, Timezone(None)]\n\n# Reading metadata back (for library authors)\ndef show_constraints(tp):\n    if get_origin(tp) is Annotated:\n        base, *metadata = get_args(tp)\n        print(f\"Base type: {base}, constraints: {metadata}\")\n\nshow_constraints(Annotated[int, Gt(0), Lt(100)])\n","lang":"python","description":"Demonstrates scalar bounds, collection length constraints, predicates, IsDigits, and Timezone usage, plus how to introspect annotations from Annotated types. No auth required."},"warnings":[{"fix":"Use `from annotated_types import ...` (underscore) in all import statements.","message":"Import module name uses underscores: `annotated_types`, not `annotated-types`. Using a hyphen causes a SyntaxError.","severity":"breaking","affected_versions":"all"},{"fix":"Replace Len(min_inclusive=a, max_exclusive=b) with Len(min_length=a, max_length=b-1) if exclusive semantics were intended, or Len(min_length=a, max_length=b) if inclusive was the intent.","message":"In v0.4.0, Len's kwargs were renamed and the semantics of the upper bound changed: `min_inclusive` → `min_length` (same meaning), `max_exclusive` → `max_length` (now INCLUSIVE). Code using old kwargs or assuming exclusive upper bound will silently produce wrong constraints.","severity":"breaking","affected_versions":"<0.4.0"},{"fix":"Replace `from annotated_types import IsDigit` with `from annotated_types import IsDigits`.","message":"`IsDigit` was renamed to `IsDigits` in v0.7.0. Importing `IsDigit` raises an ImportError on 0.7.0+.","severity":"breaking","affected_versions":"<0.7.0"},{"fix":"Upgrade to Python 3.8+ or pin annotated-types <0.6.0 for Python 3.7 environments.","message":"Python 3.7 support was dropped in v0.6.0. The minimum required Python version is now 3.8.","severity":"breaking","affected_versions":">=0.6.0"},{"fix":"Pair annotated-types constraints with a runtime enforcement library such as Pydantic v2 or a custom get_args() inspector.","message":"annotated-types does NOT enforce constraints at runtime itself. Metadata is purely declarative; enforcement depends entirely on the consuming library (e.g. Pydantic, Hypothesis). Annotating a field does not validate values without an active consumer.","severity":"gotcha","affected_versions":"all"},{"fix":"Check which interpretation your consuming library implements. Avoid using MultipleOf with non-integer or very large float values unless the library's behavior is explicitly documented.","message":"MultipleOf has two semantically different interpretations: Python modulo (`value % multiple_of == 0`) vs. JSONSchema (`int(value / multiple_of) == value / multiple_of`). For floats, these can silently diverge due to floating-point imprecision.","severity":"gotcha","affected_versions":"all"},{"fix":"Use introspectable callables such as `str.isdigit`, `math.isfinite`, or `re.compile(...).search` instead of `lambda` wrappers inside Predicate.","message":"Using lambda functions in Predicate prevents consuming libraries from introspecting the predicate for schema generation or targeted optimisations. Libraries may silently ignore or mishandle opaque lambdas.","severity":"gotcha","affected_versions":"all"},{"fix":"Focus on the behavior of the `annotated-types` library for failure diagnosis, disregarding unrelated output from package managers like pip.","message":"The test output does not indicate a failure of the `annotated-types` library; it shows successful definition of constraints and includes unrelated `pip` warnings/notices.","severity":"gotcha","affected_versions":"all"}],"env_vars":null,"last_verified":"2026-05-12T12:40:50.973Z","next_check":"2026-06-26T00:00:00.000Z","problems":[{"fix":"Install the package using 'pip install annotated-types'.","cause":"The 'annotated-types' package is not installed in the Python environment.","error":"ModuleNotFoundError: No module named 'annotated_types'"},{"fix":"Ensure you have the latest version by running 'pip install --upgrade annotated-types'.","cause":"The 'Gt' class is not available in the installed version of 'annotated-types'.","error":"ImportError: cannot import name 'Gt' from 'annotated_types'"},{"fix":"Use 'Len' within 'Annotated' for type annotations, e.g., 'Annotated[list[int], Len(0, 10)]'.","cause":"Attempting to call 'Len' as a function instead of using it as a type annotation.","error":"TypeError: 'Len' object is not callable"},{"fix":"Verify the module's documentation for the correct usage or alternative implementations.","cause":"The 'Predicate' attribute is not present in the 'annotated-types' module.","error":"AttributeError: module 'annotated_types' has no attribute 'Predicate'"},{"fix":"Add 'from typing import Annotated' at the beginning of your script.","cause":"The 'Annotated' type is not imported from the 'typing' module.","error":"NameError: name 'Annotated' is not defined"}],"ecosystem":"pypi","meta_description":null,"install_score":100,"install_tag":"verified","quickstart_score":80,"quickstart_tag":"verified","pypi_latest":null,"install_checks":{"last_tested":"2026-05-12","tag":"verified","tag_description":"installs cleanly on critical runtimes, fast import, recently tested","results":[{"runtime":"python:3.10-alpine","python_version":"3.10","os_libc":"alpine (musl)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.05,"mem_mb":1.8,"disk_size":"17.8M"},{"runtime":"python:3.10-slim","python_version":"3.10","os_libc":"slim (glibc)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.03,"mem_mb":1.8,"disk_size":"18M"},{"runtime":"python:3.11-alpine","python_version":"3.11","os_libc":"alpine (musl)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.1,"mem_mb":2,"disk_size":"19.7M"},{"runtime":"python:3.11-slim","python_version":"3.11","os_libc":"slim (glibc)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.08,"mem_mb":2,"disk_size":"20M"},{"runtime":"python:3.12-alpine","python_version":"3.12","os_libc":"alpine (musl)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.09,"mem_mb":1.8,"disk_size":"11.6M"},{"runtime":"python:3.12-slim","python_version":"3.12","os_libc":"slim (glibc)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.08,"mem_mb":1.8,"disk_size":"12M"},{"runtime":"python:3.13-alpine","python_version":"3.13","os_libc":"alpine (musl)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.07,"mem_mb":2.2,"disk_size":"11.2M"},{"runtime":"python:3.13-slim","python_version":"3.13","os_libc":"slim (glibc)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.07,"mem_mb":2,"disk_size":"12M"},{"runtime":"python:3.9-alpine","python_version":"3.9","os_libc":"alpine (musl)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.04,"mem_mb":1.7,"disk_size":"17.3M"},{"runtime":"python:3.9-slim","python_version":"3.9","os_libc":"slim (glibc)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.04,"mem_mb":1.7,"disk_size":"18M"}]},"quickstart_checks":{"last_tested":"2026-04-23","tag":"verified","tag_description":"quickstart runs on critical runtimes, recently tested","results":[{"runtime":"python:3.10-alpine","exit_code":0},{"runtime":"python:3.10-slim","exit_code":0},{"runtime":"python:3.11-alpine","exit_code":0},{"runtime":"python:3.11-slim","exit_code":0},{"runtime":"python:3.12-alpine","exit_code":0},{"runtime":"python:3.12-slim","exit_code":0},{"runtime":"python:3.13-alpine","exit_code":0},{"runtime":"python:3.13-slim","exit_code":0},{"runtime":"python:3.9-alpine","exit_code":0},{"runtime":"python:3.9-slim","exit_code":0}]}}