- Reduce the logging level for recursive invocations. We handle this case correctly, it did not need to be a warning.
- Drop support for anything older than Python 3.10.
- Use native namespace packages.
- Start publishing manylinux binary wheels.
- Remove some legacy code for Python 2 support to enable compiling with Cython 3.1.
- Add a new base class,
StandardInternalObjectExternalizer
. See PR 120 and issue 117. - Rename
IExternalMappingDecorator
toIExternalStandardDictionaryDecorator
to emphasize that it is only used if you (directly or through a super class) callto_standard_external_dictionary
. A compatibility alias remains. See PR 120 and issue 118. - Docs-deprecated aliases in
nti.externalization.interfaces
now also emit deprecation warnings at runtime. - Other documentation improvements. Sphinx can now run all the doctests (on Python 3); many doctests are still run an Python 2.
- Add support for Python 3.9.
- Depend on BTrees 4.8 and above. This simplifies externalization checks. See issue 111.
Add support for "externalization policies." These are instances of
ExternalizationPolicy
that can be used to tweak certain low-level details of externalization without replacing externalization objects wholesale. They are intended to have a very low performance impact.The only supported detail that can be changed right now is whether the standard created and last modified fields are externalized as Unix timestamps (the default) or as ISO 8601 strings.
See #109
- Change
ILocatedExternalMapping
: Previously it extended the legacyzope.interface.common.mapping.IFullMapping
. Now it extends the modernzope.interface.common.collections.IMapping
. Note that this does not require mutability unlike the older interface. (TheLocatedExternalDict
class provided by this package is fully mutable and implementsIMutableMapping
. It also continues to implementIFullMapping
, but use of that interface is discouraged.) - Change
ILocatedExternalSequence
: Previously it extended the legacyzope.interface.common.sequence.ISequence
. Now it extends the modernzope.interface.common.collections.ISequence
. Note that this does not require mutability unlike the older interface. (TheLocatedExternalList
class provided by this package is fully mutable and implementsIMutableSequence
.) - Fix the interface resolution order for
LocatedExternalList
. Previously, with zope.interface 5, it began implementing bothIMutableSequence
(the new interface fromzope.interface.common.collections
) as well as the older interfaceISequence
(fromzope.interface.common.sequence
); the two have inconsistent resolution orders. Now, it only implementsIMutableSequence
and a subset of the legacy interfaces that do not conflict. See issue 105.
- Correctly fire
IObjectWillUpdateFromExternalEvent
events before updating an object.
- Adapt to a change in zope.container 4.4.0 that exposed unsafe
assumptions that
providedBy(obj)
would return the exact same object with the exact same state on a subsequent call. This was always a bug in the case of concurrency (e.g., if a different thread calleddirectlyProvides
on the same object, or adjusted the__bases__
of some interface in the IRO); the zope.container changes made it possible without concurrency. See zopefoundation/zope.container#38 and #104.
- Fix a faulty assertion error. See issue 102.
- Make instances of
fractions.Fraction
externalize as a string such as"1/3"
. When received by a schema field that can parse this format, such aszope.schema.Rational
(or higher on the numeric tower), this means fractions can be round-tripped. - Support externalizing
decimal.Decimal
objects in the YAML representation.
- Add compatibility with, and require, zope.interface 5.0.
- Document which tagged values are inherited and which are not.
- Stop inheriting
_ext_is_marker_interface
.
- Build with Cython 0.29.14 using '3str' as the language level.
- Add support for Python 3.8.
- Update PyYAML to 5.1 and change the default output style slightly.
- Fix tests with Persistent 4.4.3 and above.
- Support zope.interface 4.7, which lets tagged values on interfaces
be inherited, when using
<registerAutoPackageIO>
on a module that had multiple objects implementing a derived interface. See issue 97.
- Support
IFromBytes
fields introduced by zope.schema 4.8.0. See issue 92. - Make
validate_field_value
(and by extensionInterfaceObjectIO.update_from_external_object
) callfromObject
defined by any fields for non-byte and non-text data. Previously, only if the field raised aWrongContainedTypeError
wouldfromObject
be called.
- Add support for zope.schema 4.7.0 and nti.schema 1.5.0. Drop support
for older versions, which includes dropping support for
dm.zope.schema.Object
fields.
- The
@WithRepr
decorator takes into account the updated default repr of Persistent objects with persistent 4.4 and doesn't hide it. - Subclasses of
ExternalizableInstanceDict
that have non-str (unicode on Python 2, bytes on Python 3) keys in their__dict__
do not throwTypeError
when externalizing. Instead, the non-str values are converted to strs (using ASCII encoding) and the_p_changed
attribute, if any, is set.
- The
registry
argument to most functions is deprecated and ignored. Instead of making calls toregistry.queryAdapter
, we now invoke the interface directly. For example,IInternalObjectExternalizer(containedObject)
. This lets individual objects have a say if they already provide the interface without going through the legacy code paths (it also calls__conform__
on the object if needed).
- Allow subclasses of
InterfaceObjectIO
to have non-frozenset values for_ext_primitive_out_ivars_
. This issues a warning and in the future will be a TypeError.
- Better support for internalizing anonymous value objects discovered
in a
Dict
value. Now, they won't raise aComponentLookupError
whenrequire_updater
is True, and they will be given aMimeType
based on the schema (if they don't have one).
- Avoid a
TypeError
fromvalidate_named_field_value
when external objects have unicode keys. LocatedExternalDict
objects accept more constructor arguments and allow arbitrary attributes.
InterfaceObjectIO
only returns an anonymous factory forIDict
fields when it wants objects for the value.StandardExternalFields
andStandardInternalFields
are deprecated aliases innti.externalization.externalization
.update_from_external_object
properly handles the case whereINamedExternalizedObjectFactoryFinder
andIInternalObjectUpdater
are registered with different levels of specificity, and the finder also implementsIInternalObjectUpdater
. Before, the finder would, perhaps incorrectly, be used as the updater.
- Objects inheriting from
InterfaceObjectIO
and registered with the component registry (in ZCML) forIInternalObjectIO
can still be found and used asINamedExternalizedObjectFactoryFinder
, an interface implemented byInterfaceObjectIO
throughIInternalObjectIOFinder
. A warning will be issued to update the registration (which generally means removing theprovides
line in ZCML). ExternalizableInstanceDict
no longer inherits fromAbstractDynamicIO
, it just implements the same interface (with the exception of many of the_ext
methods). This class is deprecated.- Formally document the
notify_modified
member ofnti.externalization.internalization
.notifyModified
is a deprecated alias.
- Make
InterfaceObjectIO._ext_self
readable from Python, even though that is not documented (and may change again in the future). Document the intended API,_ext_replacement()
. See issue 73. - Make
AbstractDynamicObjectIO._ext_getattr
handle a default value, and add_ext_replacement_getattr
for when it will only be called once. See issue 73.
- The
@NoPickle
decorator also works withPersistent
subclasses (and may or may not work with multiple-inheritance subclasses ofPersistent
, depending on the MRO, but that's always been the case for regular objects). APersistent
subclass being decorated with@NoPickle
doesn't make much sense, so aRuntimeWarning
is issued. A warning is also issued if the class directly implements one of the pickle protocol methods. - Updating objects that use
createFieldProperties
or otherwise haveFieldProperty
objects in their type is at least 10% faster thanks to avoiding double-validation due to a small monkey-patch onFieldProperty
. See issue 67. - Proxies around objects that implement
toExternalObject
are allowed again; the proxied object'stoExternalObject
will be called. - The signature for
updateFromExternalObject()
has been tightened. It should be(self, external_object, context, **kwargs)
, where**kwargs
is optional, as is context.**kwargs
currently contains nothing useful. Uses ofdataserver=None
in the signature will generate a warning. This may be tightened further in the future. See issue 30. __ext_ignore_updateFromExternalObject__
is officially deprecated and generates a warning.update_from_external_object
caches certain information about the types of the updater objects, making it 8-25% faster.update_from_external_object
mutates sequences contained in a dict in-place instead of overwriting with a new list.update_from_external_object
mutates sequences at the top level instead of returning a new list.- Add support for finding factories for incoming data which do not
specify a MIME type or class field based on the key they are
assigned to. This aids in consuming data produced by foreign systems
or using
Dict
schema fields that require modelled values. See issue 51 and PR 68. - Schemas that use
InterfaceObjectIO
(including through the ZCML directiveregisterAutoPackageIO
) can useDict
fields more easily on internalization (externalization has always worked): They automatically internalize their values by treating theDict
as anonymous external data. - Strings can automatically be adapted into
ITimeDelta
objects.
- The low levels of externalization no longer catch and hide POSKeyError. This indicates a problem with the database. See #60
- Remove support for
object_hook
inupdate_from_external_object
. See #29. - A number of deprecated aliases for moved functions have been removed.
- On CPython, some of the modules are compiled as extension modules
using Cython for a 10-30% increase in speed. Set the
PURE_PYTHON
environment variable to disable this at runtime. - The unused, undocumented method
stripSyntheticKeysFromExternalDictionary
was removed from instances ofExternalizableDictionaryMixin
. Use the import instead. - Unused keyword arguments for
to_standard_external_dictionary
andto_minimal_standard_external_dictionary
now produce a warning. In the future, extra keyword arguments will be an error. notifyModified
no longer accepts theeventFactory
argument.- The
notify_modified
alias fornotifyModified
has been removed. - Decorating external mappings and external objects handled
decorate_callback
differently. This argument is only used whendecorate
is false. This argument is also confusing and should be considered deprecated. choose_field
no longer has the undocumented conversion behaviour for the CREATOR external field name.
- First PyPI release.
- Add support for Python 3.
- Drop support for externalizing to plists. See #21
- Reach 100% test coverage and ensure we remain there through CI.
- Introduce
nti.externalization.extension_points
to hold hook functions. Move the Pyramid integration there (and deprecate that). Also move the NTIID support there (but the old name works too). See #27 - Deprecate
nti.externalization.internalization.register_legacy_search_module
. See #35 - Stop
ext:registerAutoPackageIO
from registering the legacy class-name based factories by default. If you need class-name based factories, there are two options. The first is to explicitly registerIClassObjectFactory
objects in ZCML (we could add a scanning directive to make that more convenient for large numbers of classes), and the second is to setregister_legacy_search_module
to a true value in the ZCML directive forext:registerAutoPackageIO
. Note that we expect the behaviour of this attribute to change in the near future. See #33 - Make
ext:registerAutoPackageIO
perform legacy class registrations when the configuration context executes, not when the directive runs. This means that conflicts in legacy class names will be detected at configuration time. It also means that legacy class names can be registered locally withz3c.baseregistry
(previously they were always registered in the global site manager). See #28 - Drop dependency on
zope.preference
andzope.annotation
. They were not used by this package, although ourconfigure.zcml
did include them. If you usezope.preference
orzope.annotation
, please include them in your own ZCML file. - Drop hard dependency on Acquisition. It is still used if available and is used in test mode.
- Add public implementations of
IMimeObjectFactory
andIClassObjectFactory
innti.externalization.factory
. - Drop dependency on
nti.zodb
and itsPersistentPropertyHolder
. The datastructures innti.externalization.persistence
no longer extend that class; if you have further subclasses that addnti.zodb.peristentproperty.PropertyHoldingPersistent
properties, you'll need to be sure to mixin this class now. See #43 - Add the
<ext:classObjectFactory>
directive for registeringClass
based factories. (Note: MIME factories are preferred.) - Callers of
to_standard_external_dictionary
(which includes AutoPackageScopedInterfaceIO) will now automatically get aMimeType
value if one can be found. Previously only callers ofto_minimal_standard_external_dictionary
would.