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

ENH: Make skops.io.dump and load work with TextIOWrapper #234

Merged
merged 5 commits into from
Dec 2, 2022

Conversation

BenjaminBossan
Copy link
Collaborator

(note: load already worked, only dump needed change)

The idea here is to make it possible to use skops.io.dump and load with a file wrapper, i.e. using with open(...). This makes it easier to search and replace pickle.dump and load by skops.io.dump and load.

Implementation

To decide how to check the way to treat the file argument, I went with hasattr(file, "write"), as this is what np.save does. I assume this is more robust than checking the type. Unfortunately, mypy doesn't understand this, so I had to tell it to shut up.

I didn't update the docstring or any examples because I don't think we need to "advertise" this usage.

(note: load already worked, only dump needed change)

The idea here is to make it possible to use dump and load with a file
wrapper, i.e. using 'with open(...)'. This makes it easier to search and
replace pickle dump and load by skops dump and load.

Implementation

To decide how to check the way to treat the file argument, I went with
hasattr(file, "write"), as this is what np.save does. I assume this is
more robust than checking the type. Unfortunately, mypy doesn't
understand this, so I had to tell it to shut up.

I didn't update the docstring or any examples because I don't think we
need to 'advertise' this usage.
@BenjaminBossan BenjaminBossan added the persistence Secure persistence feature label Dec 1, 2022
@BenjaminBossan
Copy link
Collaborator Author

@skops-dev/maintainers ready for review

Copy link
Member

@adrinjalali adrinjalali left a comment

Choose a reason for hiding this comment

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

This sounds pretty good to me.

Shouldn't load follow the same pattern?

Also needs a changelog.

@@ -39,7 +39,7 @@ def _save(obj: Any) -> io.BytesIO:
return buffer


def dump(obj: Any, file: str) -> None:
def dump(obj: Any, file: str | io.TextIOWrapper) -> None:
Copy link
Member

Choose a reason for hiding this comment

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

is it a textiowrapper or anything which has write?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

It's the latter, if you prefer I can create a protocol for objects with write attributes, just thought TextIOWrapper is the most common case by far.

Copy link
Member

Choose a reason for hiding this comment

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

Or not have it typed? 👻

We also accept a Path.

What we really accept here, is a file-like object, or a path like object. And that's best explained in the docstring w/o any types.

image

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I dug a bit further, it seems that typing.BinaryIO would be the correct type:

https://docs.python.org/3/library/typing.html#typing.BinaryIO

This allows mypy to flag code like the one below which uses the wrong mode:

with open(file, 'w') as f:  # <= should be 'wb' mode
    dump(f)

WDYT?

Regarding Path: Yeah, that's supported, I originally didn't add it because it's not related to this PR, but I can still add it here.

Copy link
Member

Choose a reason for hiding this comment

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

Ok, I could live with BinaryIO then.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Okay, I changed it accordingly. I also changed to if isinstance(file, (str, Path)), which is now correctly type-checked by mypy.

@BenjaminBossan BenjaminBossan changed the title Make skops.io.dump and load work with TextWrapper Make skops.io.dump and load work with TextIOWrapper Dec 2, 2022
@BenjaminBossan BenjaminBossan changed the title Make skops.io.dump and load work with TextIOWrapper ENH: Make skops.io.dump and load work with TextIOWrapper Dec 2, 2022
@BenjaminBossan
Copy link
Collaborator Author

Shouldn't load follow the same pattern?

load already works because ZipFile takes care of correctly dealing with the file argument.

Also needs a changelog.

Done, can be reviewed again.

Copy link
Collaborator

@E-Aho E-Aho left a comment

Choose a reason for hiding this comment

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

LGTM

docs/changes.rst Outdated Show resolved Hide resolved
Co-authored-by: Adrin Jalali <adrin.jalali@gmail.com>
@adrinjalali adrinjalali merged commit ec8df2f into skops-dev:main Dec 2, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
persistence Secure persistence feature
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants