skops Changelog
v0.17
Loading a skops file now checks that each part of the file holds the kind of content its loader expects, for instance that the keyword arguments of a
functools.partialare stored as a dict. A file that does not is refused with an error while it is read, before anything in it is audited or constructed, instead of failing with an unrelated error, or being accepted, during construction. #547 by Adrin Jalali.Fix a regression since v0.12.0 where saving an object whose
__reduce__raises failed at dump time.__reduce__is called on every object to detect a plain constructor call, but Cython extension types with a__cinit__and no__reduce__raise instead of returning one. pandas’BlockValuesRefsis such a type and every pandasIndexexceptRangeIndexholds one, so objects containing such an index, or aSeriesorDataFrameusing one, could not be saved. Such objects are now saved through__getstate__/__dict__again, as before v0.12.0. #550 by Adrin Jalali.Objects which contain a reference to themselves can now be saved and loaded, and subclasses of the built-in containers are persisted the way pickle does it. #549 and #554 by Adrin Jalali.
Circular references: objects which refer to themselves, directly or through their attributes, dicts, lists, or sets, including subclasses of these, can now be saved and loaded. They used to fail with a
RecursionError; this affected for instance the discrete distributions ofscipy.statsand fittedsklearn.cluster.Birchmodels, which is no longer listed as unsupported. Such a reference through any other type, e.g. a tuple, raises anUnsupportedTypeExceptionwhen saving.Container subclasses: subclasses of
dict,listandsetare now saved and loaded the way pickle does it for dicts and lists. The instance is created with__new__and filled in place instead of through its constructor, so a subclass whose constructor requires arguments can now be loaded, and its instance attributes, which used to be dropped, are saved and restored. Subclasses ofsetand ofcollections.defaultdictare treated the same way, although pickle builds them through their constructor, so that items which refer back to the container can be loaded. Files written with an earlier protocol load as before.Loading: bound methods inherited from a class defined in another module can now be loaded, they used to be rejected as corrupted. A file in which nodes of different types share an
__id__is now rejected instead of silently loading one of them in place of the other.
Restore the
skopscommand line entry point. It was declared insetup.pyand lost when the packaging moved topyproject.tomlin v0.11.0, soskops convertandskops updatehad not been available from the command line since.python -m skopsnow also runs the CLI, and running it without a subcommand prints a usage error instead of a traceback. #548 by Adrin Jalali.Fix saving of
operator.methodcallerobjects with keyword arguments: the method name and the keyword arguments were dropped, so the saved object could not be loaded. The file format now stores the keyword arguments and the persistence protocol is bumped to 3; files written with an earlier protocol load as before. #551 by Adrin Jalali.Fix loading of
collections.defaultdictobjects whose keys are not strings, which failed with aTypeError, and of objects whose class defines__slots__, which failed with anAttributeErroron Python 3.11 and later. Subclasses ofdefaultdictare now loaded as their own type, with their instance attributes; they used to be loaded as a plaindefaultdict. #554 by Adrin Jalali.
v0.16
Fix loading of time-zone-aware
datetime.datetimeanddatetime.timeobjects, and ofzoneinfo.ZoneInfoanddatetime.timezoneinstances. Their__reduce__output was not recognized as a constructor call, so they were saved without their state and could not be loaded even when trusted.ZoneInfoobjects created withZoneInfo.from_fileare not backed by a key and now raise an error when saved instead of producing a file that cannot be loaded. #546 by Adrin Jalali.Importing
skops.iois faster: resolving the module of objects without__module__, such as scipy ufuncs, no longer raises and catches an exception for every loaded module that lacks the attribute. #543 by Adrin Jalali.The
trustedargument ofskops.io.load(),skops.io.loads(),skops.io.visualize()andskops.card.Cardnow officially accepts types in addition to their fully qualified names, andskops.io.load()accepts a binary file object in addition to a path. #541 by Adrin Jalali.
v0.15
The protocol number stored in a
.skopsfile is now validated before any of its content is inspected: it must be an integer between 0 and the protocol of the installed skops version. Files saved with a newer protocol used to be silently loaded with the current loaders and now raise an error asking to update skops. The protocol selects which loaders audit and construct the file, so the developer notes inskops.io._protocolnow also require that audit fixes to a loader are mirrored to all of its older versions. #537 by Adrin Jalali.sklearn.tree._tree.Treeandsklearn.ensemble._hist_gradient_boosting.predictor.TreePredictorare no longer trusted by default: skops validates that a loaded object is of a trusted type, but not the contents of its raw state, and these types store unchecked node indices that scikit-learn can dereference out of bounds during.predict(), crashing the process. The raisedUntrustedTypesFoundExceptionnow explains the risk for these types. #535 by Adrin Jalali.Fix a security issue where loading a
numpy.random.Generatorwould resolve and call anumpy.randomattribute whose name was taken from the file, even thoughget_untrusted_typesreported nothing untrusted for that file. The bit generator type is now surfaced to the audit, and only genuine bit generators are instantiated when loading. #536 by Adrin Jalali.Fix a security issue where
skops update(skops.cli) would load a file while blindly trusting every type declared in it, allowing a malicious.skopsfile to execute arbitrary code.skops updatenow refuses to load types that are not trusted by default; use the new--trustedoption to explicitly allow types you have reviewed. #533 by Adrin Jalali.Support persisting scipy sparse arrays (e.g.
csr_array) through the same efficientnpzformat used for sparse matrices, and handle thescipy.specialufunc wrappers introduced in scipy 2.0. This adds compatibility with scipy 2.0 and scikit-learn 1.9. #534 by Adrin Jalali.Fix importing
skops.ioraisingModuleNotFoundErrorwhen an already imported package exposes lazily loaded attributes whose optional dependencies are missing, for exampletransformerswithouttorchvision. Trusted type discovery now skips such attributes. #528 by Adrin Jalali.
v0.14
Trust internal scikit-learn types needed by GradientBoosting and HistGradientBoosting models, so they no longer surface as untrusted types. #513 by cakedev0 and Adrin Jalali.
v0.13
v0.12
huggingface_hub dependency is now optional. #462 by Adrin Jalali.
Objects’ __reduce__ is used when the output of it is of the form (type, (constructor_args,) where type is the same as the type(obj). #467 by Adrin Jalali.
MethodNode and OperatorNode have a hardened audit now, removing certain security vulnerabilities. #482 by Adrin Jalali.
v0.11
Correctly restore
default_factorywhen saving and loading adefaultdict. #433 by Adrin Jalali.Support more loss functions implemented in Cython in scikit-learn. #453 by Adrin Jalali.
Fixes for scikit-learn=1.6 release. #447 by Tamara Atanasoska.
v0.10
Removes Pythn 3.8 support and adds Python 3.12 Support #418 by Thomas Lazarus.
Removes a shortcut to add sklearn-intelex as a not dependency. #420 by Thomas Lazarus.
trusted=Trueis now removed fromskops.io.loadandskops.io.loads. This is to further encourage users to inspect the input data before loading it.skops.io.get_untrusted_types()can be used to get the untrusted types present in the input. #422 by Adrin Jalali.skops.ionow supports numpy>=2. #429 by Adrin Jalali.
v0.9
Add support for quantile-forest estimators. #384 by Reid Johnson.
Fix an issue with visualizing Skops files for scikit-learn tree estimators. #386 by Reid Johnson.
skops.hub_utils.get_model_outputandskops.hub_utils.pushare deprecated and will be removed in version 0.10. #396 by Adrin Jalali.
v0.8
Adds the abillity to set the
Section.foldedproperty when usingCard.add(). #361 by Thomas Lazarus.Add the CLI command to update Skops files to the latest Skops persistence format. (
cli._update.main()). #333 by Edoardo AbatiFix a bug that prevented persisting
np.meanwhen using numpy>=1.25.0. #373 by Adrin Jalali.
v0.7
Add ability to copy plots on
Card.save()so that they can be referenced in the model card. #330 by Thomas Lazarus.compression and compresslevel from
ZipFileare now exposed to the user viaio.dumps()andio.dump(). #345 by Adrin Jalali.Fix:
skops.io.visualize()is now capable of showing bytes. #352 by Benjamin Bossan.All public
numpyufuncs (Universal Functions) and dtypes are trusted by default byio.load(). #336 by Omar Arab Oghli.Sections in
skops.card.Cardcan now be folded once added to the card. #341 by Thomas Lazarus.Model loading in
skops.card.Cardis now cached to avoid loading the model multiple times. #299 by Juan Camacho.
v0.6
Add tabular regression example. #254 by Thomas Lazarus.
All public
scipy.specialufuncs (Universal Functions) are trusted by default byio.load(). #295 by Omar Arab Oghli.Add a new function
skops.card.Card.add_metric_frame()to help users add metrics to their model cards. #298 by Thomas LazarusAdd
Card.create_toc()to create a table of contents for the model card in markdown format. #305 by Thomas Lazarus.Add example of using model card without the skops template. #291 by Benjamin Bossan.
Fix: skops persistence now also works with many functions from the
operatormodule. #287 by Benjamin Bossan.add_*methods onCardnow have default section names (butNoneis no longer valid) and no longer add descriptions by default. #321 by Benjamin Bossan.Add possibility to visualize a skops object and show untrusted types by using
skops.io.visualize(). For colored output, install rich: pip install rich. #317 by Benjamin Bossan.Fix issue with persisting
numpy.random.Generatorusing the skops format (the object could be loaded correctly but security could not be checked). #331 by Benjamin Bossan.
v0.5
Add CLI entrypoint support (
cli.entrypoint.main_cli()) and a command line function to convert Pickle files to Skops files (cli._convert.main()). #249 by Erin AhoSupport more array-like data types for tabular data and list-like data types for text data. #179 by Francesco Cariaggi.
Add an option use_intelex to
skops.hub_utils.init()which, when enabled, will result in the Hugging Face inference API running with Intel’s scikit-learn intelex library, which can accelerate inference times. #267 by Benjamin Bossan.Model cards that have been written into a markdown file can now be parsed back into a
skops.card.Cardobject and edited further by using theskops.card.parse_modelcard()function. #257 by Benjamin Bossan.
v0.4
io.dump()andio.load()now work with file like objects, which means you can use them with thewith open(...) as f: dump(obj, f)pattern, like you’d do withpickle. #234 by Benjamin Bossan.All scikit-learn estimators are trusted by default. #237 by Edoardo Abati.
Add model_format argument to
skops.hub_utils.init()to be stored in config.json so that we know how to load a model from the repository. #242 by Merve Noyan.Persistence now supports bytes and bytearrays, added tests to verify that LightGBM, XGBoost, and CatBoost work now. #244 by Benjamin Bossan.
card.Cardnow allows to add content to existing sections, using a/to separate the subsections. E.g. usecard.add(**{"Existing section/New section": "content"})to add “content” a new subsection called “New section” to an existing section called “Existing section”. #203 by Benjamin Bossan.
v0.3
Utility function to add arbitrary files to be uploaded to the hub by using
hub_utils.add_files(). #123 by Benjamin Bossan.Add
privateas an optional argument toskops.hub_utils.push()to optionally set the visibility status of a repo when pushing to the hub. #130 by Adrin Jalali.First release of the skops secure persistence feature (#128) by Adrin Jalali and Benjamin Bossan. Visit Secure persistence with skops for more information. This feature is not production ready yet but we’re happy to receive feedback from users.
Fix a bug that resulted in markdown tables being rendered incorrectly if entries contained line breaks. #156 by Benjamin Bossan.
Raise an error instead of warning the user if a given model file is empty. #214 by Adrin Jalali.
Use
huggingface_hubv0.10.1 for model cards, dropmodelcardsdependency. #162 by Benjamin Bossan.Add source links to API documentation. #172 by Ayyuce Demirbas.
Add support to load model if given Path/str to
modelargument inskops.card. #205 by Prajjwal Mishra.
v0.2
Tables, e.g. cross-validation results, can now be added to model cards using the
Card.add_table()method. #90 by Benjamin Bossan.Add method
Card.render()which returns the model card as a string. #94 by Benjamin Bossan.Make
skops.hub_utils.init()atomic. Now it doesn’t leave a trace on the filesystem if it fails for some reason. #60 by Adrin JalaliWhen adding figures or tables, it’s now possible to set
folded=Trueto render the content inside a details tag. #108 by Benjamin Bossan.Add
skops.hub_utils.get_model_outputto get the model’s output using The Hugging Face Hub’s inference API, and return an array with the outputs. #105 by Adrin Jalali.
v0.1
This is the first release of the library. It include two main modules:
skops.hub_utils: tools to create a model repository to be stored on Hugging Face Hub, mainly throughskops.hub_utils.init()andskops.hub_utils.push.skops.card: tools to create a model card explaining what the model does and how it should be used. The model card can then be stored as theREADME.mdfile on the Hugging Face Hub, with pre-populated metadata to help Hub understand the model.
Contributors
Adrin Jalali, Merve Noyan, Benjamin Bossan, Ayyuce Demirbas, Prajjwal Mishra, Francesco Cariaggi, Erin Aho, Thomas Lazarus