diff --git a/play.ipynb b/play.ipynb new file mode 100644 index 0000000..f4f87ec --- /dev/null +++ b/play.ipynb @@ -0,0 +1,878 @@ +{ + "metadata": { + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.9.6" + }, + "orig_nbformat": 4, + "kernelspec": { + "name": "python3", + "display_name": "Python 3.9.6 64-bit ('xp-env': conda)" + }, + "interpreter": { + "hash": "652fa5bafa2b8576ce7064e959b44480f5f8a15c86e6a8f20ca39abe1301c9a8" + } + }, + "nbformat": 4, + "nbformat_minor": 2, + "cells": [ + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "output_type": "error", + "ename": "AttributeError", + "evalue": "`SummaryEstimator.key` has not yet been assigned a value.", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mAttributeError\u001b[0m Traceback (most recent call last)", + "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0;32mfrom\u001b[0m \u001b[0mmetrics_repo\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mmodel_specs\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0mSummaryEstimator\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", + "\u001b[0;32m~/Repositories/netflix/metrics-repo/metrics_repo/__init__.py\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[1;32m 4\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0msnapy\u001b[0m \u001b[0;31m# noqa: F401; Import snapy before kragle to use snapy magics\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 5\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 6\u001b[0;31m \u001b[0;32mfrom\u001b[0m \u001b[0mmetrics_repo\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mlib\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mbuilder\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0mBuilder\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 7\u001b[0m \u001b[0;32mfrom\u001b[0m \u001b[0mmetrics_repo\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mlib\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mhelpers\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0mbuild_library\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 8\u001b[0m \u001b[0;32mfrom\u001b[0m \u001b[0mmetrics_repo\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mlib\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mpaths\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0mBUILDERS_DIR\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mMETRICS_DIR\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mREPORTS_DIR\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mSOURCES_DIR\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mQUERIES_DIR\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mFILTERS_DIR\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mDIMENSIONS_DIR\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mREPORT_CONFIGURATIONS_DIR\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mCONFIG_SOURCES_DIR\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m~/Repositories/netflix/metrics-repo/metrics_repo/lib/__init__.py\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[0;34m\"\"\"Utility functions.\"\"\"\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 2\u001b[0;31m \u001b[0;32mfrom\u001b[0m \u001b[0;34m.\u001b[0m\u001b[0madd_on\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0mAddOn\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 3\u001b[0m \u001b[0;32mfrom\u001b[0m \u001b[0;34m.\u001b[0m\u001b[0mafter_steps\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0mAfterExecutionStep\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 4\u001b[0m \u001b[0;32mfrom\u001b[0m \u001b[0;34m.\u001b[0m\u001b[0manalysis_context\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0mAnalysisContext\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 5\u001b[0m \u001b[0;32mfrom\u001b[0m \u001b[0;34m.\u001b[0m\u001b[0mconfig\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0mCONFIG\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m~/Repositories/netflix/metrics-repo/metrics_repo/lib/add_on.py\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[1;32m 5\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 6\u001b[0m \u001b[0;32mfrom\u001b[0m \u001b[0mmetrics_repo\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mlib\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mdimension\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0mDimension\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 7\u001b[0;31m \u001b[0;32mfrom\u001b[0m \u001b[0mmetrics_repo\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mlib\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mmetric\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0mMetric\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 8\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 9\u001b[0m \u001b[0;32mfrom\u001b[0m \u001b[0;34m.\u001b[0m\u001b[0merrors\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0mValidationError\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m~/Repositories/netflix/metrics-repo/metrics_repo/lib/metric.py\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[1;32m 38\u001b[0m \u001b[0minit_overflow_attr\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;34m'options'\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 39\u001b[0m )\n\u001b[0;32m---> 40\u001b[0;31m \u001b[0;32mclass\u001b[0m \u001b[0mMetric\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mmetaclass\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mSubclassRegisteringMeta\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 41\u001b[0m \"\"\"\n\u001b[1;32m 42\u001b[0m \u001b[0mDefines\u001b[0m \u001b[0ma\u001b[0m \u001b[0mmetric\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m~/Repositories/netflix/metrics-repo/metrics_repo/lib/metric.py\u001b[0m in \u001b[0;36mMetric\u001b[0;34m()\u001b[0m\n\u001b[1;32m 187\u001b[0m \u001b[0mcompression_overrides\u001b[0m\u001b[0;34m:\u001b[0m \u001b[0mDict\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0mstr\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mTerm\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m{\u001b[0m\u001b[0;34m}\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 188\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 189\u001b[0;31m \u001b[0mmodels\u001b[0m\u001b[0;34m:\u001b[0m \u001b[0mList\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0mModel\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m[\u001b[0m\u001b[0mDescriptiveStats\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mTTestStats\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 190\u001b[0m \u001b[0mp_value_threshold\u001b[0m\u001b[0;34m:\u001b[0m \u001b[0mfloat\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;36m0.05\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 191\u001b[0m \u001b[0mearly_stopping_alpha\u001b[0m\u001b[0;34m:\u001b[0m \u001b[0mOptional\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0mfloat\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;32mNone\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m\u001b[0m in \u001b[0;36m__init__\u001b[0;34m(self, key, data, engine, measure, link, hyperparams, estimations, label, visualizations, layout, compression_requirements, get_cell_significance, summary_estimators, treatment_effect_estimators, treatment_family_estimators, segment_by_covariates, summary_statistics, treatment_effect_statistics)\u001b[0m\n", + "\u001b[0;32m~/Repositories/github/spec-classes/spec_classes/methods/core.py\u001b[0m in \u001b[0;36minit\u001b[0;34m(spec_cls, self, **kwargs)\u001b[0m\n\u001b[1;32m 85\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mcopy_required\u001b[0m \u001b[0;32mand\u001b[0m \u001b[0;32mnot\u001b[0m \u001b[0misinstance\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mvalue\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m(\u001b[0m\u001b[0mint\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mstr\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mtuple\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 86\u001b[0m \u001b[0mvalue\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mcopy\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mdeepcopy\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mvalue\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 87\u001b[0;31m \u001b[0msetattr\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mattr\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mvalue\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 88\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 89\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0minstance_metadata\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0minit_overflow_attr\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m~/Repositories/github/spec-classes/spec_classes/methods/core.py\u001b[0m in \u001b[0;36m__setattr__\u001b[0;34m(self, attr, value, force)\u001b[0m\n\u001b[1;32m 162\u001b[0m \u001b[0mattr_spec\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m__spec_class__\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mattrs\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mget\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mattr\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 163\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mattr_spec\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 164\u001b[0;31m \u001b[0mWithAttrMethod\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mwith_attr\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mattr_spec\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mvalue\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0m_inplace\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;32mTrue\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 165\u001b[0m \u001b[0;32mreturn\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 166\u001b[0m \u001b[0mmutate_attr\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mattr\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mattr\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mvalue\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mvalue\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0minplace\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;32mTrue\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mtype_check\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;32mTrue\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mforce\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mforce\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m~/Repositories/github/spec-classes/spec_classes/methods/scalar.py\u001b[0m in \u001b[0;36mwith_attr\u001b[0;34m(attr_spec, self, _new_value, _inplace, _if, **attrs)\u001b[0m\n\u001b[1;32m 29\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 30\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mattr_spec\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mis_collection\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 31\u001b[0;31m _new_value = attr_spec.collection_mutator_type(\n\u001b[0m\u001b[1;32m 32\u001b[0m \u001b[0mattr_spec\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mtype\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mcollection\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0m_new_value\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mname\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mattr_spec\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mname\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 33\u001b[0m ).prepare(item_preparer=functools.partial(attr_spec.prepare_item, self)).collection\n", + "\u001b[0;32m~/Repositories/github/spec-classes/spec_classes/collections/sets.py\u001b[0m in \u001b[0;36mprepare\u001b[0;34m(self, item_preparer)\u001b[0m\n\u001b[1;32m 33\u001b[0m \u001b[0mitems\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mcollection\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 34\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mcollection\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_create_collection\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 35\u001b[0;31m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0madd_items\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mitems\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mitem_preparer\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 36\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 37\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0;32mnot\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mcollection\u001b[0m \u001b[0;32mor\u001b[0m \u001b[0;32mnot\u001b[0m \u001b[0mitem_preparer\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m~/Repositories/github/spec-classes/spec_classes/collections/sets.py\u001b[0m in \u001b[0;36madd_items\u001b[0;34m(self, items, preparer)\u001b[0m\n\u001b[1;32m 79\u001b[0m \u001b[0mpreparer\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mpreparer\u001b[0m \u001b[0;32mor\u001b[0m \u001b[0;34m(\u001b[0m\u001b[0;32mlambda\u001b[0m \u001b[0mitem\u001b[0m\u001b[0;34m:\u001b[0m \u001b[0mitem\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 80\u001b[0m \u001b[0;32mfor\u001b[0m \u001b[0mitem\u001b[0m \u001b[0;32min\u001b[0m \u001b[0mitems\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 81\u001b[0;31m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0madd_item\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mpreparer\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mitem\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 82\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 83\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m~/Repositories/github/spec-classes/spec_classes/collections/sets.py\u001b[0m in \u001b[0;36madd_item\u001b[0;34m(self, item, replace, attrs)\u001b[0m\n\u001b[1;32m 67\u001b[0m ):\n\u001b[1;32m 68\u001b[0m \u001b[0mitem\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mitem_spec_type\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mitem\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 69\u001b[0;31m return self._mutate_collection(\n\u001b[0m\u001b[1;32m 70\u001b[0m \u001b[0mvalue_or_index\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mitem\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 71\u001b[0m \u001b[0mextractor\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_extractor\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m~/Repositories/github/spec-classes/spec_classes/collections/base.py\u001b[0m in \u001b[0;36m_mutate_collection\u001b[0;34m(self, value_or_index, extractor, inserter, require_pre_existent, new_item, transform, attrs, attr_transforms, replace, inplace)\u001b[0m\n\u001b[1;32m 73\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mcollection\u001b[0m \u001b[0;32mis\u001b[0m \u001b[0mMISSING\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 74\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mcollection\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_create_collection\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 75\u001b[0;31m index, old_item = extractor(\n\u001b[0m\u001b[1;32m 76\u001b[0m \u001b[0mvalue_or_index\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mraise_if_missing\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mrequire_pre_existent\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 77\u001b[0m )\n", + "\u001b[0;32m~/Repositories/github/spec-classes/spec_classes/collections/sets.py\u001b[0m in \u001b[0;36m_extractor\u001b[0;34m(self, value_or_index, raise_if_missing)\u001b[0m\n\u001b[1;32m 15\u001b[0m return (\n\u001b[1;32m 16\u001b[0m \u001b[0mvalue_or_index\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 17\u001b[0;31m \u001b[0mvalue_or_index\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mvalue_or_index\u001b[0m \u001b[0;32min\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mcollection\u001b[0m \u001b[0;32melse\u001b[0m \u001b[0mMISSING\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 18\u001b[0m )\n\u001b[1;32m 19\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m~/Repositories/github/spec-classes/spec_classes/types/keyed.py\u001b[0m in \u001b[0;36m__contains__\u001b[0;34m(self, item_or_key)\u001b[0m\n\u001b[1;32m 274\u001b[0m \u001b[0;31m# Check whether item_or_key exists as a value\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 275\u001b[0m \u001b[0;32mtry\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 276\u001b[0;31m \u001b[0mkey\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mkey\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mitem_or_key\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 277\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mkey\u001b[0m \u001b[0;32min\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_dict\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 278\u001b[0m return (\n", + "\u001b[0;32m~/Repositories/github/spec-classes/spec_classes/types/keyed.py\u001b[0m in \u001b[0;36m__get_item_key\u001b[0;34m(self, item)\u001b[0m\n\u001b[1;32m 39\u001b[0m \u001b[0mkey\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mitem\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m__spec_class__\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mkey\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 40\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mkey\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 41\u001b[0;31m \u001b[0;32mreturn\u001b[0m \u001b[0mgetattr\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mitem\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mkey\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 42\u001b[0m \u001b[0;32mtry\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 43\u001b[0m \u001b[0mhash\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mitem\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m~/Repositories/github/spec-classes/spec_classes/methods/core.py\u001b[0m in \u001b[0;36m__getattr__\u001b[0;34m(self, attr)\u001b[0m\n\u001b[1;32m 138\u001b[0m \u001b[0;32mand\u001b[0m \u001b[0;32mnot\u001b[0m \u001b[0minspect\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0misdatadescriptor\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mgetattr\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m__class__\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mattr\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;32mNone\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 139\u001b[0m ):\n\u001b[0;32m--> 140\u001b[0;31m raise AttributeError(\n\u001b[0m\u001b[1;32m 141\u001b[0m \u001b[0;34mf\"`{self.__class__.__name__}.{attr}` has not yet been assigned a value.\"\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 142\u001b[0m )\n", + "\u001b[0;31mAttributeError\u001b[0m: `SummaryEstimator.key` has not yet been assigned a value." + ] + } + ], + "source": [ + "from metrics_repo.model_specs import SummaryEstimator" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [], + "source": [ + "from spec_classes import spec_class" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [], + "source": [ + "@spec_class(key='key')\n", + "class MySpec:\n", + " key: str" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": [ + "MySpec(key='asd')" + ] + }, + "metadata": {}, + "execution_count": 6 + } + ], + "source": [ + "MySpec('asd')" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [ + { + "output_type": "stream", + "name": "stderr", + "text": [ + "WARNING 2021-08-31 17:35:37,371 reporting.py(18) `RCausalModelEngine.__repr__` overrides interface `EstimationEngine.__repr__` without using the `@override` decorator.\n" + ] + }, + { + "output_type": "error", + "ename": "AttributeError", + "evalue": "`SummaryEstimator.key` has not yet been assigned a value.", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mAttributeError\u001b[0m Traceback (most recent call last)", + "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0;32mimport\u001b[0m \u001b[0mmetrics_repo\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", + "\u001b[0;32m~/Repositories/netflix/metrics-repo/metrics_repo/__init__.py\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[1;32m 4\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0msnapy\u001b[0m \u001b[0;31m# noqa: F401; Import snapy before kragle to use snapy magics\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 5\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 6\u001b[0;31m \u001b[0;32mfrom\u001b[0m \u001b[0mmetrics_repo\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mlib\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mbuilder\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0mBuilder\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 7\u001b[0m \u001b[0;32mfrom\u001b[0m \u001b[0mmetrics_repo\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mlib\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mhelpers\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0mbuild_library\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 8\u001b[0m \u001b[0;32mfrom\u001b[0m \u001b[0mmetrics_repo\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mlib\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mpaths\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0mBUILDERS_DIR\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mMETRICS_DIR\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mREPORTS_DIR\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mSOURCES_DIR\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mQUERIES_DIR\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mFILTERS_DIR\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mDIMENSIONS_DIR\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mREPORT_CONFIGURATIONS_DIR\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mCONFIG_SOURCES_DIR\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m~/Repositories/netflix/metrics-repo/metrics_repo/lib/__init__.py\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[0;34m\"\"\"Utility functions.\"\"\"\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 2\u001b[0;31m \u001b[0;32mfrom\u001b[0m \u001b[0;34m.\u001b[0m\u001b[0madd_on\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0mAddOn\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 3\u001b[0m \u001b[0;32mfrom\u001b[0m \u001b[0;34m.\u001b[0m\u001b[0mafter_steps\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0mAfterExecutionStep\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 4\u001b[0m \u001b[0;32mfrom\u001b[0m \u001b[0;34m.\u001b[0m\u001b[0manalysis_context\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0mAnalysisContext\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 5\u001b[0m \u001b[0;32mfrom\u001b[0m \u001b[0;34m.\u001b[0m\u001b[0mconfig\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0mCONFIG\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m~/Repositories/netflix/metrics-repo/metrics_repo/lib/add_on.py\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[1;32m 5\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 6\u001b[0m \u001b[0;32mfrom\u001b[0m \u001b[0mmetrics_repo\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mlib\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mdimension\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0mDimension\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 7\u001b[0;31m \u001b[0;32mfrom\u001b[0m \u001b[0mmetrics_repo\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mlib\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mmetric\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0mMetric\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 8\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 9\u001b[0m \u001b[0;32mfrom\u001b[0m \u001b[0;34m.\u001b[0m\u001b[0merrors\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0mValidationError\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m~/Repositories/netflix/metrics-repo/metrics_repo/lib/metric.py\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[1;32m 38\u001b[0m \u001b[0minit_overflow_attr\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;34m'options'\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 39\u001b[0m )\n\u001b[0;32m---> 40\u001b[0;31m \u001b[0;32mclass\u001b[0m \u001b[0mMetric\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mmetaclass\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mSubclassRegisteringMeta\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 41\u001b[0m \"\"\"\n\u001b[1;32m 42\u001b[0m \u001b[0mDefines\u001b[0m \u001b[0ma\u001b[0m \u001b[0mmetric\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m~/Repositories/netflix/metrics-repo/metrics_repo/lib/metric.py\u001b[0m in \u001b[0;36mMetric\u001b[0;34m()\u001b[0m\n\u001b[1;32m 187\u001b[0m \u001b[0mcompression_overrides\u001b[0m\u001b[0;34m:\u001b[0m \u001b[0mDict\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0mstr\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mTerm\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m{\u001b[0m\u001b[0;34m}\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 188\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 189\u001b[0;31m \u001b[0mmodels\u001b[0m\u001b[0;34m:\u001b[0m \u001b[0mList\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0mModel\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m[\u001b[0m\u001b[0mDescriptiveStats\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mTTestStats\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 190\u001b[0m \u001b[0mp_value_threshold\u001b[0m\u001b[0;34m:\u001b[0m \u001b[0mfloat\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;36m0.05\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 191\u001b[0m \u001b[0mearly_stopping_alpha\u001b[0m\u001b[0;34m:\u001b[0m \u001b[0mOptional\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0mfloat\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;32mNone\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m\u001b[0m in \u001b[0;36m__init__\u001b[0;34m(self, key, data, engine, measure, link, hyperparams, estimations, label, visualizations, layout, compression_requirements, get_cell_significance, summary_estimators, treatment_effect_estimators, treatment_family_estimators, segment_by_covariates, summary_statistics, treatment_effect_statistics)\u001b[0m\n", + "\u001b[0;32m~/Repositories/github/spec-classes/spec_classes/methods/core.py\u001b[0m in \u001b[0;36minit\u001b[0;34m(spec_cls, self, **kwargs)\u001b[0m\n\u001b[1;32m 85\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mcopy_required\u001b[0m \u001b[0;32mand\u001b[0m \u001b[0;32mnot\u001b[0m \u001b[0misinstance\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mvalue\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m(\u001b[0m\u001b[0mint\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mstr\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mtuple\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 86\u001b[0m \u001b[0mvalue\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mcopy\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mdeepcopy\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mvalue\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 87\u001b[0;31m \u001b[0msetattr\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mattr\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mvalue\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 88\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 89\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0minstance_metadata\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0minit_overflow_attr\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m~/Repositories/github/spec-classes/spec_classes/methods/core.py\u001b[0m in \u001b[0;36m__setattr__\u001b[0;34m(self, attr, value, force)\u001b[0m\n\u001b[1;32m 162\u001b[0m \u001b[0mattr_spec\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m__spec_class__\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mattrs\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mget\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mattr\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 163\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mattr_spec\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 164\u001b[0;31m \u001b[0mWithAttrMethod\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mwith_attr\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mattr_spec\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mvalue\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0m_inplace\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;32mTrue\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 165\u001b[0m \u001b[0;32mreturn\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 166\u001b[0m \u001b[0mmutate_attr\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mattr\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mattr\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mvalue\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mvalue\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0minplace\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;32mTrue\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mtype_check\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;32mTrue\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mforce\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mforce\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m~/Repositories/github/spec-classes/spec_classes/methods/scalar.py\u001b[0m in \u001b[0;36mwith_attr\u001b[0;34m(attr_spec, self, _new_value, _inplace, _if, **attrs)\u001b[0m\n\u001b[1;32m 29\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 30\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mattr_spec\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mis_collection\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 31\u001b[0;31m _new_value = attr_spec.collection_mutator_type(\n\u001b[0m\u001b[1;32m 32\u001b[0m \u001b[0mattr_spec\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mtype\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mcollection\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0m_new_value\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mname\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mattr_spec\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mname\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 33\u001b[0m ).prepare(item_preparer=functools.partial(attr_spec.prepare_item, self)).collection\n", + "\u001b[0;32m~/Repositories/github/spec-classes/spec_classes/collections/sets.py\u001b[0m in \u001b[0;36mprepare\u001b[0;34m(self, item_preparer)\u001b[0m\n\u001b[1;32m 33\u001b[0m \u001b[0mitems\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mcollection\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 34\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mcollection\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_create_collection\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 35\u001b[0;31m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0madd_items\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mitems\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mitem_preparer\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 36\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 37\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0;32mnot\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mcollection\u001b[0m \u001b[0;32mor\u001b[0m \u001b[0;32mnot\u001b[0m \u001b[0mitem_preparer\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m~/Repositories/github/spec-classes/spec_classes/collections/sets.py\u001b[0m in \u001b[0;36madd_items\u001b[0;34m(self, items, preparer)\u001b[0m\n\u001b[1;32m 79\u001b[0m \u001b[0mpreparer\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mpreparer\u001b[0m \u001b[0;32mor\u001b[0m \u001b[0;34m(\u001b[0m\u001b[0;32mlambda\u001b[0m \u001b[0mitem\u001b[0m\u001b[0;34m:\u001b[0m \u001b[0mitem\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 80\u001b[0m \u001b[0;32mfor\u001b[0m \u001b[0mitem\u001b[0m \u001b[0;32min\u001b[0m \u001b[0mitems\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 81\u001b[0;31m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0madd_item\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mpreparer\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mitem\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 82\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 83\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m~/Repositories/github/spec-classes/spec_classes/collections/sets.py\u001b[0m in \u001b[0;36madd_item\u001b[0;34m(self, item, replace, attrs)\u001b[0m\n\u001b[1;32m 67\u001b[0m ):\n\u001b[1;32m 68\u001b[0m \u001b[0mitem\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mitem_spec_type\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mitem\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 69\u001b[0;31m return self._mutate_collection(\n\u001b[0m\u001b[1;32m 70\u001b[0m \u001b[0mvalue_or_index\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mitem\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 71\u001b[0m \u001b[0mextractor\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_extractor\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m~/Repositories/github/spec-classes/spec_classes/collections/base.py\u001b[0m in \u001b[0;36m_mutate_collection\u001b[0;34m(self, value_or_index, extractor, inserter, require_pre_existent, new_item, transform, attrs, attr_transforms, replace, inplace)\u001b[0m\n\u001b[1;32m 73\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mcollection\u001b[0m \u001b[0;32mis\u001b[0m \u001b[0mMISSING\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 74\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mcollection\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_create_collection\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 75\u001b[0;31m index, old_item = extractor(\n\u001b[0m\u001b[1;32m 76\u001b[0m \u001b[0mvalue_or_index\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mraise_if_missing\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mrequire_pre_existent\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 77\u001b[0m )\n", + "\u001b[0;32m~/Repositories/github/spec-classes/spec_classes/collections/sets.py\u001b[0m in \u001b[0;36m_extractor\u001b[0;34m(self, value_or_index, raise_if_missing)\u001b[0m\n\u001b[1;32m 15\u001b[0m return (\n\u001b[1;32m 16\u001b[0m \u001b[0mvalue_or_index\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 17\u001b[0;31m \u001b[0mvalue_or_index\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mvalue_or_index\u001b[0m \u001b[0;32min\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mcollection\u001b[0m \u001b[0;32melse\u001b[0m \u001b[0mMISSING\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 18\u001b[0m )\n\u001b[1;32m 19\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m~/Repositories/github/spec-classes/spec_classes/types/keyed.py\u001b[0m in \u001b[0;36m__contains__\u001b[0;34m(self, item_or_key)\u001b[0m\n\u001b[1;32m 274\u001b[0m \u001b[0;31m# Check whether item_or_key exists as a value\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 275\u001b[0m \u001b[0;32mtry\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 276\u001b[0;31m \u001b[0mkey\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mkey\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mitem_or_key\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 277\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mkey\u001b[0m \u001b[0;32min\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_dict\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 278\u001b[0m return (\n", + "\u001b[0;32m~/Repositories/github/spec-classes/spec_classes/types/keyed.py\u001b[0m in \u001b[0;36m__get_item_key\u001b[0;34m(self, item)\u001b[0m\n\u001b[1;32m 39\u001b[0m \u001b[0mkey\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mitem\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m__spec_class__\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mkey\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 40\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mkey\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 41\u001b[0;31m \u001b[0;32mreturn\u001b[0m \u001b[0mgetattr\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mitem\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mkey\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 42\u001b[0m \u001b[0;32mtry\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 43\u001b[0m \u001b[0mhash\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mitem\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m~/Repositories/github/spec-classes/spec_classes/methods/core.py\u001b[0m in \u001b[0;36m__getattr__\u001b[0;34m(self, attr)\u001b[0m\n\u001b[1;32m 138\u001b[0m \u001b[0;32mand\u001b[0m \u001b[0;32mnot\u001b[0m \u001b[0minspect\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0misdatadescriptor\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mgetattr\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m__class__\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mattr\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;32mNone\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 139\u001b[0m ):\n\u001b[0;32m--> 140\u001b[0;31m raise AttributeError(\n\u001b[0m\u001b[1;32m 141\u001b[0m \u001b[0;34mf\"`{self.__class__.__name__}.{attr}` has not yet been assigned a value.\"\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 142\u001b[0m )\n", + "\u001b[0;31mAttributeError\u001b[0m: `SummaryEstimator.key` has not yet been assigned a value." + ] + } + ], + "source": [ + "import metrics_repo" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from spec_classes import spec_class, MISSING\n", + "from cached_property import cached_property\n", + "from typing import Dict, List, Set\n", + "from spec_classes.types import KeyedList" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": {}, + "outputs": [], + "source": [ + "@spec_class\n", + "class MyClass:\n", + " prepared_str: str = \"a\"\n", + " prepared_items: List[str] = []\n", + "\n", + " def _prepare_prepared_str(self, prepared_str):\n", + " return \"c\"\n", + "\n", + " def _prepare_prepared_item(self, prepared_item):\n", + " return \"c\"" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": {}, + "outputs": [ + { + "output_type": "error", + "ename": "TypeError", + "evalue": "Attempt to set `MyClass.prepared_items` with an invalid type [got `'c'`; expecting `list[str]`].", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mTypeError\u001b[0m Traceback (most recent call last)", + "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mMyClass\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mprepared_str\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", + "\u001b[0;32m\u001b[0m in \u001b[0;36m__init__\u001b[0;34m(self, prepared_str, prepared_items)\u001b[0m\n", + "\u001b[0;32m~/Repositories/github/spec-classes/spec_classes/methods/core.py\u001b[0m in \u001b[0;36minit\u001b[0;34m(spec_cls, self, **kwargs)\u001b[0m\n\u001b[1;32m 83\u001b[0m \u001b[0mvalue\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mcopy\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mdeepcopy\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mvalue\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 84\u001b[0m \u001b[0msetattr\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mattr\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mvalue\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 85\u001b[0;31m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 86\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0minstance_metadata\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0minit_overflow_attr\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 87\u001b[0m getattr(self, f\"with_{instance_metadata.init_overflow_attr}\")( # TODO: avoid this\n", + "\u001b[0;32m~/Repositories/github/spec-classes/spec_classes/methods/core.py\u001b[0m in \u001b[0;36m__setattr__\u001b[0;34m(self, attr, value, force)\u001b[0m\n\u001b[1;32m 160\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mattr_spec\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 161\u001b[0m \u001b[0mWithAttrMethod\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mwith_attr\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mattr_spec\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mvalue\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0m_inplace\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;32mTrue\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 162\u001b[0;31m \u001b[0;32mreturn\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 163\u001b[0m \u001b[0mmutate_attr\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mattr\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mattr\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mvalue\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mvalue\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0minplace\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;32mTrue\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mtype_check\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;32mTrue\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mforce\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mforce\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 164\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m~/Repositories/github/spec-classes/spec_classes/methods/scalar.py\u001b[0m in \u001b[0;36mwith_attr\u001b[0;34m(attr_spec, self, _new_value, _inplace, _if, **attrs)\u001b[0m\n\u001b[1;32m 40\u001b[0m )\n\u001b[1;32m 41\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 42\u001b[0;31m return mutate_attr(\n\u001b[0m\u001b[1;32m 43\u001b[0m \u001b[0mobj\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 44\u001b[0m \u001b[0mattr\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mattr_spec\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mname\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m~/Repositories/github/spec-classes/spec_classes/utils/mutation.py\u001b[0m in \u001b[0;36mmutate_attr\u001b[0;34m(obj, attr, value, inplace, type_check, force)\u001b[0m\n\u001b[1;32m 49\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mtype_check\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 50\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0;32mnot\u001b[0m \u001b[0mcheck_type\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mvalue\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mattr_spec\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mtype\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 51\u001b[0;31m raise TypeError(\n\u001b[0m\u001b[1;32m 52\u001b[0m \u001b[0;34mf\"Attempt to set `{obj.__class__.__name__}.{attr}` with an invalid type [got `{repr(value)}`; expecting `{type_label(attr_spec.type)}`].\"\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 53\u001b[0m )\n", + "\u001b[0;31mTypeError\u001b[0m: Attempt to set `MyClass.prepared_items` with an invalid type [got `'c'`; expecting `list[str]`]." + ] + } + ], + "source": [ + "MyClass().prepared_str" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [], + "source": [ + "@spec_class\n", + "class Spec:\n", + " attr: str = \"Hello\"\n", + "\n", + "@spec_class\n", + "class SubSpec(Spec):\n", + " @property\n", + " def attr(self):\n", + " return \"World\"" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": {}, + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": [ + "__main__.SubSpec" + ] + }, + "metadata": {}, + "execution_count": 14 + } + ], + "source": [ + "SubSpec.__spec_class__.attrs['attr'].owner" + ] + }, + { + "source": [ + "@spec_class\n", + "class UnkeyedSpec:\n", + " nested_scalar: int = 1\n", + " nested_scalar2: str = \"original value\"\n", + "\n", + "\n", + "@spec_class(key=\"key\")\n", + "class KeyedSpec:\n", + " key: str = \"key\"\n", + " nested_scalar: int = 1\n", + " nested_scalar2: str = \"original value\"\n", + "\n", + "\n", + "@spec_class(key=\"key\", bootstrap=True)\n", + "class Spec:\n", + " key: str = \"key\"\n", + " scalar: int\n", + " list_values: List[int]\n", + " dict_values: Dict[str, int]\n", + " set_values: Set[str]\n", + " spec: UnkeyedSpec\n", + " spec_list_items: List[UnkeyedSpec]\n", + " spec_dict_items: Dict[str, UnkeyedSpec]\n", + " keyed_spec_list_items: List[KeyedSpec]\n", + " keyed_spec_dict_items: Dict[str, KeyedSpec]\n", + " recursive: \"Spec\"" + ], + "cell_type": "code", + "metadata": {}, + "execution_count": 2, + "outputs": [] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [], + "source": [ + "\n", + "from spec_classes import spec_property\n", + "\n", + "@spec_class\n", + "class MySpecClass:\n", + "\n", + " overridable_int: int\n", + " static_str: str\n", + " cached_time: float\n", + " bad_typecheck: int\n", + "\n", + " @spec_property\n", + " def overridable_int(self):\n", + " return 10\n", + "\n", + " @spec_property(overridable=False)\n", + " def static_str(self):\n", + " return \"string\"\n", + "\n", + " @spec_property(cache=True)\n", + " def cached_time(self):\n", + " import time\n", + "\n", + " return time.time()\n", + "\n", + " @spec_property\n", + " def bad_typecheck(self):\n", + " return \"string\"\n", + "\n", + " no_methods = spec_property(None, overridable=False)\n", + "\n", + " @spec_property\n", + " def method_overrides(self):\n", + " return\n", + "\n", + " @method_overrides.getter\n", + " def method_overrides(self):\n", + " raise RuntimeError(\"In `method_overrides` getter.\")\n", + "\n", + " @method_overrides.setter\n", + " def method_overrides(self, method_overrides):\n", + " raise RuntimeError(\"In `method_overrides` setter.\")\n", + "\n", + " @method_overrides.deleter\n", + " def method_overrides(self):\n", + " raise RuntimeError(\"In `method_overrides` deleter.\")\n", + "\n", + " @spec_property(cache=True, invalidated_by=[\"overridable_int\"])\n", + " def invalidated_obj(self):\n", + " return object()\n", + "\n", + " @spec_property(cache=True, invalidated_by=\"*\")\n", + " def always_invalidated_obj(self):\n", + " return object()" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [], + "source": [ + "spec_cls = MySpecClass()\n", + "spec_cls.overridable_int = 10\n", + "spec_cls.invalidated_obj\n", + "\n", + "obj = spec_cls.invalidated_obj\n", + "aobj = spec_cls.always_invalidated_obj" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": [ + "{'overridable_int': ,\n", + " 'static_str': ,\n", + " 'cached_time': ,\n", + " 'bad_typecheck': }" + ] + }, + "metadata": {}, + "execution_count": 8 + } + ], + "source": [ + "spec_cls.__spec_class__.attrs" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "output_type": "error", + "ename": "AssertionError", + "evalue": "", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mAssertionError\u001b[0m Traceback (most recent call last)", + "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[0;32mdel\u001b[0m \u001b[0mspec_cls\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0moverridable_int\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 2\u001b[0;31m \u001b[0;32massert\u001b[0m \u001b[0mspec_cls\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0minvalidated_obj\u001b[0m \u001b[0;32mis\u001b[0m \u001b[0;32mnot\u001b[0m \u001b[0mobj\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 3\u001b[0m \u001b[0;32massert\u001b[0m \u001b[0mspec_cls\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0malways_invalidated_obj\u001b[0m \u001b[0;32mis\u001b[0m \u001b[0;32mnot\u001b[0m \u001b[0maobj\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;31mAssertionError\u001b[0m: " + ] + } + ], + "source": [ + "\n", + "\n", + "del spec_cls.overridable_int\n", + "assert spec_cls.invalidated_obj is not obj\n", + "assert spec_cls.always_invalidated_obj is not aobj" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [ + { + "output_type": "stream", + "name": "stderr", + "text": [ + "WARNING 2021-08-30 17:16:27,337 reporting.py(18) `RCausalModelEngine.__repr__` overrides interface `EstimationEngine.__repr__` without using the `@override` decorator.\n" + ] + }, + { + "output_type": "error", + "ename": "AttributeError", + "evalue": "Cannot set `DescriptiveStats.compression_requirements` to `CompressionRequirements(\n statistics={\n 'count',\n 'sos',\n 'sum'\n },\n grains=set(),\n include_quantile_extents=False,\n long_form=False\n)`. Is this a property without a setter?", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mAttributeError\u001b[0m Traceback (most recent call last)", + "\u001b[0;32m~/Repositories/github/spec-classes/spec_classes/utils/mutation.py\u001b[0m in \u001b[0;36mmutate_attr\u001b[0;34m(obj, attr, value, inplace, type_check, force)\u001b[0m\n\u001b[1;32m 60\u001b[0m \u001b[0;32mtry\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 61\u001b[0;31m \u001b[0mgetattr\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mobj\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m__setattr__\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m\"__raw__\"\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0msetattr\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mobj\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mattr\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mvalue\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 62\u001b[0m \u001b[0;32mexcept\u001b[0m \u001b[0mAttributeError\u001b[0m \u001b[0;32mas\u001b[0m \u001b[0me\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;31mAttributeError\u001b[0m: can't set attribute", + "\nThe above exception was the direct cause of the following exception:\n", + "\u001b[0;31mAttributeError\u001b[0m Traceback (most recent call last)", + "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0;32mimport\u001b[0m \u001b[0mmetrics_repo\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", + "\u001b[0;32m~/Repositories/netflix/metrics-repo/metrics_repo/__init__.py\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[1;32m 4\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0msnapy\u001b[0m \u001b[0;31m# noqa: F401; Import snapy before kragle to use snapy magics\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 5\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 6\u001b[0;31m \u001b[0;32mfrom\u001b[0m \u001b[0mmetrics_repo\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mlib\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mbuilder\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0mBuilder\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 7\u001b[0m \u001b[0;32mfrom\u001b[0m \u001b[0mmetrics_repo\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mlib\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mhelpers\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0mbuild_library\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 8\u001b[0m \u001b[0;32mfrom\u001b[0m \u001b[0mmetrics_repo\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mlib\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mpaths\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0mBUILDERS_DIR\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mMETRICS_DIR\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mREPORTS_DIR\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mSOURCES_DIR\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mQUERIES_DIR\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mFILTERS_DIR\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mDIMENSIONS_DIR\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mREPORT_CONFIGURATIONS_DIR\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mCONFIG_SOURCES_DIR\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m~/Repositories/netflix/metrics-repo/metrics_repo/lib/__init__.py\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[0;34m\"\"\"Utility functions.\"\"\"\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 2\u001b[0;31m \u001b[0;32mfrom\u001b[0m \u001b[0;34m.\u001b[0m\u001b[0madd_on\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0mAddOn\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 3\u001b[0m \u001b[0;32mfrom\u001b[0m \u001b[0;34m.\u001b[0m\u001b[0mafter_steps\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0mAfterExecutionStep\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 4\u001b[0m \u001b[0;32mfrom\u001b[0m \u001b[0;34m.\u001b[0m\u001b[0manalysis_context\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0mAnalysisContext\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 5\u001b[0m \u001b[0;32mfrom\u001b[0m \u001b[0;34m.\u001b[0m\u001b[0mconfig\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0mCONFIG\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m~/Repositories/netflix/metrics-repo/metrics_repo/lib/add_on.py\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[1;32m 5\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 6\u001b[0m \u001b[0;32mfrom\u001b[0m \u001b[0mmetrics_repo\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mlib\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mdimension\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0mDimension\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 7\u001b[0;31m \u001b[0;32mfrom\u001b[0m \u001b[0mmetrics_repo\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mlib\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mmetric\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0mMetric\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 8\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 9\u001b[0m \u001b[0;32mfrom\u001b[0m \u001b[0;34m.\u001b[0m\u001b[0merrors\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0mValidationError\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m~/Repositories/netflix/metrics-repo/metrics_repo/lib/metric.py\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[1;32m 38\u001b[0m \u001b[0minit_overflow_attr\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;34m'options'\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 39\u001b[0m )\n\u001b[0;32m---> 40\u001b[0;31m \u001b[0;32mclass\u001b[0m \u001b[0mMetric\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mmetaclass\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mSubclassRegisteringMeta\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 41\u001b[0m \"\"\"\n\u001b[1;32m 42\u001b[0m \u001b[0mDefines\u001b[0m \u001b[0ma\u001b[0m \u001b[0mmetric\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m~/Repositories/netflix/metrics-repo/metrics_repo/lib/metric.py\u001b[0m in \u001b[0;36mMetric\u001b[0;34m()\u001b[0m\n\u001b[1;32m 187\u001b[0m \u001b[0mcompression_overrides\u001b[0m\u001b[0;34m:\u001b[0m \u001b[0mDict\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0mstr\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mTerm\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m{\u001b[0m\u001b[0;34m}\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 188\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 189\u001b[0;31m \u001b[0mmodels\u001b[0m\u001b[0;34m:\u001b[0m \u001b[0mList\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0mModel\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m[\u001b[0m\u001b[0mDescriptiveStats\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mTTestStats\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 190\u001b[0m \u001b[0mp_value_threshold\u001b[0m\u001b[0;34m:\u001b[0m \u001b[0mfloat\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;36m0.05\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 191\u001b[0m \u001b[0mearly_stopping_alpha\u001b[0m\u001b[0;34m:\u001b[0m \u001b[0mOptional\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0mfloat\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;32mNone\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m\u001b[0m in \u001b[0;36m__init__\u001b[0;34m(self, key, data, engine, measure, link, hyperparams, estimations, label, visualizations, layout, compression_requirements, get_cell_significance, summary_estimators, treatment_effect_estimators, treatment_family_estimators, segment_by_covariates, summary_statistics, treatment_effect_statistics)\u001b[0m\n", + "\u001b[0;32m~/Repositories/github/spec-classes/spec_classes/methods/core.py\u001b[0m in \u001b[0;36minit\u001b[0;34m(spec_cls, self, **kwargs)\u001b[0m\n\u001b[1;32m 30\u001b[0m \u001b[0mparent_metadata\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mgetattr\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mparent\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m\"__spec_class__\"\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;32mNone\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 31\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mparent_metadata\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 32\u001b[0;31m parent.__init__(self, **{\n\u001b[0m\u001b[1;32m 33\u001b[0m \u001b[0mattr\u001b[0m\u001b[0;34m:\u001b[0m \u001b[0mkwargs\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mpop\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mattr\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 34\u001b[0m \u001b[0;32mfor\u001b[0m \u001b[0mattr\u001b[0m \u001b[0;32min\u001b[0m \u001b[0mlist\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mkwargs\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m\u001b[0m in \u001b[0;36m__init__\u001b[0;34m(self, key, data, engine, measure, link, hyperparams, estimations, label, visualizations, layout, compression_requirements, get_cell_significance, summary_estimators, treatment_effect_estimators, treatment_family_estimators, segment_by_covariates, summary_statistics, treatment_effect_statistics)\u001b[0m\n", + "\u001b[0;32m~/Repositories/github/spec-classes/spec_classes/methods/core.py\u001b[0m in \u001b[0;36minit\u001b[0;34m(spec_cls, self, **kwargs)\u001b[0m\n\u001b[1;32m 77\u001b[0m \u001b[0mvalue\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mcopy\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mdeepcopy\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mvalue\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 78\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mvalue\u001b[0m \u001b[0;32mis\u001b[0m \u001b[0;32mnot\u001b[0m \u001b[0mMISSING\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 79\u001b[0;31m \u001b[0msetattr\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mattr\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mvalue\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 80\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 81\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mmetadata\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0minit_overflow_attr\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m~/Repositories/github/spec-classes/spec_classes/methods/core.py\u001b[0m in \u001b[0;36m__setattr__\u001b[0;34m(self, attr, value, force)\u001b[0m\n\u001b[1;32m 154\u001b[0m \u001b[0mattr_spec\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m__spec_class__\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mattrs\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mget\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mattr\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 155\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mattr_spec\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 156\u001b[0;31m \u001b[0mWithAttrMethod\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mwith_attr\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mattr_spec\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mvalue\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0m_inplace\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;32mTrue\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 157\u001b[0m \u001b[0;32mreturn\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 158\u001b[0m \u001b[0mmutate_attr\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mattr\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mattr\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mvalue\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mvalue\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0minplace\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;32mTrue\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mtype_check\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;32mTrue\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mforce\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mforce\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m~/Repositories/github/spec-classes/spec_classes/methods/scalar.py\u001b[0m in \u001b[0;36mwith_attr\u001b[0;34m(attr_spec, self, _new_value, _inplace, _if, **attrs)\u001b[0m\n\u001b[1;32m 40\u001b[0m )\n\u001b[1;32m 41\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 42\u001b[0;31m return mutate_attr(\n\u001b[0m\u001b[1;32m 43\u001b[0m \u001b[0mobj\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 44\u001b[0m \u001b[0mattr\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mattr_spec\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mname\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m~/Repositories/github/spec-classes/spec_classes/utils/mutation.py\u001b[0m in \u001b[0;36mmutate_attr\u001b[0;34m(obj, attr, value, inplace, type_check, force)\u001b[0m\n\u001b[1;32m 62\u001b[0m \u001b[0;32mexcept\u001b[0m \u001b[0mAttributeError\u001b[0m \u001b[0;32mas\u001b[0m \u001b[0me\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 63\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0me\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0margs\u001b[0m \u001b[0;34m==\u001b[0m \u001b[0;34m(\u001b[0m\u001b[0;34m\"can't set attribute\"\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m \u001b[0;31m# Let's make this error less obtuse.\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 64\u001b[0;31m raise AttributeError(\n\u001b[0m\u001b[1;32m 65\u001b[0m \u001b[0;34mf\"Cannot set `{obj.__class__.__name__}.{attr}` to `{value}`. Is this a property without a setter?\"\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 66\u001b[0m ) from e\n", + "\u001b[0;31mAttributeError\u001b[0m: Cannot set `DescriptiveStats.compression_requirements` to `CompressionRequirements(\n statistics={\n 'count',\n 'sos',\n 'sum'\n },\n grains=set(),\n include_quantile_extents=False,\n long_form=False\n)`. Is this a property without a setter?" + ] + } + ], + "source": [ + "import metrics_repo" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": [ + "UnkeyedSpec(nested_scalar=1, nested_scalar2='original value')" + ] + }, + "metadata": {}, + "execution_count": 3 + } + ], + "source": [ + "UnkeyedSpec()" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [], + "source": [ + "from spec_classes.utils.type_checking import get_spec_class_for_type" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [], + "source": [ + "get_spec_class_for_type(UnkeyedSpec)" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "transform_spec spec None\n" + ] + }, + { + "output_type": "error", + "ename": "TypeError", + "evalue": "transform_spec() missing 1 required positional argument: '_transform'", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mTypeError\u001b[0m Traceback (most recent call last)", + "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mSpec\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mwith_spec\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mtransform_spec\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mnested_scalar\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;32mlambda\u001b[0m \u001b[0mx\u001b[0m\u001b[0;34m:\u001b[0m \u001b[0mx\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mwith_nested_scalar\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m3\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", + "\u001b[0;31mTypeError\u001b[0m: transform_spec() missing 1 required positional argument: '_transform'" + ] + } + ], + "source": [ + "Spec().with_spec().transform_spec(nested_scalar=lambda x: x.with_nested_scalar(3))" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": { + "tags": [ + "outputPrepend" + ] + }, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "SSING, 'new_value': MISSING, 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': 1, 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': 'original value', 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': MISSING, 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': 'key', 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': MISSING, 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': MISSING, 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': 1, 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': 'original value', 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': MISSING, 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': 'key', 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': MISSING, 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': MISSING, 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': 1, 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': 'original value', 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': MISSING, 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': 'key', 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': MISSING, 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': MISSING, 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': 1, 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': 'original value', 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': MISSING, 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': 'key', 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': MISSING, 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': MISSING, 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': 1, 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': 'original value', 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': MISSING, 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': 'key', 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': MISSING, 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': MISSING, 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': 1, 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': 'original value', 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': MISSING, 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': 'key', 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': MISSING, 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': MISSING, 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': 1, 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': 'original value', 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': MISSING, 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': 'key', 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': MISSING, 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': MISSING, 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': 1, 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': 'original value', 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': MISSING, 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': 'key', 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': MISSING, 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': MISSING, 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': 1, 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': 'original value', 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': MISSING, 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': 'key', 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': MISSING, 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': MISSING, 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': 1, 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': 'original value', 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': MISSING, 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': 'key', 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': MISSING, 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': MISSING, 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': 1, 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': 'original value', 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': MISSING, 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': 'key', 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': MISSING, 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': MISSING, 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': 1, 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': 'original value', 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': MISSING, 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': 'key', 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': MISSING, 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': MISSING, 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': 1, 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': 'original value', 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': MISSING, 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': 'key', 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': MISSING, 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': MISSING, 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': 1, 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': 'original value', 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': MISSING, 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': 'key', 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': MISSING, 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': MISSING, 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': 1, 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': 'original value', 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': MISSING, 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': 'key', 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': MISSING, 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': MISSING, 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': 1, 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': 'original value', 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': MISSING, 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': 'key', 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': MISSING, 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': MISSING, 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': 1, 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': 'original value', 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': MISSING, 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': 'key', 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': MISSING, 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': MISSING, 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': 1, 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': 'original value', 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': MISSING, 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': 'key', 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': MISSING, 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': MISSING, 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': 1, 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': 'original value', 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': MISSING, 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': 'key', 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': MISSING, 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': MISSING, 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': 1, 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': 'original value', 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': MISSING, 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': 'key', 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': MISSING, 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': MISSING, 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': 1, 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': 'original value', 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': MISSING, 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': 'key', 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': MISSING, 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': MISSING, 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': 1, 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': 'original value', 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': MISSING, 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': 'key', 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': MISSING, 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': MISSING, 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': 1, 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': 'original value', 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': MISSING, 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': 'key', 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': MISSING, 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': MISSING, 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': 1, 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': 'original value', 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': MISSING, 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': 'key', 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': MISSING, 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': MISSING, 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': 1, 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': 'original value', 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': MISSING, 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': 'key', 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': MISSING, 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': MISSING, 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': 1, 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': 'original value', 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': MISSING, 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': 'key', 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': MISSING, 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': MISSING, 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': 1, 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': 'original value', 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': MISSING, 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': 'key', 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': MISSING, 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': MISSING, 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': 1, 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': 'original value', 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': MISSING, 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': 'key', 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': MISSING, 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': MISSING, 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': 1, 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': 'original value', 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': MISSING, 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': 'key', 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': MISSING, 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': MISSING, 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': 1, 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': 'original value', 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': MISSING, 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': 'key', 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': MISSING, 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': MISSING, 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': 1, 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': 'original value', 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': MISSING, 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': 'key', 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': MISSING, 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': MISSING, 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': 1, 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': 'original value', 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': MISSING, 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': 'key', 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': MISSING, 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': MISSING, 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': 1, 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': 'original value', 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': MISSING, 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': 'key', 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': MISSING, 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': MISSING, 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': 1, 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': 'original value', 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': MISSING, 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': 'key', 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': MISSING, 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': MISSING, 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': 1, 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': 'original value', 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': MISSING, 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': 'key', 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': MISSING, 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': MISSING, 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': 1, 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': 'original value', 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': MISSING, 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': 'key', 'constructor': , 'attrs': {}}\n", + "{'old_value': MISSING, 'new_value': MISSING, 'constructor': , 'attrs': {}}\n" + ] + }, + { + "output_type": "error", + "ename": "RecursionError", + "evalue": "maximum recursion depth exceeded in comparison", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mRecursionError\u001b[0m Traceback (most recent call last)", + "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mSpec\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mkey\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;34m'a'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", + "\u001b[0;32m\u001b[0m in \u001b[0;36m__init__\u001b[0;34m(self, key, scalar, list_values, dict_values, set_values, spec, spec_list_items, spec_dict_items, keyed_spec_list_items, keyed_spec_dict_items, recursive)\u001b[0m\n", + "\u001b[0;32m~/Repositories/github/spec-classes/spec_classes/methods/core.py\u001b[0m in \u001b[0;36minit\u001b[0;34m(self, **kwargs)\u001b[0m\n\u001b[1;32m 73\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mcopy_required\u001b[0m \u001b[0;32mand\u001b[0m \u001b[0;32mnot\u001b[0m \u001b[0misinstance\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mvalue\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m(\u001b[0m\u001b[0mint\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mstr\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mtuple\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 74\u001b[0m \u001b[0mvalue\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mcopy\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mdeepcopy\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mvalue\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 75\u001b[0;31m \u001b[0msetattr\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mattr\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mvalue\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 76\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 77\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mmetadata\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0minit_overflow_attr\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m~/Repositories/github/spec-classes/spec_classes/methods/core.py\u001b[0m in \u001b[0;36m__setattr__\u001b[0;34m(self, attr, value, force)\u001b[0m\n\u001b[1;32m 150\u001b[0m \u001b[0mattr_spec\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m__spec_class__\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mattrs\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mget\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mattr\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 151\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mattr_spec\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 152\u001b[0;31m \u001b[0mWithAttrMethod\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mwith_attr\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mattr_spec\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mvalue\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0m_inplace\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;32mTrue\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 153\u001b[0m \u001b[0;32mreturn\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 154\u001b[0m \u001b[0mmutate_attr\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mattr\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mattr\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mvalue\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mvalue\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0minplace\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;32mTrue\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mtype_check\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;32mTrue\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mforce\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mforce\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m~/Repositories/github/spec-classes/spec_classes/methods/scalar.py\u001b[0m in \u001b[0;36mwith_attr\u001b[0;34m(attr_spec, self, _new_value, _inplace, _if, **attrs)\u001b[0m\n\u001b[1;32m 39\u001b[0m \u001b[0mattrs\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mattrs\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 40\u001b[0m )\n\u001b[0;32m---> 41\u001b[0;31m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 42\u001b[0m return mutate_attr(\n\u001b[1;32m 43\u001b[0m \u001b[0mobj\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m~/Repositories/github/spec-classes/spec_classes/utils/mutation.py\u001b[0m in \u001b[0;36mmutate_value\u001b[0;34m(old_value, new_value, replace, constructor, attrs, transform, attr_transforms)\u001b[0m\n\u001b[1;32m 154\u001b[0m \u001b[0mconstructor\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mconstructor\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m__origin__\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 155\u001b[0m \u001b[0mconstructor_args\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0m_get_function_args\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mconstructor\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mattrs\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 156\u001b[0;31m value = constructor(\n\u001b[0m\u001b[1;32m 157\u001b[0m **{\n\u001b[1;32m 158\u001b[0m \u001b[0mattr\u001b[0m\u001b[0;34m:\u001b[0m \u001b[0mvalue\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "... last 5 frames repeated, from the frame below ...\n", + "\u001b[0;32m\u001b[0m in \u001b[0;36m__init__\u001b[0;34m(self, key, scalar, list_values, dict_values, set_values, spec, spec_list_items, spec_dict_items, keyed_spec_list_items, keyed_spec_dict_items, recursive)\u001b[0m\n", + "\u001b[0;31mRecursionError\u001b[0m: maximum recursion depth exceeded in comparison" + ] + } + ], + "source": [ + "Spec(key='a')" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [], + "source": [ + "@spec_class(bootstrap=True)\n", + "class MySpec:\n", + " #data: Dict[str, int] = {}\n", + " items: List[int] = []\n", + "\n", + " def _prepare_item(self, s, **attrs):\n", + " return int(s)\n", + "\n", + " # def _prepare_datum(self, k, v):\n", + " # print(k, v)\n", + " # return k, v" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": [ + "" + ] + }, + "metadata": {}, + "execution_count": 7 + } + ], + "source": [ + "MySpec.__spec_class__.attrs['items'].prepare_item" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": [ + "MySpec(items=[1, 2, 3])" + ] + }, + "metadata": {}, + "execution_count": 8 + } + ], + "source": [ + "MySpec(items=['1', '2', '3'])" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + ">\n" + ] + }, + { + "output_type": "error", + "ename": "AttributeError", + "evalue": "'MySpec' object has no attribute 'with_datum'", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mAttributeError\u001b[0m Traceback (most recent call last)", + "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mMySpec\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mwith_datum\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'a'\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m1\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mtransform_datum\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"a\"\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;32mlambda\u001b[0m \u001b[0mx\u001b[0m\u001b[0;34m:\u001b[0m \u001b[0;36m2\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mwithout_datum\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'a'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", + "\u001b[0;32m~/Repositories/github/spec-classes/spec_classes/methods/core.py\u001b[0m in \u001b[0;36m__getattr__\u001b[0;34m(self, attr)\u001b[0m\n\u001b[1;32m 129\u001b[0m \u001b[0;34mf\"`{self.__class__.__name__}.{attr}` has not yet been assigned a value.\"\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 130\u001b[0m )\n\u001b[0;32m--> 131\u001b[0;31m \u001b[0;32mreturn\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m__getattr__\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m__raw__\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mattr\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 132\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 133\u001b[0m \u001b[0;31m# Add reference to original __getattr__ method.\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;31mAttributeError\u001b[0m: 'MySpec' object has no attribute 'with_datum'" + ] + } + ], + "source": [ + "MySpec().with_datum('a', 1).transform_datum(\"a\", lambda x: 2).without_datum('a')" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "Help on method transform_datum:\n\ntransform_datum(_key: str, _transform: Callable, *, _inplace: bool = False, _if: bool = True) method of __main__.MySpec instance\n Return a `MySpec` instance identical to this one except with an item transformed in `data`.\n \n Args:\n _key: The key for the item to be inserted or updated.\n _transform: A function that takes the old item as input, and returns\n the new item.\n _inplace: Whether to perform change without first copying.\n _if: This action is only taken when `_if` is `True`. If it is `False`,\n this is a no-op.\n Returns:\n A reference to the mutated `MySpec` instance.\n\n" + ] + } + ], + "source": [ + "help(MySpec().transform_datum)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ] +} \ No newline at end of file diff --git a/spec_classes/__init__.py b/spec_classes/__init__.py index fad8084..6244c8c 100644 --- a/spec_classes/__init__.py +++ b/spec_classes/__init__.py @@ -1,8 +1,12 @@ -from ._version import __version__, __version_tuple__ from .errors import FrozenInstanceError from .spec_class import spec_class from .types import Alias, DeprecatedAlias, Attr, AttrProxy, MISSING, spec_property +try: + from ._version import __version__, __version_tuple__ +except ImportError: + __version__ = __version_tuple__ = None + __author__ = "Matthew Wardrop" __author_email__ = "mpwardrop@gmail.com" diff --git a/spec_classes/methods/core.py b/spec_classes/methods/core.py index b45183f..4a6ce64 100644 --- a/spec_classes/methods/core.py +++ b/spec_classes/methods/core.py @@ -8,7 +8,7 @@ from spec_classes.errors import FrozenInstanceError from spec_classes.methods.scalar import WithAttrMethod -from spec_classes.types import Attr, MISSING +from spec_classes.types import Attr, MISSING, UNSPECIFIED from spec_classes.utils.method_builder import MethodBuilder from spec_classes.utils.mutation import ( invalidate_attrs, @@ -16,9 +16,11 @@ protect_via_deepcopy, ) -from .base import MethodDescriptor +from spec_classes.methods.base import MethodDescriptor +MISSING_FINAL = object() + class InitMethod(MethodDescriptor): """ The default implementation of `__init__` for spec-classes. @@ -39,92 +41,96 @@ class InitMethod(MethodDescriptor): method_name = "__init__" + @staticmethod - def init(spec_cls, self, **kwargs): - instance_metadata = self.__spec_class__ + def build_init_method_body(spec_cls): + metadata = spec_cls.__spec_class__ + body = [ + "metadata = self.__spec_class__", + ] + + for attr, attr_spec in metadata.attrs.items(): + body.append(f""" + if {attr} is UNSPECIFIED: + {attr} = metadata.attrs['{attr}'].get_value(self.__class__, {attr}, copy={not attr_spec.do_not_copy}) + """) # Unlock the class for mutation during initialization. - is_frozen = instance_metadata.frozen - if instance_metadata.owner is spec_cls and instance_metadata.frozen: - instance_metadata.frozen = False + is_frozen = metadata.frozen + if metadata.owner is spec_cls and metadata.frozen: + body.append("metadata.frozen = False") # Initialise any non-local spec attributes via parent constructors - if instance_metadata.owner is spec_cls: - for parent in reversed(spec_cls.mro()[1:]): + if metadata.owner is spec_cls: + for parent_index, parent in enumerate(reversed(spec_cls.mro()[1:])): parent_metadata = getattr(parent, "__spec_class__", None) if parent_metadata: - parent_kwargs = {} + parent_args = [] for attr in parent_metadata.attrs: - instance_attr_spec = instance_metadata.attrs[attr] - if instance_attr_spec.owner is not parent: + attr_spec = metadata.attrs[attr] + if attr_spec.owner is not parent: continue - if attr in kwargs: - parent_kwargs[attr] = kwargs.pop(attr) - else: - # Parent constructor may may be overridden, and not pick up - # subclass defaults. We pre-emptively solve this here. - # If the constructor was not overridden, then no harm is - # done (we just looked it up earlier than we had to). - # We don't pass missing values in case overridden constructor - # has defaults in the signature. - instance_default = instance_attr_spec.lookup_default_value( - self.__class__ - ) - if instance_default is not MISSING: - parent_kwargs[attr] = instance_default - if parent_metadata.key and parent_metadata.key not in parent_kwargs: - parent_kwargs[parent_metadata.key] = MISSING - parent.__init__( # pylint: disable=unnecessary-dunder-call - self, **parent_kwargs - ) - - # For each attribute owned by this spec_cls in `instance_metadata`, + parent_args.append(f""""{attr}": {attr},""") + if parent_metadata.key and parent_metadata.key not in parent_args: + parent_args.append(f""""{parent_metadata.key}": MISSING if {parent_metadata.key} is UNSPECIFIED else MISSING""") + parent_args = "".join(parent_args) + body.append(f""" + self.__class__.mro()[-{parent_index+1}].__init__(self, **{{k: v for k, v in {{{parent_args}}}.items() if v is not UNSPECIFIED }}) + """) + + # For each attribute owned by this spec_cls in `metadata`, # initalize the attribute. - for attr, attr_spec in instance_metadata.attrs.items(): + for attr, attr_spec in metadata.attrs.items(): + if ( not attr_spec.init or attr_spec.owner is not spec_cls - or attr == instance_metadata.init_overflow_attr + or attr == metadata.init_overflow_attr ): continue - value = kwargs.get(attr, MISSING) - if value is not MISSING: - # If owner is not spec-class, we have already looked up and - # handled copying. - copy_required = ( - instance_metadata.owner is spec_cls and not attr_spec.do_not_copy - ) - else: - value = attr_spec.lookup_default_value(self.__class__) - copy_required = False - - if value is not MISSING: - if copy_required: - value = protect_via_deepcopy(value) - setattr(self, attr, value) + copy_required = metadata.owner is spec_cls and not attr_spec.do_not_copy + + body.append(f""" + # Assign `{attr}` + # {attr} = metadata.attrs['{attr}'].get_value(self.__class__, {attr}, copy={copy_required}) + if {attr} not in (MISSING, UNSPECIFIED): + self.{attr} = {attr} + """) + # if copy_required: + # body.append(f""" + # if {attr} is not MISSING: + # {attr} = protect_via_deepcopy({attr}) + # """) + + # body.append(f""" + # if {attr} is MISSING: + # {attr} = metadata.attrs['{attr}'].lookup_default_value(self.__class__) + # if {attr} is not MISSING: + # self.{attr} = {attr} + # """) # Finalize initialisation by storing overflow attrs and restoring frozen # status. - if instance_metadata.owner is spec_cls: - if instance_metadata.init_overflow_attr: - getattr( - self, f"with_{instance_metadata.init_overflow_attr}" - )( # TODO: avoid this - { - key: value - for key, value in kwargs.items() - if key not in instance_metadata.annotations - or key == instance_metadata.init_overflow_attr - }, - _inplace=True, - ) + if metadata.owner is spec_cls: + if metadata.init_overflow_attr: + body.append(f""" + self.with_{metadata.init_overflow_attr}({{ key: value for key, value in {metadata.init_overflow_attr}.items() + if key not in metadata.annotations + or key == metadata.init_overflow_attr }}, _inplace=True) + """) - if instance_metadata.post_init: - instance_metadata.post_init(self) + if metadata.post_init: + body.append("metadata.post_init(self)") if is_frozen: - instance_metadata.frozen = True + body.append("metadata.frozen = True") + + return "\n".join( + textwrap.dedent(s) + for s in body + ) + def build_method(self) -> Callable: spec_class_key = self.spec_cls.__spec_class__.key @@ -136,11 +142,11 @@ def build_method(self) -> Callable: # If the key has a default, don't require it to be set during # construction. key_default = ( - MISSING if spec_class_key_spec.has_default else inspect.Parameter.empty + UNSPECIFIED if spec_class_key_spec.has_default else inspect.Parameter.empty ) return ( - MethodBuilder("__init__", functools.partial(self.init, self.spec_cls)) + MethodBuilder("__init__", self.build_init_method_body(self.spec_cls), {"UNSPECIFIED": UNSPECIFIED, "MISSING": MISSING, "protect_via_deepcopy": protect_via_deepcopy}) .with_preamble(f"Initialise this `{self.spec_cls.__name__}` instance.") .with_arg( spec_class_key, diff --git a/spec_classes/types/__init__.py b/spec_classes/types/__init__.py index ae6d0ff..f201ef1 100644 --- a/spec_classes/types/__init__.py +++ b/spec_classes/types/__init__.py @@ -2,7 +2,7 @@ from .attr import Attr from .attr_proxy import AttrProxy from .keyed import KeyedList, KeyedSet -from .missing import MISSING +from .missing import MISSING, UNSPECIFIED from .spec_property import spec_property from .validated import ValidatedType, bounded, validated @@ -14,6 +14,7 @@ "KeyedList", "KeyedSet", "MISSING", + "UNSPECIFIED", "ValidatedType", "bounded", "spec_property", diff --git a/spec_classes/types/attr.py b/spec_classes/types/attr.py index fd99f56..953945e 100644 --- a/spec_classes/types/attr.py +++ b/spec_classes/types/attr.py @@ -17,7 +17,7 @@ type_match, ) -from .missing import MISSING +from .missing import MISSING, UNSPECIFIED if TYPE_CHECKING: # pragma: no cover from spec_classes.collections.base import CollectionAttrMutator @@ -272,6 +272,21 @@ def item_constructor(self) -> Optional[Type]: return self.item_spec_type_polymorphic or self.item_type # Helpers + + def get_value(self, spec_cls: Type, value: Any = UNSPECIFIED, copy: bool = True) -> Any: + from spec_classes.utils.mutation import protect_via_deepcopy + + if value is MISSING: + return value + if value is UNSPECIFIED: + value = self.lookup_default_value(spec_cls) + if value is MISSING: + return UNSPECIFIED + return value + return protect_via_deepcopy(value) if copy else value + + + def lookup_default_value(self, spec_cls: Type) -> Any: """ Look up the correct default value for this attribute for `instance`. diff --git a/spec_classes/types/missing.py b/spec_classes/types/missing.py index 0f0551f..22d2711 100644 --- a/spec_classes/types/missing.py +++ b/spec_classes/types/missing.py @@ -1,17 +1,20 @@ # Sentinel for unset inputs to spec_class methods class _MissingType: - __instance__ = None + __instances__ = {} - def __new__(cls): - if cls.__instance__ is None: - cls.__instance__ = super(_MissingType, cls).__new__(cls) - return cls.__instance__ + def __new__(cls, name="MISSING"): + if name not in cls.__instances__: + cls.__instances__[name] = super(_MissingType, cls).__new__(cls) + return cls.__instances__[name] + + def __init__(self, name="MISSING"): + self.name = name def __bool__(self): return False def __repr__(self): - return "MISSING" + return self.name def __copy__(self): return self @@ -21,3 +24,4 @@ def __deepcopy__(self, memo): MISSING = _MissingType() +UNSPECIFIED = _MissingType("UNSPECIFIED") diff --git a/spec_classes/utils/method_builder.py b/spec_classes/utils/method_builder.py index 467fd4f..220ef6a 100644 --- a/spec_classes/utils/method_builder.py +++ b/spec_classes/utils/method_builder.py @@ -1,11 +1,12 @@ from __future__ import annotations import inspect +import linecache import textwrap from inspect import Parameter, Signature, cleandoc from typing import Any, Callable, Dict, List, Optional, Tuple, Type, Union -from spec_classes.types import MISSING +from spec_classes.types import MISSING, UNSPECIFIED from spec_classes.utils.type_checking import type_label @@ -60,9 +61,10 @@ class MethodBuilder: """ - def __init__(self, name: str, implementation: Callable): + def __init__(self, name: str, implementation: Union[str, Callable], exec_context: Optional[Dict[str, Any]] = None): self.name = name self.implementation = implementation + self.exec_context = exec_context # Documentation attributes self.doc_preamble: str = "" @@ -231,7 +233,7 @@ def with_args( name, desc=desc, annotation=(annotations or {}).get(name, Parameter.empty), - default=(defaults or {}).get(name, MISSING), + default=(defaults or {}).get(name, UNSPECIFIED), kind=Parameter.KEYWORD_ONLY, virtual=virtual, ) @@ -285,7 +287,7 @@ def with_spec_attrs_for( else attr_spec.desc ) annotations[attr] = attr_spec.type - defaults[attr] = MISSING if attr_spec.is_masked else attr_spec.default + defaults[attr] = UNSPECIFIED if attr_spec.is_masked else attr_spec.lookup_default_value(spec_cls) self.with_args( args=args, @@ -388,48 +390,90 @@ def build(self) -> Callable: namespace = {} signature = self._signature - impl_signature = Signature.from_callable(self.implementation) signature_advertised = ( self._signature_virtual if self.method_args_virtual else signature ) + str_signature, defaults = self._method_signature_to_definition_str( + signature_advertised + if isinstance(self.implementation, str) + else signature + ) - if not self._check_signature_compatible_with_implementation( - signature, impl_signature - ): - raise RuntimeError( - f"Proposed method signature `{self.name}{signature}` is not compatible with implementation signature `implementation{impl_signature}`." - ) - - VALID_KWARGS = {p.name for p in self.method_args_virtual} - - def validate_attrs(attrs): - for attr in attrs: - if attr not in VALID_KWARGS: - extra_attrs = set(attrs) - extra_attrs.difference_update(VALID_KWARGS) - raise TypeError( - f"{self.name}() got unexpected keyword arguments: {repr(extra_attrs)}." - ) - - str_signature, defaults = self._method_signature_to_definition_str(signature) + if not isinstance(self.implementation, str): + impl_signature = Signature.from_callable(self.implementation) + if not self._check_signature_compatible_with_implementation( + signature, impl_signature + ): + raise RuntimeError( + f"Proposed method signature `{self.name}{signature}` is not compatible with implementation signature `implementation{impl_signature}`." + ) - exec( - textwrap.dedent( + VALID_KWARGS = {p.name for p in self.method_args_virtual} + + def validate_attrs(attrs): + for attr in attrs: + if attr not in VALID_KWARGS: + extra_attrs = set(attrs) + extra_attrs.difference_update(VALID_KWARGS) + raise TypeError( + f"{self.name}() got unexpected keyword arguments: {repr(extra_attrs)}." + ) + + exec( + textwrap.dedent( + f""" + from __future__ import annotations + def {self.name}{str_signature} { '-> ' + repr(type_label(self.method_return_type)) if self.method_return_type is not None else ""}: + {"validate_attrs(kwargs)" if self.method_args_virtual and self.check_attrs_match_sig else ""} + return implementation({self._method_signature_to_implementation_call(self._signature)}) + """ + ), + { + "implementation": self.implementation, + "MISSING": MISSING, + "UNSPECIFIED": UNSPECIFIED, + "validate_attrs": validate_attrs, + "DEFAULTS": defaults, + }, + namespace, + ) + else: + import hashlib + function_source = textwrap.dedent( f""" from __future__ import annotations - def {self.name}{str_signature} { '-> ' + repr(type_label(self.method_return_type)) if self.method_return_type is not None else ""}: - {"validate_attrs(kwargs)" if self.method_args_virtual and self.check_attrs_match_sig else ""} - return implementation({self._method_signature_to_implementation_call(self._signature)}) + def {self.name}{self._signature_without_annotations} { '-> ' + repr(type_label(self.method_return_type)) if self.method_return_type is not None else ""}: +{textwrap.indent(self.implementation, " ")} """ - ), - { - "implementation": self.implementation, - "MISSING": MISSING, - "validate_attrs": validate_attrs, - "DEFAULTS": defaults, - }, - namespace, - ) + ) + source_hash = hashlib.sha256(function_source.encode()).hexdigest() + fake_source_file = f"spec_classes/{source_hash}.py" + print(function_source, defaults) + + # In order of debuggers like PDB being able to step through the code, + # we add a fake linecache entry. + count = 1 + filename = fake_source_file + while True: + linecache_tuple = ( + len(function_source), + None, + function_source.splitlines(True), + filename, + ) + old_val = linecache.cache.setdefault(fake_source_file, linecache_tuple) + if old_val == linecache_tuple: + break + else: + filename = f"{filename[:-1]}-{count}>" + count += 1 + + code = compile(function_source, filename, "exec") + exec(code, { + **self.exec_context, + "DEFAULTS": defaults, + }, + namespace,) method = namespace[self.name] method.__doc__ = self._docstring @@ -458,6 +502,19 @@ def _signature_virtual(self) -> Signature: self._signature ) # pragma: no cover; we avoid this case in the code to running this twice + @property + def _signature_without_annotations(self) -> str: + args = [] + for arg in (self.method_args[:-1] if self.method_args_virtual else self.method_args): + arg_str = str(Parameter(arg.name, kind=arg.kind)) + if arg.default is not Parameter.empty: + arg_str += f" = DEFAULTS['{arg.name}']" + args.append(arg_str) + if self.method_args_virtual: + for arg in self.method_args_virtual: + args.append(str(Parameter(arg.name, kind=arg.kind)) + (" = UNSPECIFIED" if arg.default is not Parameter.empty else "")) + return f"""({", ".join(args)})""" + @property def _docstring(self) -> str: """ diff --git a/tests/test_spec_class.py b/tests/test_spec_class.py index e39e43a..bfc24db 100644 --- a/tests/test_spec_class.py +++ b/tests/test_spec_class.py @@ -754,7 +754,7 @@ class Spec: with pytest.raises( TypeError, match=re.escape( - "__init__() got unexpected keyword arguments: {'hidden_attr'}." + "__init__() got an unexpected keyword argument 'hidden_attr'" ), ): Spec(hidden_attr="Not here")