Skip to content

Commit

Permalink
Update dependencies, fix pydantic-core usage, fix CI issues (#7150)
Browse files Browse the repository at this point in the history
  • Loading branch information
dmontagu committed Aug 16, 2023
1 parent 37b7f08 commit 6e3e931
Show file tree
Hide file tree
Showing 12 changed files with 187 additions and 176 deletions.
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

0 comments on commit 6e3e931

Please sign in to comment.