From 2c364ce563586a1eb16f00f7e1a066f87c53f8aa Mon Sep 17 00:00:00 2001 From: Viicos <65306057+Viicos@users.noreply.github.com> Date: Mon, 4 Mar 2024 09:31:05 +0100 Subject: [PATCH 1/3] Use PEP 570 syntax --- pydantic/_internal/_dataclasses.py | 4 +- pydantic/_internal/_decorators.py | 8 +- pydantic/_internal/_generics.py | 8 +- .../_internal/_schema_generation_shared.py | 12 +-- pydantic/_internal/_std_types_schema.py | 4 +- pydantic/_internal/_utils.py | 8 +- pydantic/_internal/_validators.py | 95 ++++++++++--------- pydantic/annotated_handlers.py | 20 ++-- pydantic/fields.py | 9 +- pydantic/functional_serializers.py | 18 ++-- pydantic/functional_validators.py | 15 +-- pydantic/main.py | 19 ++-- pydantic/networks.py | 24 ++--- pydantic/type_adapter.py | 42 ++++---- pydantic/types.py | 10 +- pydantic/validate_call_decorator.py | 11 ++- tests/benchmarks/basemodel_eq_performance.py | 8 +- tests/test_validators.py | 4 +- 18 files changed, 166 insertions(+), 153 deletions(-) diff --git a/pydantic/_internal/_dataclasses.py b/pydantic/_internal/_dataclasses.py index a3f764ed54..db200f4bdf 100644 --- a/pydantic/_internal/_dataclasses.py +++ b/pydantic/_internal/_dataclasses.py @@ -185,8 +185,8 @@ def __init__(__dataclass_self__: PydanticDataclass, *args: Any, **kwargs: Any) - if config_wrapper.validate_assignment: @wraps(cls.__setattr__) - def validated_setattr(instance: Any, __field: str, __value: str) -> None: - validator.validate_assignment(instance, __field, __value) + def validated_setattr(instance: Any, field: str, value: str, /) -> None: + validator.validate_assignment(instance, field, value) cls.__setattr__ = validated_setattr.__get__(None, cls) # type: ignore diff --git a/pydantic/_internal/_decorators.py b/pydantic/_internal/_decorators.py index 5672464cea..8507e4a243 100644 --- a/pydantic/_internal/_decorators.py +++ b/pydantic/_internal/_decorators.py @@ -635,18 +635,18 @@ def inspect_model_serializer(serializer: Callable[..., Any], mode: Literal['plai def _serializer_info_arg(mode: Literal['plain', 'wrap'], n_positional: int) -> bool | None: if mode == 'plain': if n_positional == 1: - # (__input_value: Any) -> Any + # (input_value: Any, /) -> Any return False elif n_positional == 2: - # (__model: Any, __input_value: Any) -> Any + # (model: Any, input_value: Any, /) -> Any return True else: assert mode == 'wrap', f"invalid mode: {mode!r}, expected 'plain' or 'wrap'" if n_positional == 2: - # (__input_value: Any, __serializer: SerializerFunctionWrapHandler) -> Any + # (input_value: Any, serializer: SerializerFunctionWrapHandler, /) -> Any return False elif n_positional == 3: - # (__input_value: Any, __serializer: SerializerFunctionWrapHandler, __info: SerializationInfo) -> Any + # (input_value: Any, serializer: SerializerFunctionWrapHandler, info: SerializationInfo, /) -> Any return True return None diff --git a/pydantic/_internal/_generics.py b/pydantic/_internal/_generics.py index 5a66eaa957..a24763a07b 100644 --- a/pydantic/_internal/_generics.py +++ b/pydantic/_internal/_generics.py @@ -52,13 +52,13 @@ def __init__(self, size_limit: int = _LIMITED_DICT_SIZE): self.size_limit = size_limit super().__init__() - def __setitem__(self, __key: Any, __value: Any) -> None: - super().__setitem__(__key, __value) + def __setitem__(self, key: Any, value: Any, /) -> None: + super().__setitem__(key, value) if len(self) > self.size_limit: excess = len(self) - self.size_limit + self.size_limit // 10 to_remove = list(self.keys())[:excess] - for key in to_remove: - del self[key] + for k in to_remove: + del self[k] # weak dictionaries allow the dynamically created parametrized versions of generic models to get collected diff --git a/pydantic/_internal/_schema_generation_shared.py b/pydantic/_internal/_schema_generation_shared.py index 1a9aa852c3..2cf01c669f 100644 --- a/pydantic/_internal/_schema_generation_shared.py +++ b/pydantic/_internal/_schema_generation_shared.py @@ -32,8 +32,8 @@ def __init__(self, generate_json_schema: GenerateJsonSchema, handler_override: H self.handler = handler_override or generate_json_schema.generate_inner self.mode = generate_json_schema.mode - def __call__(self, __core_schema: CoreSchemaOrField) -> JsonSchemaValue: - return self.handler(__core_schema) + def __call__(self, core_schema: CoreSchemaOrField, /) -> JsonSchemaValue: + return self.handler(core_schema) def resolve_ref_schema(self, maybe_ref_json_schema: JsonSchemaValue) -> JsonSchemaValue: """Resolves `$ref` in the json schema. @@ -78,8 +78,8 @@ def __init__( self._generate_schema = generate_schema self._ref_mode = ref_mode - def __call__(self, __source_type: Any) -> core_schema.CoreSchema: - schema = self._handler(__source_type) + def __call__(self, source_type: Any, /) -> core_schema.CoreSchema: + schema = self._handler(source_type) ref = schema.get('ref') if self._ref_mode == 'to-def': if ref is not None: @@ -92,8 +92,8 @@ def __call__(self, __source_type: Any) -> core_schema.CoreSchema: def _get_types_namespace(self) -> dict[str, Any] | None: return self._generate_schema._types_namespace - def generate_schema(self, __source_type: Any) -> core_schema.CoreSchema: - return self._generate_schema.generate_schema(__source_type) + def generate_schema(self, source_type: Any, /) -> core_schema.CoreSchema: + return self._generate_schema.generate_schema(source_type) @property def field_name(self) -> str | None: diff --git a/pydantic/_internal/_std_types_schema.py b/pydantic/_internal/_std_types_schema.py index 814c608d8a..5c61d8f058 100644 --- a/pydantic/_internal/_std_types_schema.py +++ b/pydantic/_internal/_std_types_schema.py @@ -86,9 +86,9 @@ def get_json_schema(_, handler: GetJsonSchemaHandler) -> JsonSchemaValue: else: expected = ', '.join([repr(case.value) for case in cases[:-1]]) + f' or {cases[-1].value!r}' - def to_enum(__input_value: Any) -> Enum: + def to_enum(input_value: Any, /) -> Enum: try: - return enum_type(__input_value) + return enum_type(input_value) except ValueError: # The type: ignore on the next line is to ignore the requirement of LiteralString raise PydanticCustomError('enum', f'Input should be {expected}', {'expected': expected}) # type: ignore diff --git a/pydantic/_internal/_utils.py b/pydantic/_internal/_utils.py index 31f5b2c5e3..ef8b32df6d 100644 --- a/pydantic/_internal/_utils.py +++ b/pydantic/_internal/_utils.py @@ -349,8 +349,8 @@ class SafeGetItemProxy: wrapped: Mapping[str, Any] - def __getitem__(self, __key: str) -> Any: - return self.wrapped.get(__key, _SENTINEL) + def __getitem__(self, key: str, /) -> Any: + return self.wrapped.get(key, _SENTINEL) # required to pass the object to operator.itemgetter() instances due to a quirk of typeshed # https://github.com/python/mypy/issues/13713 @@ -358,5 +358,5 @@ def __getitem__(self, __key: str) -> Any: # Since this is typing-only, hide it in a typing.TYPE_CHECKING block if typing.TYPE_CHECKING: - def __contains__(self, __key: str) -> bool: - return self.wrapped.__contains__(__key) + def __contains__(self, key: str, /) -> bool: + return self.wrapped.__contains__(key) diff --git a/pydantic/_internal/_validators.py b/pydantic/_internal/_validators.py index ee6007cefd..6eb9953a88 100644 --- a/pydantic/_internal/_validators.py +++ b/pydantic/_internal/_validators.py @@ -16,11 +16,12 @@ def sequence_validator( - __input_value: typing.Sequence[Any], + input_value: typing.Sequence[Any], + /, validator: core_schema.ValidatorFunctionWrapHandler, ) -> typing.Sequence[Any]: """Validator for `Sequence` types, isinstance(v, Sequence) has already been called.""" - value_type = type(__input_value) + value_type = type(input_value) # We don't accept any plain string as a sequence # Relevant issue: https://github.com/pydantic/pydantic/issues/5595 @@ -37,9 +38,9 @@ def sequence_validator( # SequenceValidator in _std_types_schema.py (preferably this one, while porting over some logic). # Effectively, a refactor for sequence validation is needed. if value_type == tuple: - __input_value = list(__input_value) + input_value = list(input_value) - v_list = validator(__input_value) + v_list = validator(input_value) # the rest of the logic is just re-creating the original type from `v_list` if value_type == list: @@ -116,39 +117,39 @@ def _import_string_logic(dotted_path: str) -> Any: return module -def pattern_either_validator(__input_value: Any) -> typing.Pattern[Any]: - if isinstance(__input_value, typing.Pattern): - return __input_value - elif isinstance(__input_value, (str, bytes)): +def pattern_either_validator(input_value: Any, /) -> typing.Pattern[Any]: + if isinstance(input_value, typing.Pattern): + return input_value + elif isinstance(input_value, (str, bytes)): # todo strict mode - return compile_pattern(__input_value) # type: ignore + return compile_pattern(input_value) # type: ignore else: raise PydanticCustomError('pattern_type', 'Input should be a valid pattern') -def pattern_str_validator(__input_value: Any) -> typing.Pattern[str]: - if isinstance(__input_value, typing.Pattern): - if isinstance(__input_value.pattern, str): - return __input_value +def pattern_str_validator(input_value: Any, /) -> typing.Pattern[str]: + if isinstance(input_value, typing.Pattern): + if isinstance(input_value.pattern, str): + return input_value else: raise PydanticCustomError('pattern_str_type', 'Input should be a string pattern') - elif isinstance(__input_value, str): - return compile_pattern(__input_value) - elif isinstance(__input_value, bytes): + elif isinstance(input_value, str): + return compile_pattern(input_value) + elif isinstance(input_value, bytes): raise PydanticCustomError('pattern_str_type', 'Input should be a string pattern') else: raise PydanticCustomError('pattern_type', 'Input should be a valid pattern') -def pattern_bytes_validator(__input_value: Any) -> typing.Pattern[bytes]: - if isinstance(__input_value, typing.Pattern): - if isinstance(__input_value.pattern, bytes): - return __input_value +def pattern_bytes_validator(input_value: Any, /) -> typing.Pattern[bytes]: + if isinstance(input_value, typing.Pattern): + if isinstance(input_value.pattern, bytes): + return input_value else: raise PydanticCustomError('pattern_bytes_type', 'Input should be a bytes pattern') - elif isinstance(__input_value, bytes): - return compile_pattern(__input_value) - elif isinstance(__input_value, str): + elif isinstance(input_value, bytes): + return compile_pattern(input_value) + elif isinstance(input_value, str): raise PydanticCustomError('pattern_bytes_type', 'Input should be a bytes pattern') else: raise PydanticCustomError('pattern_type', 'Input should be a valid pattern') @@ -164,72 +165,72 @@ def compile_pattern(pattern: PatternType) -> typing.Pattern[PatternType]: raise PydanticCustomError('pattern_regex', 'Input should be a valid regular expression') -def ip_v4_address_validator(__input_value: Any) -> IPv4Address: - if isinstance(__input_value, IPv4Address): - return __input_value +def ip_v4_address_validator(input_value: Any, /) -> IPv4Address: + if isinstance(input_value, IPv4Address): + return input_value try: - return IPv4Address(__input_value) + return IPv4Address(input_value) except ValueError: raise PydanticCustomError('ip_v4_address', 'Input is not a valid IPv4 address') -def ip_v6_address_validator(__input_value: Any) -> IPv6Address: - if isinstance(__input_value, IPv6Address): - return __input_value +def ip_v6_address_validator(input_value: Any, /) -> IPv6Address: + if isinstance(input_value, IPv6Address): + return input_value try: - return IPv6Address(__input_value) + return IPv6Address(input_value) except ValueError: raise PydanticCustomError('ip_v6_address', 'Input is not a valid IPv6 address') -def ip_v4_network_validator(__input_value: Any) -> IPv4Network: +def ip_v4_network_validator(input_value: Any, /) -> IPv4Network: """Assume IPv4Network initialised with a default `strict` argument. See more: https://docs.python.org/library/ipaddress.html#ipaddress.IPv4Network """ - if isinstance(__input_value, IPv4Network): - return __input_value + if isinstance(input_value, IPv4Network): + return input_value try: - return IPv4Network(__input_value) + return IPv4Network(input_value) except ValueError: raise PydanticCustomError('ip_v4_network', 'Input is not a valid IPv4 network') -def ip_v6_network_validator(__input_value: Any) -> IPv6Network: +def ip_v6_network_validator(input_value: Any, /) -> IPv6Network: """Assume IPv6Network initialised with a default `strict` argument. See more: https://docs.python.org/library/ipaddress.html#ipaddress.IPv6Network """ - if isinstance(__input_value, IPv6Network): - return __input_value + if isinstance(input_value, IPv6Network): + return input_value try: - return IPv6Network(__input_value) + return IPv6Network(input_value) except ValueError: raise PydanticCustomError('ip_v6_network', 'Input is not a valid IPv6 network') -def ip_v4_interface_validator(__input_value: Any) -> IPv4Interface: - if isinstance(__input_value, IPv4Interface): - return __input_value +def ip_v4_interface_validator(input_value: Any, /) -> IPv4Interface: + if isinstance(input_value, IPv4Interface): + return input_value try: - return IPv4Interface(__input_value) + return IPv4Interface(input_value) except ValueError: raise PydanticCustomError('ip_v4_interface', 'Input is not a valid IPv4 interface') -def ip_v6_interface_validator(__input_value: Any) -> IPv6Interface: - if isinstance(__input_value, IPv6Interface): - return __input_value +def ip_v6_interface_validator(input_value: Any, /) -> IPv6Interface: + if isinstance(input_value, IPv6Interface): + return input_value try: - return IPv6Interface(__input_value) + return IPv6Interface(input_value) except ValueError: raise PydanticCustomError('ip_v6_interface', 'Input is not a valid IPv6 interface') diff --git a/pydantic/annotated_handlers.py b/pydantic/annotated_handlers.py index 081949a8d1..b1a4487286 100644 --- a/pydantic/annotated_handlers.py +++ b/pydantic/annotated_handlers.py @@ -28,7 +28,7 @@ class GetJsonSchemaHandler: mode: JsonSchemaMode - def __call__(self, __core_schema: CoreSchemaOrField) -> JsonSchemaValue: + def __call__(self, core_schema: CoreSchemaOrField, /) -> JsonSchemaValue: """Call the inner handler and get the JsonSchemaValue it returns. This will call the next JSON schema modifying function up until it calls into `pydantic.json_schema.GenerateJsonSchema`, which will raise a @@ -36,7 +36,7 @@ def __call__(self, __core_schema: CoreSchemaOrField) -> JsonSchemaValue: a JSON schema. Args: - __core_schema: A `pydantic_core.core_schema.CoreSchema`. + core_schema: A `pydantic_core.core_schema.CoreSchema`. Returns: JsonSchemaValue: The JSON schema generated by the inner JSON schema modify @@ -44,13 +44,13 @@ def __call__(self, __core_schema: CoreSchemaOrField) -> JsonSchemaValue: """ raise NotImplementedError - def resolve_ref_schema(self, __maybe_ref_json_schema: JsonSchemaValue) -> JsonSchemaValue: + def resolve_ref_schema(self, maybe_ref_json_schema: JsonSchemaValue, /) -> JsonSchemaValue: """Get the real schema for a `{"$ref": ...}` schema. If the schema given is not a `$ref` schema, it will be returned as is. This means you don't have to check before calling this function. Args: - __maybe_ref_json_schema: A JsonSchemaValue which may be a `$ref` schema. + maybe_ref_json_schema: A JsonSchemaValue which may be a `$ref` schema. Raises: LookupError: If the ref is not found. @@ -64,7 +64,7 @@ def resolve_ref_schema(self, __maybe_ref_json_schema: JsonSchemaValue) -> JsonSc class GetCoreSchemaHandler: """Handler to call into the next CoreSchema schema generation function.""" - def __call__(self, __source_type: Any) -> core_schema.CoreSchema: + def __call__(self, source_type: Any, /) -> core_schema.CoreSchema: """Call the inner handler and get the CoreSchema it returns. This will call the next CoreSchema modifying function up until it calls into Pydantic's internal schema generation machinery, which will raise a @@ -72,14 +72,14 @@ def __call__(self, __source_type: Any) -> core_schema.CoreSchema: a CoreSchema for the given source type. Args: - __source_type: The input type. + source_type: The input type. Returns: CoreSchema: The `pydantic-core` CoreSchema generated. """ raise NotImplementedError - def generate_schema(self, __source_type: Any) -> core_schema.CoreSchema: + def generate_schema(self, source_type: Any, /) -> core_schema.CoreSchema: """Generate a schema unrelated to the current context. Use this function if e.g. you are handling schema generation for a sequence and want to generate a schema for its items. @@ -87,20 +87,20 @@ def generate_schema(self, __source_type: Any) -> core_schema.CoreSchema: that was intended for the sequence itself to its items! Args: - __source_type: The input type. + source_type: The input type. Returns: CoreSchema: The `pydantic-core` CoreSchema generated. """ raise NotImplementedError - def resolve_ref_schema(self, __maybe_ref_schema: core_schema.CoreSchema) -> core_schema.CoreSchema: + def resolve_ref_schema(self, maybe_ref_schema: core_schema.CoreSchema, /) -> core_schema.CoreSchema: """Get the real schema for a `definition-ref` schema. If the schema given is not a `definition-ref` schema, it will be returned as is. This means you don't have to check before calling this function. Args: - __maybe_ref_schema: A `CoreSchema`, `ref`-based or not. + maybe_ref_schema: A `CoreSchema`, `ref`-based or not. Raises: LookupError: If the `ref` is not found. diff --git a/pydantic/fields.py b/pydantic/fields.py index 6007c0e9fb..1f345bf75f 100644 --- a/pydantic/fields.py +++ b/pydantic/fields.py @@ -1035,7 +1035,8 @@ def computed_field(__func: PropertyT) -> PropertyT: def computed_field( - __f: PropertyT | None = None, + func: PropertyT | None = None, + /, *, alias: str | None = None, alias_priority: int | None = None, @@ -1166,7 +1167,7 @@ def _private_property(self) -> int: ``` Args: - __f: the function to wrap. + func: the function to wrap. alias: alias to use when serializing this computed field, only used when `by_alias=True` alias_priority: priority of the alias. This affects whether an alias generator is used title: Title to use when including this computed field in JSON Schema @@ -1221,7 +1222,7 @@ def dec(f: Any) -> Any: ) return _decorators.PydanticDescriptorProxy(f, dec_info) - if __f is None: + if func is None: return dec else: - return dec(__f) + return dec(func) diff --git a/pydantic/functional_serializers.py b/pydantic/functional_serializers.py index 6e31bf6759..1a9e556363 100644 --- a/pydantic/functional_serializers.py +++ b/pydantic/functional_serializers.py @@ -184,7 +184,8 @@ def __get_pydantic_core_schema__(self, source_type: Any, handler: GetCoreSchemaH @overload def field_serializer( - __field: str, + field: str, + /, *fields: str, return_type: Any = ..., when_used: Literal['always', 'unless-none', 'json', 'json-unless-none'] = ..., @@ -195,7 +196,8 @@ def field_serializer( @overload def field_serializer( - __field: str, + field: str, + /, *fields: str, mode: Literal['plain'], return_type: Any = ..., @@ -207,7 +209,8 @@ def field_serializer( @overload def field_serializer( - __field: str, + field: str, + /, *fields: str, mode: Literal['wrap'], return_type: Any = ..., @@ -304,7 +307,8 @@ def model_serializer( def model_serializer( - __f: Callable[..., Any] | None = None, + f: Callable[..., Any] | None = None, + /, *, mode: Literal['plain', 'wrap'] = 'plain', when_used: Literal['always', 'unless-none', 'json', 'json-unless-none'] = 'always', @@ -339,7 +343,7 @@ def serialize_model(self): See [Custom serializers](../concepts/serialization.md#custom-serializers) for more information. Args: - __f: The function to be decorated. + f: The function to be decorated. mode: The serialization mode. - `'plain'` means the function will be called instead of the default serialization logic @@ -356,10 +360,10 @@ def dec(f: Callable[..., Any]) -> _decorators.PydanticDescriptorProxy[Any]: dec_info = _decorators.ModelSerializerDecoratorInfo(mode=mode, return_type=return_type, when_used=when_used) return _decorators.PydanticDescriptorProxy(f, dec_info) - if __f is None: + if f is None: return dec else: - return dec(__f) # type: ignore + return dec(f) # type: ignore AnyType = TypeVar('AnyType') diff --git a/pydantic/functional_validators.py b/pydantic/functional_validators.py index c453578b40..fc3ad71740 100644 --- a/pydantic/functional_validators.py +++ b/pydantic/functional_validators.py @@ -273,7 +273,8 @@ def __call__( @overload def field_validator( - __field: str, + field: str, + /, *fields: str, mode: Literal['before', 'after', 'plain'] = ..., check_fields: bool | None = ..., @@ -283,7 +284,8 @@ def field_validator( @overload def field_validator( - __field: str, + field: str, + /, *fields: str, mode: Literal['wrap'], check_fields: bool | None = ..., @@ -295,7 +297,8 @@ def field_validator( def field_validator( - __field: str, + field: str, + /, *fields: str, mode: FieldValidatorModes = 'after', check_fields: bool | None = None, @@ -341,7 +344,7 @@ def ensure_foobar(cls, v: Any): For more in depth examples, see [Field Validators](../concepts/validators.md#field-validators). Args: - __field: The first field the `field_validator` should be called on; this is separate + field: The first field the `field_validator` should be called on; this is separate from `fields` to ensure an error is raised if you don't pass at least one. *fields: Additional field(s) the `field_validator` should be called on. mode: Specifies whether to validate the fields before or after validation. @@ -356,13 +359,13 @@ def ensure_foobar(cls, v: Any): - If the args passed to `@field_validator` as fields are not strings. - If `@field_validator` applied to instance methods. """ - if isinstance(__field, FunctionType): + if isinstance(field, FunctionType): raise PydanticUserError( '`@field_validator` should be used with fields and keyword arguments, not bare. ' "E.g. usage should be `@validator('', ...)`", code='validator-no-fields', ) - fields = __field, *fields + fields = field, *fields if not all(isinstance(field, str) for field in fields): raise PydanticUserError( '`@field_validator` fields should be passed as separate string args. ' diff --git a/pydantic/main.py b/pydantic/main.py index 39112eadd1..525c8f98a1 100644 --- a/pydantic/main.py +++ b/pydantic/main.py @@ -568,13 +568,13 @@ def model_validate_strings( return cls.__pydantic_validator__.validate_strings(obj, strict=strict, context=context) @classmethod - def __get_pydantic_core_schema__(cls, __source: type[BaseModel], __handler: GetCoreSchemaHandler) -> CoreSchema: + def __get_pydantic_core_schema__(cls, source: type[BaseModel], handler: GetCoreSchemaHandler, /) -> CoreSchema: """Hook into generating the model's CoreSchema. Args: - __source: The class we are generating a schema for. + source: The class we are generating a schema for. This will generally be the same as the `cls` argument if this is a classmethod. - __handler: Call into Pydantic's internal JSON schema generation. + handler: Call into Pydantic's internal JSON schema generation. A callable that calls into Pydantic's internal CoreSchema generation logic. Returns: @@ -589,22 +589,23 @@ def __get_pydantic_core_schema__(cls, __source: type[BaseModel], __handler: GetC if not cls.__pydantic_generic_metadata__['origin']: return cls.__pydantic_core_schema__ - return __handler(__source) + return handler(source) @classmethod def __get_pydantic_json_schema__( cls, - __core_schema: CoreSchema, - __handler: GetJsonSchemaHandler, + core_schema: CoreSchema, + handler: GetJsonSchemaHandler, + /, ) -> JsonSchemaValue: """Hook into generating the model's JSON schema. Args: - __core_schema: A `pydantic-core` CoreSchema. + core_schema: A `pydantic-core` CoreSchema. You can ignore this argument and call the handler with a new CoreSchema, wrap this CoreSchema (`{'type': 'nullable', 'schema': current_schema}`), or just call the handler with the original schema. - __handler: Call into Pydantic's internal JSON schema generation. + handler: Call into Pydantic's internal JSON schema generation. This will raise a `pydantic.errors.PydanticInvalidForJsonSchema` if JSON schema generation fails. Since this gets called by `BaseModel.model_json_schema` you can override the @@ -614,7 +615,7 @@ def __get_pydantic_json_schema__( Returns: A JSON schema, as a Python object. """ - return __handler(__core_schema) + return handler(core_schema) @classmethod def __pydantic_init_subclass__(cls, **kwargs: Any) -> None: diff --git a/pydantic/networks.py b/pydantic/networks.py index 2a67198a6b..4219b63947 100644 --- a/pydantic/networks.py +++ b/pydantic/networks.py @@ -415,8 +415,8 @@ def __get_pydantic_json_schema__( return field_schema @classmethod - def _validate(cls, __input_value: str) -> str: - return validate_email(__input_value)[1] + def _validate(cls, input_value: str, /) -> str: + return validate_email(input_value)[1] class NameEmail(_repr.Representation): @@ -494,11 +494,11 @@ def __get_pydantic_core_schema__( ) @classmethod - def _validate(cls, __input_value: NameEmail | str) -> NameEmail: - if isinstance(__input_value, cls): - return __input_value + def _validate(cls, input_value: NameEmail | str, /) -> NameEmail: + if isinstance(input_value, cls): + return input_value else: - name, email = validate_email(__input_value) # type: ignore[arg-type] + name, email = validate_email(input_value) # type: ignore[arg-type] return cls(name, email) def __str__(self) -> str: @@ -571,8 +571,8 @@ def __get_pydantic_core_schema__( ) @classmethod - def _validate(cls, __input_value: Any) -> IPv4Address | IPv6Address: - return cls(__input_value) # type: ignore[return-value] + def _validate(cls, input_value: Any, /) -> IPv4Address | IPv6Address: + return cls(input_value) # type: ignore[return-value] class IPvAnyInterface: @@ -611,8 +611,8 @@ def __get_pydantic_core_schema__( ) @classmethod - def _validate(cls, __input_value: NetworkType) -> IPv4Interface | IPv6Interface: - return cls(__input_value) # type: ignore[return-value] + def _validate(cls, input_value: NetworkType, /) -> IPv4Interface | IPv6Interface: + return cls(input_value) # type: ignore[return-value] class IPvAnyNetwork: @@ -653,8 +653,8 @@ def __get_pydantic_core_schema__( ) @classmethod - def _validate(cls, __input_value: NetworkType) -> IPv4Network | IPv6Network: - return cls(__input_value) # type: ignore[return-value] + def _validate(cls, input_value: NetworkType, /) -> IPv4Network | IPv6Network: + return cls(input_value) # type: ignore[return-value] def _build_pretty_email_regex() -> re.Pattern[str]: diff --git a/pydantic/type_adapter.py b/pydantic/type_adapter.py index c7573b91b3..f06312eb62 100644 --- a/pydantic/type_adapter.py +++ b/pydantic/type_adapter.py @@ -235,7 +235,8 @@ def __init__( def validate_python( self, - __object: Any, + object: Any, + /, *, strict: bool | None = None, from_attributes: bool | None = None, @@ -244,7 +245,7 @@ def validate_python( """Validate a Python object against the model. Args: - __object: The Python object to validate against the model. + object: The Python object to validate against the model. strict: Whether to strictly check types. from_attributes: Whether to extract data from object attributes. context: Additional context to pass to the validator. @@ -256,37 +257,37 @@ def validate_python( Returns: The validated object. """ - return self.validator.validate_python(__object, strict=strict, from_attributes=from_attributes, context=context) + return self.validator.validate_python(object, strict=strict, from_attributes=from_attributes, context=context) def validate_json( - self, __data: str | bytes, *, strict: bool | None = None, context: dict[str, Any] | None = None + self, data: str | bytes, /, *, strict: bool | None = None, context: dict[str, Any] | None = None ) -> T: """Usage docs: https://docs.pydantic.dev/2.7/concepts/json/#json-parsing Validate a JSON string or bytes against the model. Args: - __data: The JSON data to validate against the model. + data: The JSON data to validate against the model. strict: Whether to strictly check types. context: Additional context to use during validation. Returns: The validated object. """ - return self.validator.validate_json(__data, strict=strict, context=context) + return self.validator.validate_json(data, strict=strict, context=context) - def validate_strings(self, __obj: Any, *, strict: bool | None = None, context: dict[str, Any] | None = None) -> T: + def validate_strings(self, obj: Any, /, *, strict: bool | None = None, context: dict[str, Any] | None = None) -> T: """Validate object contains string data against the model. Args: - __obj: The object contains string data to validate. + obj: The object contains string data to validate. strict: Whether to strictly check types. context: Additional context to use during validation. Returns: The validated object. """ - return self.validator.validate_strings(__obj, strict=strict, context=context) + return self.validator.validate_strings(obj, strict=strict, context=context) def get_default_value(self, *, strict: bool | None = None, context: dict[str, Any] | None = None) -> Some[T] | None: """Get the default value for the wrapped type. @@ -302,7 +303,8 @@ def get_default_value(self, *, strict: bool | None = None, context: dict[str, An def dump_python( self, - __instance: T, + instance: T, + /, *, mode: Literal['json', 'python'] = 'python', include: IncEx | None = None, @@ -317,7 +319,7 @@ def dump_python( """Dump an instance of the adapted type to a Python object. Args: - __instance: The Python object to serialize. + instance: The Python object to serialize. mode: The output format. include: Fields to include in the output. exclude: Fields to exclude from the output. @@ -332,7 +334,7 @@ def dump_python( The serialized object. """ return self.serializer.to_python( - __instance, + instance, mode=mode, by_alias=by_alias, include=include, @@ -346,7 +348,8 @@ def dump_python( def dump_json( self, - __instance: T, + instance: T, + /, *, indent: int | None = None, include: IncEx | None = None, @@ -363,7 +366,7 @@ def dump_json( Serialize an instance of the adapted type to JSON. Args: - __instance: The instance to be serialized. + instance: The instance to be serialized. indent: Number of spaces for JSON indentation. include: Fields to include. exclude: Fields to exclude. @@ -378,7 +381,7 @@ def dump_json( The JSON representation of the given instance as bytes. """ return self.serializer.to_json( - __instance, + instance, indent=indent, include=include, exclude=exclude, @@ -414,7 +417,8 @@ def json_schema( @staticmethod def json_schemas( - __inputs: Iterable[tuple[JsonSchemaKeyT, JsonSchemaMode, TypeAdapter[Any]]], + inputs: Iterable[tuple[JsonSchemaKeyT, JsonSchemaMode, TypeAdapter[Any]]], + /, *, by_alias: bool = True, title: str | None = None, @@ -425,7 +429,7 @@ def json_schemas( """Generate a JSON schema including definitions from multiple type adapters. Args: - __inputs: Inputs to schema generation. The first two items will form the keys of the (first) + inputs: Inputs to schema generation. The first two items will form the keys of the (first) output mapping; the type adapters will provide the core schemas that get converted into definitions in the output JSON schema. by_alias: Whether to use alias names. @@ -446,9 +450,9 @@ def json_schemas( """ schema_generator_instance = schema_generator(by_alias=by_alias, ref_template=ref_template) - inputs = [(key, mode, adapter.core_schema) for key, mode, adapter in __inputs] + inputs_tup = [(key, mode, adapter.core_schema) for key, mode, adapter in inputs] - json_schemas_map, definitions = schema_generator_instance.generate_definitions(inputs) + json_schemas_map, definitions = schema_generator_instance.generate_definitions(inputs_tup) json_schema: dict[str, Any] = {} if definitions: diff --git a/pydantic/types.py b/pydantic/types.py index d8b042e438..ccf673de27 100644 --- a/pydantic/types.py +++ b/pydantic/types.py @@ -1747,9 +1747,9 @@ def __get_pydantic_core_schema__(cls, source: type[Any], handler: GetCoreSchemaH ) @classmethod - def validate(cls, __input_value: str, _: core_schema.ValidationInfo) -> PaymentCardNumber: + def validate(cls, input_value: str, /, _: core_schema.ValidationInfo) -> PaymentCardNumber: """Validate the card number and return a `PaymentCardNumber` instance.""" - return cls(__input_value) + return cls(input_value) @property def masked(self) -> str: @@ -1912,13 +1912,13 @@ def __get_pydantic_core_schema__(cls, source: type[Any], handler: GetCoreSchemaH ) @classmethod - def _validate(cls, __input_value: Any, _: core_schema.ValidationInfo) -> ByteSize: + def _validate(cls, input_value: Any, /, _: core_schema.ValidationInfo) -> ByteSize: try: - return cls(int(__input_value)) + return cls(int(input_value)) except ValueError: pass - str_match = cls.byte_string_re.match(str(__input_value)) + str_match = cls.byte_string_re.match(str(input_value)) if str_match is None: raise PydanticCustomError('byte_size', 'could not parse value and unit from byte string') diff --git a/pydantic/validate_call_decorator.py b/pydantic/validate_call_decorator.py index 76d1cecbd5..5b82e19d85 100644 --- a/pydantic/validate_call_decorator.py +++ b/pydantic/validate_call_decorator.py @@ -22,12 +22,13 @@ def validate_call( @overload -def validate_call(__func: AnyCallableT) -> AnyCallableT: +def validate_call(func: AnyCallableT, /) -> AnyCallableT: ... def validate_call( - __func: AnyCallableT | None = None, + func: AnyCallableT | None = None, + /, *, config: ConfigDict | None = None, validate_return: bool = False, @@ -39,7 +40,7 @@ def validate_call( Usage may be either as a plain decorator `@validate_call` or with arguments `@validate_call(...)`. Args: - __func: The function to be decorated. + func: The function to be decorated. config: The configuration dictionary. validate_return: Whether to validate the return value. @@ -61,7 +62,7 @@ def wrapper_function(*args, **kwargs): return wrapper_function # type: ignore - if __func: - return validate(__func) + if func: + return validate(func) else: return validate diff --git a/tests/benchmarks/basemodel_eq_performance.py b/tests/benchmarks/basemodel_eq_performance.py index 090822202f..2f7e05f585 100644 --- a/tests/benchmarks/basemodel_eq_performance.py +++ b/tests/benchmarks/basemodel_eq_performance.py @@ -144,11 +144,11 @@ class _SafeGetItemProxy(Generic[K, V]): wrapped: dict[K, V] - def __getitem__(self, __key: K) -> V | _SentinelType: - return self.wrapped.get(__key, _SENTINEL) + def __getitem__(self, key: K, /) -> V | _SentinelType: + return self.wrapped.get(key, _SENTINEL) - def __contains__(self, __key: K) -> bool: - return self.wrapped.__contains__(__key) + def __contains__(self, key: K, /) -> bool: + return self.wrapped.__contains__(key) class SafeItemGetterEqModelFastPath(pydantic.BaseModel, frozen=True): diff --git a/tests/test_validators.py b/tests/test_validators.py index 226d15dbbd..24f0069d30 100644 --- a/tests/test_validators.py +++ b/tests/test_validators.py @@ -562,9 +562,7 @@ def checker(cls, v): def test_use_no_fields_field_validator(): - with pytest.raises( - TypeError, match=re.escape("field_validator() missing 1 required positional argument: '__field'") - ): + with pytest.raises(TypeError, match=re.escape("field_validator() missing 1 required positional argument: 'field'")): class Model(BaseModel): a: str From 6c891199e7686f790c9f0f944fbfcaeddefc1ce0 Mon Sep 17 00:00:00 2001 From: Viicos <65306057+Viicos@users.noreply.github.com> Date: Mon, 4 Mar 2024 09:31:57 +0100 Subject: [PATCH 2/3] Fix annotation --- pydantic/networks.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pydantic/networks.py b/pydantic/networks.py index 4219b63947..d8e6549f62 100644 --- a/pydantic/networks.py +++ b/pydantic/networks.py @@ -8,7 +8,7 @@ from typing import TYPE_CHECKING, Any from pydantic_core import MultiHostUrl, PydanticCustomError, Url, core_schema -from typing_extensions import Annotated, TypeAlias +from typing_extensions import Annotated, Self, TypeAlias from ._internal import _fields, _repr, _schema_generation_shared from ._migration import getattr_migration @@ -494,11 +494,11 @@ def __get_pydantic_core_schema__( ) @classmethod - def _validate(cls, input_value: NameEmail | str, /) -> NameEmail: + def _validate(cls, input_value: Self | str, /) -> Self: if isinstance(input_value, cls): return input_value else: - name, email = validate_email(input_value) # type: ignore[arg-type] + name, email = validate_email(input_value) return cls(name, email) def __str__(self) -> str: From 131b3c217f764a3f3c6f30c8b70012b9fb0a3ed3 Mon Sep 17 00:00:00 2001 From: Sydney Runkle <54324534+sydney-runkle@users.noreply.github.com> Date: Tue, 5 Mar 2024 08:15:32 -0600 Subject: [PATCH 3/3] Apply suggestions from code review --- pydantic/type_adapter.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pydantic/type_adapter.py b/pydantic/type_adapter.py index f06312eb62..e743405011 100644 --- a/pydantic/type_adapter.py +++ b/pydantic/type_adapter.py @@ -450,9 +450,9 @@ def json_schemas( """ schema_generator_instance = schema_generator(by_alias=by_alias, ref_template=ref_template) - inputs_tup = [(key, mode, adapter.core_schema) for key, mode, adapter in inputs] + inputs_ = [(key, mode, adapter.core_schema) for key, mode, adapter in inputs] - json_schemas_map, definitions = schema_generator_instance.generate_definitions(inputs_tup) + json_schemas_map, definitions = schema_generator_instance.generate_definitions(inputs_) json_schema: dict[str, Any] = {} if definitions: