Skip to content

Conversation

nix010
Copy link
Contributor

@nix010 nix010 commented Jun 26, 2024

Change Summary

Fix #9706

Related issue number

Fix #9706

Checklist

  • The pull request title is a good summary of the changes - it will be used in the changelog
  • Unit tests for the changes exist
  • Tests pass on CI
  • Documentation reflects the changes where applicable
  • My PR is ready to review, please add a comment including the phrase "please review" to assign reviewers

Selected Reviewer: @hramezani

@github-actions github-actions bot added the relnotes-fix Used for bugfixes. label Jun 26, 2024
@nix010
Copy link
Contributor Author

nix010 commented Jun 26, 2024

please review

Copy link

codspeed-hq bot commented Jun 26, 2024

CodSpeed Performance Report

Merging #9764 will not alter performance

Comparing nix010:9706-fix-pathlike-with-sub-type (b5c87ec) with main (1e9873f)

Summary

✅ 13 untouched benchmarks

@nix010
Copy link
Contributor Author

nix010 commented Jun 26, 2024

Not sure if the change is align wiht what is expected from #9706 but made PR anyway to see if it on the right direction!

Copy link
Contributor

@sydney-runkle sydney-runkle left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey @nix010,

Great start here. Left some general feedback + a few test requests!

@pydantic-hooky pydantic-hooky bot added awaiting author revision awaiting changes from the PR author and removed ready for review labels Jun 26, 2024
@pydantic-hooky pydantic-hooky bot assigned nix010 and unassigned hramezani Jun 26, 2024
@nix010 nix010 requested a review from sydney-runkle June 27, 2024 12:12
Copy link
Contributor

@sydney-runkle sydney-runkle left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some ideas for simplification :)

@@ -207,7 +207,11 @@ def path_schema_prepare_pydantic_annotations(
) -> tuple[Any, list[Any]] | None:
import pathlib

if source_type not in {
orig_source_type = get_origin(source_type) or source_type
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about:

orig_source_type: Any = get_origin(source_type) or source_type
if (source_type_args := get_args(source_type)) and source_type_args[0] not in {str, bytes, Any}:
    return None

if orig_source_type not in {
    os.PathLike,
    pathlib.Path,
    pathlib.PurePath,
    pathlib.PosixPath,
    pathlib.PurePosixPath,
    pathlib.PureWindowsPath,
}:
    return None

Copy link
Contributor Author

@nix010 nix010 Jul 1, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@sydney-runkle so there's a test case like test_string_import_callable which make source_type_args[0] a list and result in TypeError: unhashable type: 'list'.
So I just check it below.

is_path_like_subtype_invalid = (
        orig_source_type == os.PathLike
        and source_type_args
        and source_type_args[0]
        not in {
            str,
            bytes,
            Any,
        }
    )

    if is_path_like_subtype_invalid:
        return None 

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@nix010,

I believe my suggestion above does the same...

_known_annotated_metadata.check_metadata(metadata, _known_annotated_metadata.STR_CONSTRAINTS, source_type)
_known_annotated_metadata.check_metadata(metadata, _known_annotated_metadata.STR_CONSTRAINTS, orig_source_type)

construct_path = orig_source_type
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about:

construct_path = pathlib.PurePath if orig_source_type is os.PathLike else orig_source_type
constrained_schema = (
    core_schema.bytes_schema(**metadata) if source_type_args and source_type_args[0] is bytes 
    else core_schema.str_schema(**metadata)
)

def path_validator(input_value: str) -> os.PathLike[Any]:
    try:
        return construct_path(input_value)
    except TypeError as e:
        raise PydanticCustomError('path_type', 'Input is not a valid path') from e

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I realize I've skipped the decoding here, one moment... trying to add back in with correct typing

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is type safe:

def path_validator(input_value: str | bytes) -> os.PathLike[str]:
    try:
        if source_type_args and source_type_args[0] is bytes:
            if isinstance(input_value, bytes):
                try:
                    input_value = input_value.decode()
                except UnicodeDecodeError as e:
                    raise PydanticCustomError('bytes_type', 'Input must be valid bytes') from e
            else:
                raise PydanticCustomError('bytes_type', 'Input must be bytes')
        elif not isinstance(input_value, str):
            raise PydanticCustomError('path_type', 'Input is not a valid path')
    
        return construct_path(input_value)
    except TypeError as e:
        raise PydanticCustomError('path_type', 'Input is not a valid path') from e

assert Model.model_json_schema() == {
'properties': {
'str_type': {'format': 'path', 'title': 'Str Type', 'type': 'string'},
'byte_type': {'format': 'path', 'title': 'Byte Type', 'type': 'string'},
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, I wonder if we want to change the JSON schema for these path types...

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sure, what should we change them into ?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I feel like the type should be bytes for the byte_type path...

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Honestly though, if someone complains we can fix this, I don't think it's super high priority and this gives us some flexibility to change it based on user experience.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bc it's really a string once you populate the path

Copy link
Contributor

@sydney-runkle sydney-runkle left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great, thanks!!

@sydney-runkle sydney-runkle enabled auto-merge (squash) July 3, 2024 20:45
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
awaiting author revision awaiting changes from the PR author relnotes-fix Used for bugfixes.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

PydanticSchemaGenerationError when using os.PathLike[str]
3 participants