Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update dependencies, fix pydantic-core usage, fix CI issues #7150

Merged
merged 2 commits into from Aug 16, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Expand Up @@ -227,7 +227,7 @@ jobs:
node-version: '18'

- name: install pyright
run: npm install -g pyright@1.1.302 # try to keep this in sync with .pre-commit-config.yaml
run: npm install -g pyright@1.1.322 # try to keep this in sync with .pre-commit-config.yaml

- name: run pyright tests
run: make test-pyright
Expand Down
2 changes: 1 addition & 1 deletion .pre-commit-config.yaml
Expand Up @@ -30,4 +30,4 @@ repos:
types: [python]
language: node
pass_filenames: false
additional_dependencies: ["pyright@1.1.310"]
additional_dependencies: ["pyright@1.1.322"]
278 changes: 142 additions & 136 deletions pdm.lock

Large diffs are not rendered by default.

8 changes: 7 additions & 1 deletion pydantic/_internal/_core_utils.py
Expand Up @@ -283,7 +283,13 @@ def handle_function_schema(self, schema: AnyFunctionSchema, f: Walk) -> core_sch
return schema

def handle_union_schema(self, schema: core_schema.UnionSchema, f: Walk) -> core_schema.CoreSchema:
schema['choices'] = [self.walk(v, f) for v in schema['choices']]
new_choices: list[CoreSchema | tuple[CoreSchema, str]] = []
for v in schema['choices']:
if isinstance(v, tuple):
new_choices.append((self.walk(v[0], f), v[1]))
else:
new_choices.append(self.walk(v, f))
schema['choices'] = new_choices
return schema

def handle_tagged_union_schema(self, schema: core_schema.TaggedUnionSchema, f: Walk) -> core_schema.CoreSchema:
Expand Down
12 changes: 8 additions & 4 deletions pydantic/_internal/_discriminated_union.py
Expand Up @@ -188,7 +188,8 @@ def _apply_to_root(self, schema: core_schema.CoreSchema) -> core_schema.CoreSche
schema = core_schema.union_schema([schema])

