All notable changes to this project will be documented in this file.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
v1.1.0 — 2023-02-27
Overview of what's new in this version:
fauxdoc
is now fully typed and passesmypy --strict
checks.- Much refactoring. Fixing type hints revealed some underlying issues, and I've applied fixes and changes while leaving the public API as intact as possible — see details below about what exactly has changed.
- A small number of deprecations to be removed in v2. See details below.
- Previously undefined behavior, mainly around instance attributes, has been defined, documented, and tested. Attributes that are not read-only now have defined behavior when they are set after object instantiation.
- A
py.typed
file to indicate that the package now has type hints. - New
mypy_strict
tox environment for runningmypy
tests. - New tox environments for testing a package built using
build_package
against a target Python version:py37-test_built_package
throughpy311-test_built_package
. - A new kwarg for initializing
fauxdoc.emitters.choice.Choice
instances:cum_weights
can now be supplied, if needed. Note that you can only supplyweights
orcum_weights
— not both. All previous args/kwargs still work as before. - A
fauxdoc.emitters.fromfields.SourceFieldGroup
class. This is a subtype offauxdoc.groups.ObjectGroup
, used infauxdoc.emitters.fromfield
emitters to represent groups of source fields. It now implements thesingle_valued
property that was previously only a private attribute on thefauxdoc.emitters.fromfields.CopyFields
class. - Additions to
fauxdoc.emitters.fromfields
emitters (CopyFields
andBasedOnFields
):- A new public attribute,
single_valued
, for bothCopyFields
andBasedOnFields
. This attribute was previously private. set_source_fields
method, onCopyFields
andBasedOnFields
— used to set thesource
attribute from one or a list ofField
instances. (You can setsource
directly, but that requires afauxdoc.emitters.fromfields.SourceFieldGroup
instance. This is just for convenience.)set_action_function
method, onBasedOnFields
— used to set theaction
attribute from a function. (You can setaction
directly, but that requires afauxdoc.emitters.wrappers.BoundWrapper
instance. This is just for convenience.)
- A new public attribute,
- Two new static methods on
fauxdoc.emitters.fixed.Iterative
, which move previously internal operations into utilities that can be used by external agents:check_iter_factory
— validates that an iterator factory function/method does not return an empty iterator, and raises a ValueError if it does.make_infinite_iter
— creates an iterator from an iterator factory that loops infinitely.
- A new
check_seq_iter_factory
static method onfauxdoc.emitters.fixed.Sequential
allows validating that an iterator factory function/method probably generates an iterator that iterates over a sequence. - A
fauxdoc.emitters.wrappers.BoundWrapper
class. Used to encapsulate a user-provided wrapper function, bind it to an object that provides RNG, and allow validating a given signature against the wrapper function's signature. - A
set_wrapper_function
method onfauxdoc.emitters.wrappers.WrapOne
andfauxdoc.emitters.wrappers.WrapMany
— used to set thewrapper
attribute from a function or other callable. (You can setwrapper
directly, but that requires afauxdoc.emitters.wrappers.BoundWrapper
instance. This is just for convenience.) - A new
set_fields
method, onfauxdoc.profile.Schema
— used to setfields
more naturally, without forcing the user to supply afauxdoc.groups.ObjectMap
instance. (You can still setfields
directly, as anObjectMap
.) - A
fauxdoc.typing.ImplementsRNG
protocol, for representing types that implement anrng
attribute andseed
method — such asField
s and various emitters. - New
fauxdoc.typing.OrderedDict
andfauxdoc.typing.UserList
types, to control for the fact that thecollections
versions of these types are not subscriptable in Python 3.7 and 3.8 (which is needed for type hints). For Python 3.7 and 3.8, a__getitem__
method is monkey-patched ontocollections.OrderedDict
andcollections.UserList
, to make them subscriptable. - New type aliases in
fauxdoc.typing
:F
— a TypeVar for float types.CT
— general-purpose covariant TypeVar.SourceT
— a contravariant TypeVar for e.g. callable arguments and other types that represent source data.OutputT
— a covariant TypeVar for e.g. callable return values that represent output data.FieldReturn
— represents the return type when callingfauxdoc.profile.Field
instances.
- A new
fauxdoc.warn
module, which contains a function (get_deprecated_attr
) for injecting a deprecation warning when a user gets a deprecated module or object attribute. (It's called from the__getattr__
method of the applicable module or object.)
- The minimum
pytest
version for Python 3.7 through 3.9 has been bumped up from 3.0.0 to 3.8.0. This is to allow testing deprecation warnings. - Tox environment
build_package
no longer triespip install
ing the built package. It's assumed you'll use the new*-test_built_package
environments to test the built package, which will of course have to install it. - Comparing a
fauxdoc.dtrange.DateOrTimeRange
instance to another type of object is explicitly not supported and returnsNotImplemented
. - On
fauxdoc.emitters.choice.Choice
, any sequences provided for theweights
andcum_weights
attributes are now cast to tuples on assignment so that they are immutable once assigned. (You can set a brand new sequence, but you cannot change individual elements.) fauxdoc.emitters.fromfields.BasedOnFields
no longer inherits fromfauxdoc.emitters.fromfields.CopyFields
. The shared functionality thatCopyFields
previously provided is now implemented asfauxdoc.emitters.fromfields.SourceFieldGroup
, which is now used for thesource
attribute on instances of both classes. If you setsource
directly, you must now give it aSourceFieldGroup
instance.fauxdoc.emitters.fromfields.BasedOnFields
now uses thefauxdoc.emitters.wrappers.BoundWrapper
class for itsaction
attribute. This moves all of the relevant functionality that was basically duplicated from thewrappers
emitters out into theBoundWrapper
. If you setaction
directly, you must now give it aBoundWrapper
instance.fauxdoc.emitters.fromfields.BasedOnFields
now validates the expected call signature of the providedaction
function when it's first set, not later when it's first called, so that the user gets notified immediately if theiraction
function is not configured correctly.- The
iterator
instance attribute offauxdoc.emitters.fixed.Iterative
andfauxdoc.emitters.fixed.Sequential
is now a read-only property. It should never have been settable in the first place, as it's impossible to make this attribute settable in a way that makes any sense. fauxdoc.emitters.fixed.Sequential
no longer inherits fromfauxdoc.emitters.fixed.Iterative
. Much of the specific functionality thatSequential
needed to use fromIterative
has been moved into public methods onIterative
, whichSequential
now calls directly.fauxdoc.emitters.wrappers.WrapOne
andfauxdoc.emitters.wrappers.WrapMany
no longer inherit fromfauxdoc.emitters.wrappers.Wrap
. The shared functionality that theWrap
parent class provided is now implemented asfauxdoc.emitters.wrappers.BoundWrapper
, which is now used for thewrapper
attribute on instances ofWrap
,WrapOne
, andWrapMany
. If you setwrapper
directly, you must now give it aBoundWrapper
instance.- Each of
fauxdoc.emitters.wrappers.WrapOne
andfauxdoc.emitters.wrappers.WrapMany
now validates the expected call signature of the providedwrapper
function when it's set, not later when it's first called, so that the user gets notified immediately if theirwrapper
function is not configured correctly. fauxdoc.profile.Field
now inherits fromfauxdoc.mixins.RandomWithChildrenMixin
instead of justRandomMixin
. This moves the functionality related to setting, resetting, and seeding children emitters fromField
intoRandomWithChildrenMixin
.- On
fauxdoc.profile.Field
, themulti_valued
attribute is now read-only. This attribute should never have been settable, as it is a fully computed attribute (based onrepeat_emitter
). - On
fauxdoc.profile.Schema
, thehidden_fields
andpublic_fields
were already read-only, dynamic properties; now they are no longer even cached. They were of course never meant to be mutable — but now, if you try changing them as dictionaries, your changes will not be saved. - The
fauxdoc.typing.EmitterLike
protocol is now more robust. It's now generic, so you can for instance useEmitterLike[int]
to indicate that an Emitter-like type emitsint
s. It now includes propertiesnum_unique_values
andemits_unique_values
. And__call__
is overloaded to show that passing None returns a single atomic value, while passing an integer returns a list of values. - The
fauxdoc.typing.RandomEmitterLike
protocol now inherits from bothImplementsRNG
andEmitterLike
, and it is now generic. - The
fauxdoc.typing.FieldLike
protocol is now generic.
fauxdoc.emitters.fixed.Sequential.iterator_factory
: This is currently settable but will become read-only in the future. Instead of settingiterator_factory
to change the sequence that aSequential
instance emits, you should create a newSequential
instance using the new sequence.fauxdoc.emitters.wrappers.Wrap
: Usewrappers.WrapOne
orWrapMany
.fauxdoc.emitters.Wrap
: Useemitters.WrapOne
orWrapMany
.fauxdoc.typing.BoolEmitterLike
: UseEmitterLike[bool]
.fauxdoc.typing.EmitterLikeCallable
: UseEmitterLike
.fauxdoc.typing.Number
: Usefloat
.fauxdoc.typing.IntEmitterLike
: UseEmitterLike[int]
.fauxdoc.typing.StrEmitterLike
: UseEmitterLike[str]
.
- Many, many type hints throughout the package have been added or altered to resolve
mypy
errors. In some cases, specific function or method implementations have been tweaked to better accommodate added type hints. - Many docstrings that were missing or incomplete have been added or updated.
- On
fauxdoc.emitters.choice.Choice
instances, setting either of theweights
orcum_weights
attributes now correctly updates object state. The provided list of weights or cumulative weights is validated to ensure it contains the same number of entries as there areitems
. Whichever "weights" attribute is set, the other is updated with the correct values. And, if thereplace
attribute is False, the global items shuffle is regenerated to reflect the new weights. - On
fauxdoc.emitters.choice.Choice
instances, setting either of thereplace
orreplace_only_after_call
attributes may update the other to ensure valid object state. I.e., if the latter is True then the former must be True; if the former is False then the latter must also be False. Additionally, whenreplace
changes to False, the global items shuffle is regenerated to reflect the current object state. - On
fauxdoc.emitters.fixed.Static
instances, setting thevalue
attribute now correctly updates the contents of theitems
attribute with the new value. - On
fauxdoc.emitters.fixed.Iterative
andfauxdoc.emitters.fixed.Sequential
instances, setting theiterator_factory
attribute now performs appropriate validation on the iterator that the factory makes and then correctly regenerates theiterator
attribute. OnSequential
instances, it also repopulates theitems
attribute using the contents of the new iterator. - During a call to
fauxdoc.emitters.text.Text
'semit_many
method, a private_get_words_iterator
method is used to generate words from theword_emitter
. Whenword_emitter.replace_only_after_call
is True, then it attempts to generate a set of unique words for each text string. Previously, it based this onword_emitter.num_unique_items
. This has been changed so that it bases this onword_emitter.num_unique_values
. (The difference being thatnum_unique_items
might include duplicate words in separate items, whilenum_unique_values
only counts truly unique words.) - On
fauxdoc.profile.Schema
,fields
is both settable and mutable — i.e., you can add or modify fields simply by editingfields
as you would any dictionary. Thehidden_fields
andpublic_fields
attributes are now calculated fully dynamically, meaning these now automatically update whenfields
changes. Previously they did not.
v1.0.0 - 2022-11-02
First public release.
fauxdoc.emitter
— Emitter abstract base class to be used for all data emitters. Provides basic interface for creating callable emitter objects, which can have different underlying methods for emitting one versus many values, provide information about whether or not they emit unique values, and provide the number of unique values they emit. Emitters output values when called.fauxdoc.group
andfauxdoc.mixins
— Helper classes and mixins for creating emitters that use random-number generation, generate compound values using data from atomic children emitters, and emit values from a set sequence of items.fauxdoc.dtrange
— Tools for producing and working with ranges ofdatetime.datetime
anddatetime.time
objects, including a simplerange
-like factory (fauxdoc.dtrange.dtrange
).fauxdoc.mathtools
— Math-related utility functions. Includes functions for creating gaussian and poisson distributions, clamping a number to fit within a specific range, and randomly shuffling a list based on weights.fauxdoc.profile
— Classes for building complete data profiles from emitter instances: Schema and Field. A Schema contains a set of named Field instances and outputs a data record when called. Each Field encapsulates an emitter and can be set to control the chances that any value will be output along how many values are output, per data record.fauxdoc.emitters.choice
— Choice emitters, used to select random values. Provides an optimized implementation using optional weights and optional replacement. Also provides factory methods for creating choice emitters that use common weight distributions (poisson, gaussian).fauxdoc.emitters.fixed
— Fixed emitters, used for emitting predefined values: a single static value, values from an iterator, or values from a sequence.fauxdoc.emitters.text
— Emitters for generating randomized text-like strings, both single words and multi-word sentences.fauxdoc.emitters.fromfields
— Emitters whose output should be based on values already generated via other fields (in context of a schema). They may copy values directly or copy and then modify values.fauxdoc.emitters.wrappers
— Emitters that wrap other emitter instances in order to modify their output. For example, you may have an emitter that generates random datetime objects, and you might have several functions for converting your datetime objects to strings of various formats. You could easily create wrapper emitters that wrap your datetime emitter and use the conversion functions to generate formatted strings without having to create individual emitter classes to do this.- Preliminary type-hints, not (yet) tested via a type checker. They are therefore currently quite broken.
- A modern
pyproject.toml
-based configuration plus support for Python 3.7, 3.8, 3.9, 3.10, and 3.11.
- Just a historical note to say that this project originated from the UNT Libraries' catalog-api project, recent development of which has moved over to our private GitLab server. When we first pulled it into its own repository (also on our private GitLab), we named it
solrfixtures
and used Poetry to manage dependencies. Shortly before releasing v1.0.0, we renamed the projectfauxdoc
, moved it to GitHub, removed the reliance on Poetry (and standardizedpyproject.toml
), and implemented GitHub actions for CI. It has also been fully and completely refactored compared to its original form. It was never public until v1.0.0, so I'm not bothering documenting those changes here.