Hello community, here is the log from the commit of package python-traittypes for openSUSE:Factory checked in at 2018-08-10 09:48:37 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/python-traittypes (Old) and /work/SRC/openSUSE:Factory/.python-traittypes.new (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-traittypes" Fri Aug 10 09:48:37 2018 rev:2 rq:627752 version:0.2.1 Changes: -------- --- /work/SRC/openSUSE:Factory/python-traittypes/python-traittypes.changes 2018-05-15 10:31:08.597165763 +0200 +++ /work/SRC/openSUSE:Factory/.python-traittypes.new/python-traittypes.changes 2018-08-10 09:48:42.702166892 +0200 @@ -1,0 +2,12 @@ +Thu Aug 2 20:10:12 UTC 2018 - toddrme2...@gmail.com + +- Update to 0.2.1 + * Add xarray DataArray + * Remove unused imports (pandas and xarray) + * Add xarray Dataset + * Allow Undefined as default + * Refactor commond pandas trait type (DRY) + * Add tests for SciType validators + * Only raise error for missing dependencies on use + +------------------------------------------------------------------- Old: ---- traittypes-0.0.6.tar.gz New: ---- traittypes-0.2.1.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python-traittypes.spec ++++++ --- /var/tmp/diff_new_pack.Wqu6nA/_old 2018-08-10 09:48:43.378167980 +0200 +++ /var/tmp/diff_new_pack.Wqu6nA/_new 2018-08-10 09:48:43.378167980 +0200 @@ -18,7 +18,7 @@ %{?!python_module:%define python_module() python-%{**} python3-%{**}} Name: python-traittypes -Version: 0.0.6 +Version: 0.2.1 Release: 0 Summary: Scipy trait types License: BSD-3-Clause @@ -34,11 +34,10 @@ BuildRequires: %{python_module numpy} BuildRequires: %{python_module pandas} BuildRequires: %{python_module pytest} -BuildRequires: %{python_module traitlets} +BuildRequires: %{python_module traitlets >= 4.2.2} +BuildRequires: %{python_module xarray} # /SECTION -Requires: python-numpy -Requires: python-pandas -Requires: python-traitlets +Requires: python-traitlets >= 4.2.2 BuildArch: noarch %python_subpackages ++++++ traittypes-0.0.6.tar.gz -> traittypes-0.2.1.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/traittypes-0.0.6/PKG-INFO new/traittypes-0.2.1/PKG-INFO --- old/traittypes-0.0.6/PKG-INFO 2016-09-08 19:03:24.000000000 +0200 +++ new/traittypes-0.2.1/PKG-INFO 2018-06-16 09:33:42.000000000 +0200 @@ -1,6 +1,6 @@ Metadata-Version: 1.1 Name: traittypes -Version: 0.0.6 +Version: 0.2.1 Summary: Scipy trait types Home-page: http://ipython.org Author: IPython Development Team @@ -18,4 +18,5 @@ Classifier: Programming Language :: Python Classifier: Programming Language :: Python :: 2.7 Classifier: Programming Language :: Python :: 3 -Classifier: Programming Language :: Python :: 3.3 +Classifier: Programming Language :: Python :: 3.5 +Classifier: Programming Language :: Python :: 3.6 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/traittypes-0.0.6/README.md new/traittypes-0.2.1/README.md --- old/traittypes-0.0.6/README.md 2016-08-31 15:03:46.000000000 +0200 +++ new/traittypes-0.2.1/README.md 2018-06-16 09:31:24.000000000 +0200 @@ -1,6 +1,7 @@ # Scipy Trait Types -[![Build Status](https://travis-ci.org/jupyter-incubator/traittypes.svg?branch=master)](https://travis-ci.org/jupyter-incubator/traittypes) +[![Build Status](https://travis-ci.org/jupyter-widgets/traittypes.svg?branch=master)](https://travis-ci.org/jupyter-widgets/traittypes) +[![Documentation Status](https://readthedocs.org/projects/traittypes/badge/?version=latest)](http://traittypes.readthedocs.org/en/latest/?badge=latest) Trait types for NumPy, SciPy and friends @@ -8,8 +9,8 @@ Provide a reference implementation of trait types for common data structures used in the scipy stack such as - - numpy arrays - - pandas / xray data structures + - [numpy](https://github.com/numpy/numpy) arrays + - [pandas](https://github.com/pydata/pandas) and [xarray](https://github.com/pydata/xarray) data structures which are out of the scope of the main [traitlets](https://github.com/ipython/traitlets) project but are a common requirement to build applications with traitlets in @@ -39,13 +40,13 @@ ## Usage -The `Array` trait type provide an implementation of a trait type for the numpy -array. - - `Array` overrides some methods from `TraiType` that are generally not -overloaded in order to work around some limitations with numpy array -comparison. - - `Array` provides an API for adding custom validators to constained proposed -values for the attribute. +`traittypes` extends the `traitlets` library with an implementation of trait types for numpy arrays, pandas dataframes, pandas series, xarray datasets and xarray dataarrays. + - `traittypes` works around some limitations with numpy array comparison to only trigger change events when necessary. + - `traittypes` also extends the traitlets API for adding custom validators to constained proposed values for the attribute. + +For a general introduction to `traitlets`, check out the [traitlets documentation](https://traitlets.readthedocs.io/en/stable/). + +### Example usage with a custom validator ```python from traitlets import HasTraits, TraitError Binary files old/traittypes-0.0.6/docs/.DS_Store and new/traittypes-0.2.1/docs/.DS_Store differ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/traittypes-0.0.6/docs/Makefile new/traittypes-0.2.1/docs/Makefile --- old/traittypes-0.0.6/docs/Makefile 1970-01-01 01:00:00.000000000 +0100 +++ new/traittypes-0.2.1/docs/Makefile 2016-09-23 18:28:45.000000000 +0200 @@ -0,0 +1,194 @@ +# Makefile for Sphinx documentation +# + +# You can set these variables from the command line. +SPHINXOPTS = +SPHINXBUILD = sphinx-build +PAPER = +BUILDDIR = build + +# User-friendly check for sphinx-build +ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1) +$(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/) +endif + +# Internal variables. +PAPEROPT_a4 = -D latex_paper_size=a4 +PAPEROPT_letter = -D latex_paper_size=letter +ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source +# the i18n builder cannot share the environment and doctrees with the others +I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source + +.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest coverage gettext api + +default: html + +help: + @echo "Please use \`make <target>' where <target> is one of" + @echo " html to make standalone HTML files" + @echo " dirhtml to make HTML files named index.html in directories" + @echo " singlehtml to make a single large HTML file" + @echo " pickle to make pickle files" + @echo " json to make JSON files" + @echo " htmlhelp to make HTML files and a HTML help project" + @echo " qthelp to make HTML files and a qthelp project" + @echo " applehelp to make an Apple Help Book" + @echo " devhelp to make HTML files and a Devhelp project" + @echo " epub to make an epub" + @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" + @echo " latexpdf to make LaTeX files and run them through pdflatex" + @echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx" + @echo " text to make text files" + @echo " man to make manual pages" + @echo " texinfo to make Texinfo files" + @echo " info to make Texinfo files and run them through makeinfo" + @echo " gettext to make PO message catalogs" + @echo " changes to make an overview of all changed/added/deprecated items" + @echo " xml to make Docutils-native XML files" + @echo " pseudoxml to make pseudoxml-XML files for display purposes" + @echo " linkcheck to check all external links for integrity" + @echo " doctest to run all doctests embedded in the documentation (if enabled)" + @echo " coverage to run coverage check of the documentation (if enabled)" + +clean: + rm -rf $(BUILDDIR)/* + +html: + $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html + @echo + @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." + +dirhtml: + $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml + @echo + @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." + +singlehtml: + $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml + @echo + @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." + +pickle: + $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle + @echo + @echo "Build finished; now you can process the pickle files." + +json: + $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json + @echo + @echo "Build finished; now you can process the JSON files." + +htmlhelp: + $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp + @echo + @echo "Build finished; now you can run HTML Help Workshop with the" \ + ".hhp project file in $(BUILDDIR)/htmlhelp." + +qthelp: + $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp + @echo + @echo "Build finished; now you can run "qcollectiongenerator" with the" \ + ".qhcp project file in $(BUILDDIR)/qthelp, like this:" + @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/traittypes.qhcp" + @echo "To view the help file:" + @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/traittypes.qhc" + +applehelp: + $(SPHINXBUILD) -b applehelp $(ALLSPHINXOPTS) $(BUILDDIR)/applehelp + @echo + @echo "Build finished. The help book is in $(BUILDDIR)/applehelp." + @echo "N.B. You won't be able to view it unless you put it in" \ + "~/Library/Documentation/Help or install it in your application" \ + "bundle." + +devhelp: + $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp + @echo + @echo "Build finished." + @echo "To view the help file:" + @echo "# mkdir -p $$HOME/.local/share/devhelp/traittypes" + @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/traittypes" + @echo "# devhelp" + +epub: + $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub + @echo + @echo "Build finished. The epub file is in $(BUILDDIR)/epub." + +latex: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo + @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." + @echo "Run \`make' in that directory to run these through (pdf)latex" \ + "(use \`make latexpdf' here to do that automatically)." + +latexpdf: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo "Running LaTeX files through pdflatex..." + $(MAKE) -C $(BUILDDIR)/latex all-pdf + @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." + +latexpdfja: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo "Running LaTeX files through platex and dvipdfmx..." + $(MAKE) -C $(BUILDDIR)/latex all-pdf-ja + @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." + +text: + $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text + @echo + @echo "Build finished. The text files are in $(BUILDDIR)/text." + +man: + $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man + @echo + @echo "Build finished. The manual pages are in $(BUILDDIR)/man." + +texinfo: + $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo + @echo + @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." + @echo "Run \`make' in that directory to run these through makeinfo" \ + "(use \`make info' here to do that automatically)." + +info: + $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo + @echo "Running Texinfo files through makeinfo..." + make -C $(BUILDDIR)/texinfo info + @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." + +gettext: + $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale + @echo + @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." + +changes: + $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes + @echo + @echo "The overview file is in $(BUILDDIR)/changes." + +linkcheck: + $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck + @echo + @echo "Link check complete; look for any errors in the above output " \ + "or in $(BUILDDIR)/linkcheck/output.txt." + +doctest: + $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest + @echo "Testing of doctests in the sources finished, look at the " \ + "results in $(BUILDDIR)/doctest/output.txt." + +coverage: + $(SPHINXBUILD) -b coverage $(ALLSPHINXOPTS) $(BUILDDIR)/coverage + @echo "Testing of coverage in the sources finished, look at the " \ + "results in $(BUILDDIR)/coverage/python.txt." + +xml: + $(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml + @echo + @echo "Build finished. The XML files are in $(BUILDDIR)/xml." + +pseudoxml: + $(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml + @echo + @echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml." diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/traittypes-0.0.6/docs/make.bat new/traittypes-0.2.1/docs/make.bat --- old/traittypes-0.0.6/docs/make.bat 1970-01-01 01:00:00.000000000 +0100 +++ new/traittypes-0.2.1/docs/make.bat 2016-09-23 18:28:45.000000000 +0200 @@ -0,0 +1,263 @@ +@ECHO OFF + +REM Command file for Sphinx documentation + +if "%SPHINXBUILD%" == "" ( + set SPHINXBUILD=sphinx-build +) +set BUILDDIR=build +set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% source +set I18NSPHINXOPTS=%SPHINXOPTS% source +if NOT "%PAPER%" == "" ( + set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS% + set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS% +) + +if "%1" == "" goto help + +if "%1" == "help" ( + :help + echo.Please use `make ^<target^>` where ^<target^> is one of + echo. html to make standalone HTML files + echo. dirhtml to make HTML files named index.html in directories + echo. singlehtml to make a single large HTML file + echo. pickle to make pickle files + echo. json to make JSON files + echo. htmlhelp to make HTML files and a HTML help project + echo. qthelp to make HTML files and a qthelp project + echo. devhelp to make HTML files and a Devhelp project + echo. epub to make an epub + echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter + echo. text to make text files + echo. man to make manual pages + echo. texinfo to make Texinfo files + echo. gettext to make PO message catalogs + echo. changes to make an overview over all changed/added/deprecated items + echo. xml to make Docutils-native XML files + echo. pseudoxml to make pseudoxml-XML files for display purposes + echo. linkcheck to check all external links for integrity + echo. doctest to run all doctests embedded in the documentation if enabled + echo. coverage to run coverage check of the documentation if enabled + goto end +) + +if "%1" == "clean" ( + for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i + del /q /s %BUILDDIR%\* + goto end +) + + +REM Check if sphinx-build is available and fallback to Python version if any +%SPHINXBUILD% 2> nul +if errorlevel 9009 goto sphinx_python +goto sphinx_ok + +:sphinx_python + +set SPHINXBUILD=python -m sphinx.__init__ +%SPHINXBUILD% 2> nul +if errorlevel 9009 ( + echo. + echo.The 'sphinx-build' command was not found. Make sure you have Sphinx + echo.installed, then set the SPHINXBUILD environment variable to point + echo.to the full path of the 'sphinx-build' executable. Alternatively you + echo.may add the Sphinx directory to PATH. + echo. + echo.If you don't have Sphinx installed, grab it from + echo.http://sphinx-doc.org/ + exit /b 1 +) + +:sphinx_ok + + +if "%1" == "html" ( + %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The HTML pages are in %BUILDDIR%/html. + goto end +) + +if "%1" == "dirhtml" ( + %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml. + goto end +) + +if "%1" == "singlehtml" ( + %SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml. + goto end +) + +if "%1" == "pickle" ( + %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle + if errorlevel 1 exit /b 1 + echo. + echo.Build finished; now you can process the pickle files. + goto end +) + +if "%1" == "json" ( + %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json + if errorlevel 1 exit /b 1 + echo. + echo.Build finished; now you can process the JSON files. + goto end +) + +if "%1" == "htmlhelp" ( + %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp + if errorlevel 1 exit /b 1 + echo. + echo.Build finished; now you can run HTML Help Workshop with the ^ +.hhp project file in %BUILDDIR%/htmlhelp. + goto end +) + +if "%1" == "qthelp" ( + %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp + if errorlevel 1 exit /b 1 + echo. + echo.Build finished; now you can run "qcollectiongenerator" with the ^ +.qhcp project file in %BUILDDIR%/qthelp, like this: + echo.^> qcollectiongenerator %BUILDDIR%\qthelp\traittypes.qhcp + echo.To view the help file: + echo.^> assistant -collectionFile %BUILDDIR%\qthelp\traittypes.ghc + goto end +) + +if "%1" == "devhelp" ( + %SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. + goto end +) + +if "%1" == "epub" ( + %SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The epub file is in %BUILDDIR%/epub. + goto end +) + +if "%1" == "latex" ( + %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex + if errorlevel 1 exit /b 1 + echo. + echo.Build finished; the LaTeX files are in %BUILDDIR%/latex. + goto end +) + +if "%1" == "latexpdf" ( + %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex + cd %BUILDDIR%/latex + make all-pdf + cd %~dp0 + echo. + echo.Build finished; the PDF files are in %BUILDDIR%/latex. + goto end +) + +if "%1" == "latexpdfja" ( + %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex + cd %BUILDDIR%/latex + make all-pdf-ja + cd %~dp0 + echo. + echo.Build finished; the PDF files are in %BUILDDIR%/latex. + goto end +) + +if "%1" == "text" ( + %SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The text files are in %BUILDDIR%/text. + goto end +) + +if "%1" == "man" ( + %SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The manual pages are in %BUILDDIR%/man. + goto end +) + +if "%1" == "texinfo" ( + %SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo. + goto end +) + +if "%1" == "gettext" ( + %SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The message catalogs are in %BUILDDIR%/locale. + goto end +) + +if "%1" == "changes" ( + %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes + if errorlevel 1 exit /b 1 + echo. + echo.The overview file is in %BUILDDIR%/changes. + goto end +) + +if "%1" == "linkcheck" ( + %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck + if errorlevel 1 exit /b 1 + echo. + echo.Link check complete; look for any errors in the above output ^ +or in %BUILDDIR%/linkcheck/output.txt. + goto end +) + +if "%1" == "doctest" ( + %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest + if errorlevel 1 exit /b 1 + echo. + echo.Testing of doctests in the sources finished, look at the ^ +results in %BUILDDIR%/doctest/output.txt. + goto end +) + +if "%1" == "coverage" ( + %SPHINXBUILD% -b coverage %ALLSPHINXOPTS% %BUILDDIR%/coverage + if errorlevel 1 exit /b 1 + echo. + echo.Testing of coverage in the sources finished, look at the ^ +results in %BUILDDIR%/coverage/python.txt. + goto end +) + +if "%1" == "xml" ( + %SPHINXBUILD% -b xml %ALLSPHINXOPTS% %BUILDDIR%/xml + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The XML files are in %BUILDDIR%/xml. + goto end +) + +if "%1" == "pseudoxml" ( + %SPHINXBUILD% -b pseudoxml %ALLSPHINXOPTS% %BUILDDIR%/pseudoxml + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The pseudo-XML files are in %BUILDDIR%/pseudoxml. + goto end +) + +:end diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/traittypes-0.0.6/docs/requirements.txt new/traittypes-0.2.1/docs/requirements.txt --- old/traittypes-0.0.6/docs/requirements.txt 1970-01-01 01:00:00.000000000 +0100 +++ new/traittypes-0.2.1/docs/requirements.txt 2016-09-23 18:28:45.000000000 +0200 @@ -0,0 +1 @@ +-e . diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/traittypes-0.0.6/docs/source/api_documentation.rst new/traittypes-0.2.1/docs/source/api_documentation.rst --- old/traittypes-0.0.6/docs/source/api_documentation.rst 1970-01-01 01:00:00.000000000 +0100 +++ new/traittypes-0.2.1/docs/source/api_documentation.rst 2018-06-16 09:31:41.000000000 +0200 @@ -0,0 +1,30 @@ +API Reference Documentation +--------------------------- + +The ``SciType`` trait type is the base trait type for all Scipy trait types. + +It complements the ``traitlets.TraitType`` with a special API to register custom +validators. + +.. autoclass:: traittypes.traittypes.SciType + :members: + +The ``Array`` trait type holds a numpy Array. + +.. autoclass:: traittypes.traittypes.Array + +The ``DataFrame`` trait type holds a pandas DataFrame. + +.. autoclass:: traittypes.traittypes.DataFrame + +The ``Series`` trait type holds a pandas Series. + +.. autoclass:: traittypes.traittypes.Series + +The ``Dataset`` trait type holds an xarray Dataset. + +.. autoclass:: traittypes.traittypes.Dataset + +The ``DataArray`` trait type holds an xarray DataArray. + +.. autoclass:: traittypes.traittypes.DataArray diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/traittypes-0.0.6/docs/source/conf.py new/traittypes-0.2.1/docs/source/conf.py --- old/traittypes-0.0.6/docs/source/conf.py 1970-01-01 01:00:00.000000000 +0100 +++ new/traittypes-0.2.1/docs/source/conf.py 2016-09-23 19:10:50.000000000 +0200 @@ -0,0 +1,268 @@ +# -*- coding: utf-8 -*- +# +# traittypes documentation build configuration file. +# +# NOTE: This file has been edited manually from the auto-generated one from +# sphinx. Do NOT delete and re-generate. If any changes from sphinx are +# needed, generate a scratch one and merge by hand any new fields needed. +# + +import sys +import os + + +# We load the traittypes release info into a dict by explicit execution +import traittypes +release = traittypes.__version__ + +# -- General configuration ------------------------------------------------ + +# If your documentation needs a minimal Sphinx version, state it here. +#needs_sphinx = '1.0' + +# Add any Sphinx extension module names here, as strings. They can be +# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom +# ones. +extensions = [ + 'sphinx.ext.autodoc', + 'sphinx.ext.intersphinx', + 'sphinx.ext.autosummary', + 'sphinx.ext.viewcode', + 'sphinx.ext.napoleon', + 'sphinx.ext.mathjax', +] + +autosummary_generate = True + +# Add any paths that contain templates here, relative to this directory. +templates_path = ['_templates'] + +# The suffix(es) of source filenames. +source_suffix = '.rst' + +# Add dev disclaimer. +if 'dev' in release: + rst_prolog = """ + .. note:: + + This documentation is for a development version of traittypes. There may be + significant differences from the latest stable release. + + """ + +# The encoding of source files. +#source_encoding = 'utf-8-sig' + +# The master toctree document. +master_doc = 'index' + +# General information about the project. +project = u'traittypes' +author = u'The IPython Contributors' + +# The version info for the project you're documenting, acts as replacement for +# |version| and |release|, also used in various other places throughout the +# built documents. +# + +# The language for content autogenerated by Sphinx. Refer to documentation +# for a list of supported languages. +language = None + +# There are two options for replacing |today|: either, you set today to some +# non-false value, then it is used: +#today = '' +# Else, today_fmt is used as the format for a strftime call. +#today_fmt = '%B %d, %Y' + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +exclude_patterns = [] + +# The reST default role (used for this markup: `text`) to use for all +# documents. +#default_role = None + +# If true, '()' will be appended to :func: etc. cross-reference text. +#add_function_parentheses = True + +# If true, the current module name will be prepended to all description +# unit titles (such as .. function::). +#add_module_names = True + +# If true, sectionauthor and moduleauthor directives will be shown in the +# output. They are ignored by default. +#show_authors = False + +# The name of the Pygments (syntax highlighting) style to use. +pygments_style = 'sphinx' + +# A list of ignored prefixes for module index sorting. +#modindex_common_prefix = [] + +# If true, keep warnings as "system message" paragraphs in the built documents. +#keep_warnings = False + + +# -- Options for HTML output ---------------------------------------------- + +# The theme to use for HTML and HTML Help pages. See the documentation for +# a list of builtin themes. +#html_theme = 'alabaster' + +# Theme options are theme-specific and customize the look and feel of a theme +# further. For a list of options available for each theme, see the +# documentation. +#html_theme_options = {} + +# Add any paths that contain custom themes here, relative to this directory. +#html_theme_path = [] + +# The name for this set of Sphinx documents. If None, it defaults to +# "<project> v<release> documentation". +#html_title = None + +# A shorter title for the navigation bar. Default is the same as html_title. +#html_short_title = None + +# The name of an image file (relative to this directory) to place at the top +# of the sidebar. +#html_logo = None + +# The name of an image file (within the static path) to use as favicon of the +# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 +# pixels large. +#html_favicon = None + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +# html_static_path = ['_static'] + +# Add any extra paths that contain custom files (such as robots.txt or +# .htaccess) here, relative to this directory. These files are copied +# directly to the root of the documentation. +#html_extra_path = [] + +# If not '', a 'Last updated on:' timestamp is inserted at every page bottom, +# using the given strftime format. +#html_last_updated_fmt = '%b %d, %Y' + +# If true, SmartyPants will be used to convert quotes and dashes to +# typographically correct entities. +#html_use_smartypants = True + +# Custom sidebar templates, maps document names to template names. +#html_sidebars = {} + +# Additional templates that should be rendered to pages, maps page names to +# template names. +#html_additional_pages = {} + +# If false, no module index is generated. +#html_domain_indices = True + +# If false, no index is generated. +#html_use_index = True + +# If true, the index is split into individual pages for each letter. +#html_split_index = False + +# If true, links to the reST sources are added to the pages. +#html_show_sourcelink = True + +# If true, "Created using Sphinx" is shown in the HTML footer. Default is True. +#html_show_sphinx = True + +# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. +#html_show_copyright = True + +# If true, an OpenSearch description file will be output, and all pages will +# contain a <link> tag referring to it. The value of this option must be the +# base URL from which the finished HTML is served. +#html_use_opensearch = '' + +# This is the file name suffix for HTML files (e.g. ".xhtml"). +#html_file_suffix = None + +# Output file base name for HTML help builder. +htmlhelp_basename = 'traittypesdoc' + + +# -- Options for LaTeX output --------------------------------------------- + +latex_elements = { +# The paper size ('letterpaper' or 'a4paper'). +#'papersize': 'letterpaper', + +# The font size ('10pt', '11pt' or '12pt'). +#'pointsize': '10pt', + +# Additional stuff for the LaTeX preamble. +#'preamble': '', +} + +# Grouping the document tree into LaTeX files. List of tuples +# (source start file, target name, title, +# author, documentclass [howto, manual, or own class]). +latex_documents = [ + ('index', 'traittypes.tex', u'traittypes Documentation', + u'IPython contributors', 'manual'), +] + +# The name of an image file (relative to this directory) to place at the top of +# the title page. +#latex_logo = None + +# For "manual" documents, if this is true, then toplevel headings are parts, +# not chapters. +#latex_use_parts = False + +# If true, show page references after internal links. +#latex_show_pagerefs = False + +# If true, show URL addresses after external links. +#latex_show_urls = False + +# Documents to append as an appendix to all manuals. +#latex_appendices = [] + +# If false, no module index is generated. +#latex_domain_indices = True + + +# -- Options for manual page output --------------------------------------- + +# One entry per manual page. List of tuples +# (source start file, name, description, authors, manual section). +man_pages = [ + ('index', 'traittypes', u'traittypes Documentation', + [u'IPython contributors'], 1) +] + +# If true, show URL addresses after external links. +#man_show_urls = False + + +# -- Options for Texinfo output ------------------------------------------- + +# Grouping the document tree into Texinfo files. List of tuples +# (source start file, target name, title, author, +# dir menu entry, description, category) +texinfo_documents = [ + ('index', 'traittypes', u'traittypes Documentation', + u'IPython contributors', 'traittypes', 'One line description of project.', + 'Miscellaneous'), +] + +# Documents to append as an appendix to all manuals. +#texinfo_appendices = [] + +# If false, no module index is generated. +#texinfo_domain_indices = True + +# How to display URL addresses: 'footnote', 'no', or 'inline'. +#texinfo_show_urls = 'footnote' + +# If true, do not generate a @detailmenu in the "Top" node's menu. +#texinfo_no_detailmenu = False diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/traittypes-0.0.6/docs/source/index.rst new/traittypes-0.2.1/docs/source/index.rst --- old/traittypes-0.0.6/docs/source/index.rst 1970-01-01 01:00:00.000000000 +0100 +++ new/traittypes-0.2.1/docs/source/index.rst 2016-09-25 00:09:35.000000000 +0200 @@ -0,0 +1,9 @@ +============================================= +traittypes: Trait Types for Scientific Python +============================================= + +.. toctree:: + + introduction + usage + api_documentation diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/traittypes-0.0.6/docs/source/introduction.rst new/traittypes-0.2.1/docs/source/introduction.rst --- old/traittypes-0.0.6/docs/source/introduction.rst 1970-01-01 01:00:00.000000000 +0100 +++ new/traittypes-0.2.1/docs/source/introduction.rst 2016-09-23 18:28:45.000000000 +0200 @@ -0,0 +1,19 @@ +.. _introduction: + +Introduction +============ + +The `traittypes` module provides a robust reference implementation of trait +types for common data structures used in the scipy stack such as + + - `numpy <https://github.com/numpy/numpy>`_ arrays + - `pandas <https://github.com/pydata/pandas>`_ and `xarray <https://github.com/pydata/xarray>`_ data structures + +which are out of the scope of the main `traitlets <https://github.com/ipython/traitlets>`_ +project but are a common requirement to build applications with traitlets in +combination with the scipy stack. + +Another goal is to create adequate serialization and deserialization routines +for these trait types to be used with the `ipywidgets <https://github.com/ipython/ipywidgets>`_ +project (``to_json`` and ``from_json``). These could also return a list of binary +buffers as allowed by the current messaging protocol. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/traittypes-0.0.6/docs/source/usage.rst new/traittypes-0.2.1/docs/source/usage.rst --- old/traittypes-0.0.6/docs/source/usage.rst 1970-01-01 01:00:00.000000000 +0100 +++ new/traittypes-0.2.1/docs/source/usage.rst 2016-09-23 18:40:52.000000000 +0200 @@ -0,0 +1,29 @@ +Usage +===== + +Example: Validating the Shape of a Numpy Array +---------------------------------------------- + +We pass a validation function to the ``valid`` method of the ``Array`` trait type. + +In this example, the validation function is returned by the ``shape`` closure which stores +the tuple in its closure. + +.. code:: + + from traitlets import HasTraits, TraitError + from traittypes import Array + + def shape(*dimensions): + def validator(trait, value): + if value.shape != dimensions: + raise TraitError('Expected an of shape %s and got and array with shape %s' % (dimensions, value.shape)) + else: + return value + return validator + + class Foo(HasTraits): + bar = Array(np.identity(2)).valid(shape(2, 2)) + foo = Foo() + + foo.bar = [1, 2] # Should raise a TraitError diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/traittypes-0.0.6/setup.cfg new/traittypes-0.2.1/setup.cfg --- old/traittypes-0.0.6/setup.cfg 2015-11-13 21:21:41.000000000 +0100 +++ new/traittypes-0.2.1/setup.cfg 2018-06-15 15:32:38.000000000 +0200 @@ -1,2 +1,5 @@ [bdist_wheel] universal=1 + +[metadata] +license_file = LICENSE diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/traittypes-0.0.6/setup.py new/traittypes-0.2.1/setup.py --- old/traittypes-0.0.6/setup.py 2016-09-08 17:02:13.000000000 +0200 +++ new/traittypes-0.2.1/setup.py 2018-06-15 15:32:38.000000000 +0200 @@ -16,8 +16,8 @@ import sys v = sys.version_info -if v[:2] < (2,7) or (v[0] >= 3 and v[:2] < (3,3)): - error = "ERROR: %s requires Python version 2.7 or 3.3 or above." % name +if v[:2] < (2,7) or (v[0] >= 3 and v[:2] < (3, 5)): + error = "ERROR: %s requires Python version 2.7 or 3.5 or above." % name print(error, file=sys.stderr) sys.exit(1) @@ -67,7 +67,8 @@ 'Programming Language :: Python', 'Programming Language :: Python :: 2.7', 'Programming Language :: Python :: 3', - 'Programming Language :: Python :: 3.3', + 'Programming Language :: Python :: 3.5', + 'Programming Language :: Python :: 3.6', ], ) @@ -78,11 +79,15 @@ install_requires = setuptools_args['install_requires'] = [ 'traitlets>=4.2.2', - 'numpy', - 'pandas' ] extras_require = setuptools_args['extras_require'] = { + 'test': [ + 'numpy', + 'pandas', + 'xarray', + 'pytest', # traitlets[test] require this + ] } if 'setuptools' in sys.modules: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/traittypes-0.0.6/traittypes/_version.py new/traittypes-0.2.1/traittypes/_version.py --- old/traittypes-0.0.6/traittypes/_version.py 2016-09-08 19:00:02.000000000 +0200 +++ new/traittypes-0.2.1/traittypes/_version.py 2018-06-16 09:32:53.000000000 +0200 @@ -1,2 +1,2 @@ -version_info = (0, 0, 6) +version_info = (0, 2, 1) __version__ = '.'.join(map(str, version_info)) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/traittypes-0.0.6/traittypes/tests/test_import_errors.py new/traittypes-0.2.1/traittypes/tests/test_import_errors.py --- old/traittypes-0.0.6/traittypes/tests/test_import_errors.py 1970-01-01 01:00:00.000000000 +0100 +++ new/traittypes-0.2.1/traittypes/tests/test_import_errors.py 2018-04-27 16:58:52.000000000 +0200 @@ -0,0 +1,10 @@ + +import nose.tools as nt + +from ..traittypes import _DelayedImportError + + +@nt.raises(RuntimeError) +def test_delayed_access_raises(): + dummy = _DelayedImportError('mypackage') + dummy.asarray([1, 2, 3]) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/traittypes-0.0.6/traittypes/tests/test_traittypes.py new/traittypes-0.2.1/traittypes/tests/test_traittypes.py --- old/traittypes-0.0.6/traittypes/tests/test_traittypes.py 2016-09-08 17:02:13.000000000 +0200 +++ new/traittypes-0.2.1/traittypes/tests/test_traittypes.py 2018-06-15 15:32:38.000000000 +0200 @@ -5,11 +5,12 @@ # Distributed under the terms of the Modified BSD License. from unittest import TestCase -from traitlets import HasTraits, TraitError, observe +from traitlets import HasTraits, TraitError, observe, Undefined from traitlets.tests.test_traitlets import TraitTestBase -from traittypes import Array, DataFrame, Series +from traittypes import Array, DataFrame, Series, Dataset, DataArray import numpy as np import pandas as pd +import xarray as xr # Good / Bad value trait test cases @@ -56,11 +57,13 @@ b = Array(dtype='int') c = Array(None, allow_none=True) d = Array([]) + e = Array(Undefined) foo = Foo() self.assertTrue(np.array_equal(foo.a, np.array(0))) self.assertTrue(np.array_equal(foo.b, np.array(0))) self.assertTrue(foo.c is None) self.assertTrue(np.array_equal(foo.d, [])) + self.assertTrue(foo.e is Undefined) def test_allow_none(self): class Foo(HasTraits): @@ -116,19 +119,21 @@ notifications.append(change) foo = Foo() foo.bar = [1, 2] - self.assertFalse(len(notifications)) + self.assertEqual(notifications, []) foo.bar = [1, 1] - self.assertTrue(len(notifications)) + self.assertEqual(len(notifications), 1) def test_initial_values(self): class Foo(HasTraits): a = DataFrame() b = DataFrame(None, allow_none=True) c = DataFrame([]) + d = DataFrame(Undefined) foo = Foo() self.assertTrue(foo.a.equals(pd.DataFrame())) self.assertTrue(foo.b is None) self.assertTrue(foo.c.equals(pd.DataFrame([]))) + self.assertTrue(foo.d is Undefined) def test_allow_none(self): class Foo(HasTraits): @@ -142,7 +147,7 @@ class TestSeries(TestCase): - def test_sereis_equal(self): + def test_series_equal(self): notifications = [] class Foo(HasTraits): bar = Series([1, 2]) @@ -151,19 +156,21 @@ notifications.append(change) foo = Foo() foo.bar = [1, 2] - self.assertFalse(len(notifications)) + self.assertEqual(notifications, []) foo.bar = [1, 1] - self.assertTrue(len(notifications)) + self.assertEqual(len(notifications), 1) def test_initial_values(self): class Foo(HasTraits): a = Series() b = Series(None, allow_none=True) c = Series([]) + d = Series(Undefined) foo = Foo() self.assertTrue(foo.a.equals(pd.Series())) self.assertTrue(foo.b is None) self.assertTrue(foo.c.equals(pd.Series([]))) + self.assertTrue(foo.d is Undefined) def test_allow_none(self): class Foo(HasTraits): @@ -172,4 +179,65 @@ foo = Foo() with self.assertRaises(TraitError): foo.bar = None - foo.baz = None \ No newline at end of file + foo.baz = None + + +class TestDataset(TestCase): + + def test_ds_equal(self): + notifications = [] + class Foo(HasTraits): + bar = Dataset({'foo': xr.DataArray([[0, 1, 2], [3, 4, 5]], coords={'x': ['a', 'b']}, dims=('x', 'y')), 'bar': ('x', [1, 2]), 'baz': 3.14}) + @observe('bar') + def _(self, change): + notifications.append(change) + foo = Foo() + foo.bar = {'foo': xr.DataArray([[0, 1, 2], [3, 4, 5]], coords={'x': ['a', 'b']}, dims=('x', 'y')), 'bar': ('x', [1, 2]), 'baz': 3.14} + self.assertEqual(notifications, []) + foo.bar = {'foo': xr.DataArray([[0, 1, 2], [3, 4, 5]], coords={'x': ['a', 'b']}, dims=('x', 'y')), 'bar': ('x', [1, 2]), 'baz': 3.15} + self.assertEqual(len(notifications), 1) + + def test_initial_values(self): + class Foo(HasTraits): + a = Dataset() + b = Dataset(None, allow_none=True) + d = Dataset(Undefined) + foo = Foo() + self.assertTrue(foo.a.equals(xr.Dataset())) + self.assertTrue(foo.b is None) + self.assertTrue(foo.d is Undefined) + + def test_allow_none(self): + class Foo(HasTraits): + bar = Dataset() + baz = Dataset(allow_none=True) + foo = Foo() + with self.assertRaises(TraitError): + foo.bar = None + foo.baz = None + + +class TestDataArray(TestCase): + + def test_ds_equal(self): + notifications = [] + class Foo(HasTraits): + bar = DataArray([[0, 1], [2, 3]]) + @observe('bar') + def _(self, change): + notifications.append(change) + foo = Foo() + foo.bar = [[0, 1], [2, 3]] + self.assertEqual(notifications, []) + foo.bar = [[0, 1], [2, 4]] + self.assertEqual(len(notifications), 1) + + def test_initial_values(self): + class Foo(HasTraits): + b = DataArray(None, allow_none=True) + c = DataArray([]) + d = DataArray(Undefined) + foo = Foo() + self.assertTrue(foo.b is None) + self.assertTrue(foo.c.equals(xr.DataArray([]))) + self.assertTrue(foo.d is Undefined) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/traittypes-0.0.6/traittypes/tests/test_validators.py new/traittypes-0.2.1/traittypes/tests/test_validators.py --- old/traittypes-0.0.6/traittypes/tests/test_validators.py 1970-01-01 01:00:00.000000000 +0100 +++ new/traittypes-0.2.1/traittypes/tests/test_validators.py 2018-05-25 18:04:13.000000000 +0200 @@ -0,0 +1,47 @@ +#!/usr/bin/env python +# coding: utf-8 + +# Copyright (c) Jupyter Development Team. +# Distributed under the terms of the Modified BSD License. + +import pytest + +from traitlets import HasTraits, TraitError + +from ..traittypes import SciType + + +def test_coercion_validator(): + # Test with a squeeze coercion + def truncate(trait, value): + return value[:10] + + class Foo(HasTraits): + bar = SciType().valid(truncate) + + foo = Foo(bar=list(range(20))) + assert foo.bar == list(range(10)) + foo.bar = list(range(10, 40)) + assert foo.bar == list(range(10, 20)) + + +def test_validaton_error(): + # Test with a squeeze coercion + def maxlen(trait, value): + if len(value) > 10: + raise ValueError('Too long sequence!') + return value + + class Foo(HasTraits): + bar = SciType().valid(maxlen) + + # Check that it works as expected: + foo = Foo(bar=list(range(5))) + assert foo.bar == list(range(5)) + # Check that it fails as expected: + with pytest.raises(TraitError): # Should convert ValueError to TraitError + foo.bar = list(range(10, 40)) + assert foo.bar == list(range(5)) + # Check that it can again be set correctly + foo = Foo(bar=list(range(5, 10))) + assert foo.bar == list(range(5, 10)) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/traittypes-0.0.6/traittypes/traittypes.py new/traittypes-0.2.1/traittypes/traittypes.py --- old/traittypes-0.0.6/traittypes/traittypes.py 2016-09-08 18:53:16.000000000 +0200 +++ new/traittypes-0.2.1/traittypes/traittypes.py 2018-06-15 15:32:38.000000000 +0200 @@ -1,11 +1,36 @@ -from traitlets import TraitType, TraitError, Undefined -import numpy as np -import pandas as pd +import inspect +import warnings + +from traitlets import TraitType, TraitError, Undefined, Sentinel + +class _DelayedImportError(object): + def __init__(self, package_name): + self.package_name = package_name + + def __getattribute__(self, name): + package_name = super(_DelayedImportError, self).__getattribute__('package_name') + raise RuntimeError('Missing dependency: %s' % package_name) + +try: + import numpy as np +except ImportError: + np = _DelayedImportError('numpy') + + +Empty = Sentinel('Empty', 'traittypes', +""" +Used in traittypes to specify that the default value should +be an empty dataset +""") class SciType(TraitType): - """A base traittype for numpy arrays, pandas dataframes and series.""" + """A base trait type for numpy arrays, pandas dataframes, pandas series, xarray datasets and xarray dataarrays.""" + + def __init__(self, **kwargs): + super(SciType, self).__init__(**kwargs) + self.validators = [] def valid(self, *validators): """ @@ -24,7 +49,8 @@ Example ------- - .. code-block:: python + .. code:: python + # Test with a shape constraint def shape(*dimensions): def validator(trait, value): @@ -43,6 +69,15 @@ self.validators.extend(validators) return self + def validate(self, obj, value): + """Validate the value against registered validators.""" + try: + for validator in self.validators: + value = validator(self, value) + return value + except (ValueError, TypeError) as e: + raise TraitError(e) + class Array(SciType): @@ -54,13 +89,20 @@ def validate(self, obj, value): if value is None and not self.allow_none: self.error(obj, value) + if value is None or value is Undefined: + return super(Array, self).validate(obj, value) try: - value = np.asarray(value, dtype=self.dtype) - for validator in self.validators: - value = validator(self, value) - return value + r = np.asarray(value, dtype=self.dtype) + if isinstance(value, np.ndarray) and r is not value: + warnings.warn( + 'Given trait value dtype "%s" does not match required type "%s". ' + 'A coerced copy has been created.' % ( + np.dtype(value.dtype).name, + np.dtype(self.dtype).name)) + value = r except (ValueError, TypeError) as e: raise TraitError(e) + return super(Array, self).validate(obj, value) def set(self, obj, value): new_value = self._validate(obj, value) @@ -69,97 +111,174 @@ if not np.array_equal(old_value, new_value): obj._notify_trait(self.name, old_value, new_value) - def __init__(self, default_value=Undefined, allow_none=False, dtype=None, **kwargs): + def __init__(self, default_value=Empty, allow_none=False, dtype=None, **kwargs): self.dtype = dtype - if default_value is Undefined: + if default_value is Empty: default_value = np.array(0, dtype=self.dtype) - elif default_value is not None: + elif default_value is not None and default_value is not Undefined: default_value = np.asarray(default_value, dtype=self.dtype) - self.validators = [] super(Array, self).__init__(default_value=default_value, allow_none=allow_none, **kwargs) def make_dynamic_default(self): - if self.default_value is None: + if self.default_value is None or self.default_value is Undefined: return self.default_value else: return np.copy(self.default_value) -class DataFrame(SciType): +class PandasType(SciType): - """A pandas dataframe trait type.""" + """A pandas dataframe or series trait type.""" - info_text = 'a pandas dataframe' + info_text = 'a pandas dataframe or series' + + klass = None def validate(self, obj, value): if value is None and not self.allow_none: self.error(obj, value) + if value is None or value is Undefined: + return super(PandasType, self).validate(obj, value) try: - value = pd.DataFrame(value) - for validator in self.validators: - value = validator(self, value) - return value + value = self.klass(value) except (ValueError, TypeError) as e: raise TraitError(e) + return super(PandasType, self).validate(obj, value) def set(self, obj, value): new_value = self._validate(obj, value) old_value = obj._trait_values.get(self.name, self.default_value) obj._trait_values[self.name] = new_value - if (old_value is None and new_value is not None) or not old_value.equals(new_value): + if ((old_value is None and new_value is not None) or + (old_value is Undefined and new_value is not Undefined) or + not old_value.equals(new_value)): obj._notify_trait(self.name, old_value, new_value) - def __init__(self, default_value=Undefined, allow_none=False, dtype=None, **kwargs): - self.dtype = dtype - if default_value is Undefined: - default_value = pd.DataFrame() - elif default_value is not None: - default_value = pd.DataFrame(default_value) - self.validators = [] - super(DataFrame, self).__init__(default_value=default_value, allow_none=allow_none, **kwargs) + def __init__(self, default_value=Empty, allow_none=False, klass=None, **kwargs): + if klass is None: + klass = self.klass + if (klass is not None) and inspect.isclass(klass): + self.klass = klass + else: + raise TraitError('The klass attribute must be a class' + ' not: %r' % klass) + if default_value is Empty: + default_value = klass() + elif default_value is not None and default_value is not Undefined: + default_value = klass(default_value) + super(PandasType, self).__init__(default_value=default_value, allow_none=allow_none, **kwargs) def make_dynamic_default(self): - if self.default_value is None: + if self.default_value is None or self.default_value is Undefined: return self.default_value else: return self.default_value.copy() -class Series(SciType): +class DataFrame(PandasType): + + """A pandas dataframe trait type.""" + + info_text = 'a pandas dataframe' + + def __init__(self, default_value=Empty, allow_none=False, dtype=None, **kwargs): + if 'klass' not in kwargs and self.klass is None: + import pandas as pd + kwargs['klass'] = pd.DataFrame + super(DataFrame, self).__init__( + default_value=default_value, allow_none=allow_none, dtype=dtype, **kwargs) + + +class Series(PandasType): """A pandas series trait type.""" info_text = 'a pandas series' + dtype = None + + def __init__(self, default_value=Empty, allow_none=False, dtype=None, **kwargs): + if 'klass' not in kwargs and self.klass is None: + import pandas as pd + kwargs['klass'] = pd.Series + super(Series, self).__init__( + default_value=default_value, allow_none=allow_none, dtype=dtype, **kwargs) + self.dtype = dtype + + +class XarrayType(SciType): + + """An xarray dataset or dataarray trait type.""" + + info_text = 'an xarray dataset or dataarray' + + klass = None def validate(self, obj, value): if value is None and not self.allow_none: self.error(obj, value) + if value is None or value is Undefined: + return super(XarrayType, self).validate(obj, value) try: - value = pd.Series(value) - for validator in self.validators: - value = validator(self, value) - return value + value = self.klass(value) except (ValueError, TypeError) as e: raise TraitError(e) + return super(XarrayType, self).validate(obj, value) def set(self, obj, value): new_value = self._validate(obj, value) old_value = obj._trait_values.get(self.name, self.default_value) obj._trait_values[self.name] = new_value - if (old_value is None and new_value is not None) or not old_value.equals(new_value): + if ((old_value is None and new_value is not None) or + (old_value is Undefined and new_value is not Undefined) or + not old_value.equals(new_value)): obj._notify_trait(self.name, old_value, new_value) - def __init__(self, default_value=Undefined, allow_none=False, dtype=None, **kwargs): - self.dtype = dtype - if default_value is Undefined: - default_value = pd.Series() - elif default_value is not None: - default_value = pd.Series(default_value) - self.validators = [] - super(Series, self).__init__(default_value=default_value, allow_none=allow_none, **kwargs) + def __init__(self, default_value=Empty, allow_none=False, klass=None, **kwargs): + if klass is None: + klass = self.klass + if (klass is not None) and inspect.isclass(klass): + self.klass = klass + else: + raise TraitError('The klass attribute must be a class' + ' not: %r' % klass) + if default_value is Empty: + default_value = klass() + elif default_value is not None and default_value is not Undefined: + default_value = klass(default_value) + super(XarrayType, self).__init__(default_value=default_value, allow_none=allow_none, **kwargs) def make_dynamic_default(self): - if self.default_value is None: + if self.default_value is None or self.default_value is Undefined: return self.default_value else: return self.default_value.copy() + + +class Dataset(XarrayType): + + """An xarray dataset trait type.""" + + info_text = 'an xarray dataset' + + def __init__(self, default_value=Empty, allow_none=False, dtype=None, **kwargs): + if 'klass' not in kwargs and self.klass is None: + import xarray as xr + kwargs['klass'] = xr.Dataset + super(Dataset, self).__init__( + default_value=default_value, allow_none=allow_none, dtype=dtype, **kwargs) + + +class DataArray(XarrayType): + + """An xarray dataarray trait type.""" + + info_text = 'an xarray dataarray' + dtype = None + + def __init__(self, default_value=Empty, allow_none=False, dtype=None, **kwargs): + if 'klass' not in kwargs and self.klass is None: + import xarray as xr + kwargs['klass'] = xr.DataArray + super(DataArray, self).__init__( + default_value=default_value, allow_none=allow_none, dtype=dtype, **kwargs) + self.dtype = dtype