# Reverse the choices list before extending the stack so that they get handled in the order they occur
self._choices_to_handle.extend(schema['choices'][::-1])
choices_schemas = [v[0] if isinstance(v, tuple) else v for v in schema['choices'][::-1]]
self._choices_to_handle.extend(choices_schemas)
while self._choices_to_handle:
choice = self._choices_to_handle.pop()
self._handle_choice(choice)
Expand Down Expand Up @@ -237,7 +238,8 @@ def _handle_choice(self, choice: core_schema.CoreSchema) -> None:
self._handle_choice(choice['schema']) # unwrap the nullable schema
elif choice['type'] == 'union':
# Reverse the choices list before extending the stack so that they get handled in the order they occur
self._choices_to_handle.extend(choice['choices'][::-1])
choices_schemas = [v[0] if isinstance(v, tuple) else v for v in choice['choices'][::-1]]
self._choices_to_handle.extend(choices_schemas)
elif choice['type'] == 'definition-ref':
if choice['schema_ref'] not in self.definitions:
raise ValueError(f"Missing definition for ref {choice['schema_ref']!r}")
Expand Down Expand Up @@ -315,7 +317,8 @@ def _infer_discriminator_values_for_choice( # noqa C901
elif choice['type'] == 'union':
values = []
for subchoice in choice['choices']:
subchoice_values = self._infer_discriminator_values_for_choice(subchoice, source_name=None)
subchoice_schema = subchoice[0] if isinstance(subchoice, tuple) else subchoice
subchoice_values = self._infer_discriminator_values_for_choice(subchoice_schema, source_name=None)
values.extend(subchoice_values)
return values

Expand Down Expand Up @@ -422,7 +425,8 @@ def _infer_discriminator_values_for_inner_schema(
# For example, this lets us handle `Union[Literal['key'], Union[Literal['Key'], Literal['KEY']]]`
values: list[Any] = []
for choice in schema['choices']:
choice_values = self._infer_discriminator_values_for_inner_schema(choice, source)
choice_schema = choice[0] if isinstance(choice, tuple) else choice
choice_values = self._infer_discriminator_values_for_inner_schema(choice_schema, source)
values.extend(choice_values)
return values

Expand Down
5 changes: 3 additions & 2 deletions pydantic/_internal/_generate_schema.py
Expand Up @@ -970,7 +970,7 @@ def json_schema_update_func(schema: CoreSchemaOrField, handler: GetJsonSchemaHan
def _union_schema(self, union_type: Any) -> core_schema.CoreSchema:
"""Generate schema for a Union."""
args = self._get_args_resolving_forward_refs(union_type, required=True)
choices: list[core_schema.CoreSchema] = []
choices: list[CoreSchema | tuple[CoreSchema, str]] = []
nullable = False
for arg in args:
if arg is None or arg is _typing_extra.NoneType:
Expand All @@ -979,7 +979,8 @@ def _union_schema(self, union_type: Any) -> core_schema.CoreSchema:
choices.append(self.generate_schema(arg))

if len(choices) == 1:
s = choices[0]
first_choice = choices[0]
s = first_choice[0] if isinstance(first_choice, tuple) else first_choice
else:
s = core_schema.union_schema(choices)

Expand Down
2 changes: 1 addition & 1 deletion pydantic/_internal/_generics.py
Expand Up @@ -309,7 +309,7 @@ def replace_types(type_: Any, type_map: Mapping[Any, Any] | None) -> Any:
assert origin_type is not None
# PEP-604 syntax (Ex.: list | str) is represented with a types.UnionType object that does not have __getitem__.
# We also cannot use isinstance() since we have to compare types.
if sys.version_info >= (3, 10) and origin_type is types.UnionType: # noqa: E721
if sys.version_info >= (3, 10) and origin_type is types.UnionType:
return _UnionGenericAlias(origin_type, resolved_type_args)
return origin_type[resolved_type_args]

Expand Down
4 changes: 2 additions & 2 deletions pydantic/_internal/_typing_extra.py
Expand Up @@ -46,7 +46,7 @@ def origin_is_union(tp: type[Any] | None) -> bool:
else:

def origin_is_union(tp: type[Any] | None) -> bool:
return tp is typing.Union or tp is types.UnionType # noqa: E721
return tp is typing.Union or tp is types.UnionType

WithArgsTypes = typing._GenericAlias, types.GenericAlias, types.UnionType # type: ignore[attr-defined]

Expand Down Expand Up @@ -388,7 +388,7 @@ def get_type_hints( # noqa: C901
if isinstance(obj, typing._allowed_types): # type: ignore
return {}
else:
raise TypeError('{!r} is not a module, class, method, ' 'or function.'.format(obj))
raise TypeError(f'{obj!r} is not a module, class, method, ' 'or function.')
defaults = typing._get_defaults(obj) # type: ignore
hints = dict(hints)
for name, value in hints.items():
Expand Down
34 changes: 12 additions & 22 deletions pydantic/json_schema.py
Expand Up @@ -1010,9 +1010,11 @@ def union_schema(self, schema: core_schema.UnionSchema) -> JsonSchemaValue:
generated: list[JsonSchemaValue] = []

choices = schema['choices']
for s in choices:
for choice in choices:
# choice will be a tuple if an explicit label was provided
choice_schema = choice[0] if isinstance(choice, tuple) else choice
try:
generated.append(self.generate_inner(s))
generated.append(self.generate_inner(choice_schema))
except PydanticOmit:
continue
except PydanticInvalidForJsonSchema as exc:
Expand All @@ -1036,26 +1038,14 @@ def tagged_union_schema(self, schema: core_schema.TaggedUnionSchema) -> JsonSche
for k, v in schema['choices'].items():
if isinstance(k, Enum):
k = k.value
if not isinstance(v, (str, int)):
try:
# Use str(k) since keys must be strings for json; while not technically correct,
# it's the closest that can be represented in valid JSON
generated[str(k)] = self.generate_inner(v).copy()
except PydanticOmit:
continue
except PydanticInvalidForJsonSchema as exc:
self.emit_warning('skipped-choice', exc.message)

# Populate the schema with any "indirect" references
for k, v in schema['choices'].items():
if isinstance(v, (str, int)):
while isinstance(schema['choices'][v], (str, int)):
v = schema['choices'][v]
assert isinstance(v, (int, str))
if str(v) in generated:
# while it might seem unnecessary to check `if str(v) in generated`, a PydanticInvalidForJsonSchema
# may have been raised above, which would mean that the schema we want to reference won't be present
generated[str(k)] = generated[str(v)]
try:
# Use str(k) since keys must be strings for json; while not technically correct,
# it's the closest that can be represented in valid JSON
generated[str(k)] = self.generate_inner(v).copy()
except PydanticOmit:
continue
except PydanticInvalidForJsonSchema as exc:
self.emit_warning('skipped-choice', exc.message)

one_of_choices = _deduplicate_schemas(generated.values())
json_schema: JsonSchemaValue = {'oneOf': one_of_choices}
Expand Down
4 changes: 2 additions & 2 deletions pyproject.toml
Expand Up @@ -61,7 +61,7 @@ requires-python = '>=3.7'
dependencies = [
'typing-extensions>=4.6.1',
'annotated-types>=0.4.0',
"pydantic-core==2.5.0",
"pydantic-core==2.6.0",
]
dynamic = ['version', 'readme']

Expand Down Expand Up @@ -179,7 +179,7 @@ exclude=['pydantic/v1', 'tests/mypy/outputs']

[tool.ruff.extend-per-file-ignores]
"docs/**/*.py" = ['T']
"tests/**/*.py" = ['T']
"tests/**/*.py" = ['T', 'E721', 'F811']
"tests/benchmarks/test_fastapi_startup.py" = ['UP006']

[tool.ruff.pydocstyle]
Expand Down
2 changes: 1 addition & 1 deletion tests/test_docs.py
Expand Up @@ -95,7 +95,7 @@ def run_example(example: CodeExample, eval_example: EvalExample, mocker: Any) ->

group_name = prefix_settings.get('group')

eval_example.set_config(ruff_ignore=['D', 'T'], line_length=LINE_LENGTH)
eval_example.set_config(ruff_ignore=['D', 'T', 'E721'], line_length=LINE_LENGTH)
if '# ignore-above' in example.source:
eval_example.set_config(ruff_ignore=eval_example.config.ruff_ignore + ['E402'], line_length=LINE_LENGTH)
if group_name:
Expand Down
10 changes: 7 additions & 3 deletions tests/test_json_schema.py
Expand Up @@ -1614,7 +1614,9 @@ class MyEnum(str, Enum):
class UserModel(BaseModel):
friends: MyEnum = MyEnum.FOO

assert UserModel.model_json_schema()['properties']['friends']['default'] is MyEnum.FOO.value
default_value = UserModel.model_json_schema()['properties']['friends']['default']
assert type(default_value) is str
assert default_value == MyEnum.FOO.value


def test_enum_int_default():
Expand All @@ -1624,7 +1626,9 @@ class MyEnum(IntEnum):
class UserModel(BaseModel):
friends: MyEnum = MyEnum.FOO

assert UserModel.model_json_schema()['properties']['friends']['default'] is MyEnum.FOO.value
default_value = UserModel.model_json_schema()['properties']['friends']['default']
assert type(default_value) is int
assert default_value == MyEnum.FOO.value


def test_dict_default():
Expand Down Expand Up @@ -5315,7 +5319,7 @@ class ModelTest(BaseModel):

for _ in range(sys.getrecursionlimit() + 1):

class ModelTest(BaseModel): # noqa: F811
class ModelTest(BaseModel):
c: Outer[Inner]

ModelTest.model_json_schema()
Expand Down