From 490d39da8aee17b739f3112bced0cdd5edbcb758 Mon Sep 17 00:00:00 2001 From: Florian Einfalt Date: Mon, 6 Mar 2017 15:36:51 +0000 Subject: [PATCH] Initial commit --- .gitignore | 18 ++ LICENSE | 13 ++ MANIFEST.in | 11 + README.rst | 89 ++++++++ docs/Makefile | 225 ++++++++++++++++++ docs/make.bat | 281 +++++++++++++++++++++++ docs/source/api_documentation.rst | 8 + docs/source/conf.py | 363 ++++++++++++++++++++++++++++++ docs/source/getting_started.rst | 68 ++++++ docs/source/index.rst | 21 ++ docs/source/installation.rst | 14 ++ manage.py | 69 ++++++ nukedatastore/__init__.py | 275 ++++++++++++++++++++++ run_tests.py | 8 + setup.cfg | 10 + setup.py | 35 +++ tests/conftest.py | 14 ++ tests/test_nukedatastore.py | 41 ++++ 18 files changed, 1563 insertions(+) create mode 100644 .gitignore create mode 100644 LICENSE create mode 100644 MANIFEST.in create mode 100644 README.rst create mode 100644 docs/Makefile create mode 100644 docs/make.bat create mode 100644 docs/source/api_documentation.rst create mode 100644 docs/source/conf.py create mode 100644 docs/source/getting_started.rst create mode 100644 docs/source/index.rst create mode 100644 docs/source/installation.rst create mode 100644 manage.py create mode 100644 nukedatastore/__init__.py create mode 100644 run_tests.py create mode 100644 setup.cfg create mode 100644 setup.py create mode 100644 tests/conftest.py create mode 100644 tests/test_nukedatastore.py diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..0a0272d --- /dev/null +++ b/.gitignore @@ -0,0 +1,18 @@ +.tox/* +.idea/* +.cache/* +__pycache__/* +bin/* +docs/build/* +docs/_build/* +tests/assets/production/* +*.egg +*.egg-info +*.log +*.pyc +*.pyd +*.pyo +.DS_Store +.coverage +dist +build diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..31b5151 --- /dev/null +++ b/LICENSE @@ -0,0 +1,13 @@ +Copyright 2017 Florian Einfalt + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/MANIFEST.in b/MANIFEST.in new file mode 100644 index 0000000..301f83f --- /dev/null +++ b/MANIFEST.in @@ -0,0 +1,11 @@ +include .gitignore +include LICENSE +include README.rst +include run_tests.py + +graft tests +graft docs + +global-exclude *.py[cod] + +prune docs/build diff --git a/README.rst b/README.rst new file mode 100644 index 0000000..1ac0630 --- /dev/null +++ b/README.rst @@ -0,0 +1,89 @@ +nukedatastore +============= + +.. image:: https://img.shields.io/pypi/l/nukedatastore.svg + :target: https://pypi.python.org/pypi/nukedatastore +.. image:: https://img.shields.io/pypi/pyversions/nukedatastore.svg + :target: https://pypi.python.org/pypi/nukedatastore +.. image:: https://img.shields.io/pypi/v/nukedatastore.svg + :target: https://pypi.python.org/pypi/nukedatastore +.. image:: https://img.shields.io/pypi/wheel/nukedatastore.svg + :target: https://pypi.python.org/pypi/nukedatastore +.. image:: https://readthedocs.org/projects/nukedatastore/badge/?version=latest + :target: https://readthedocs.org/projects/nukedatastore/?badge=latest + +A library for basic data persistence in Nuke + +`Full Documentation`_ + +Installation +------------ + +To install ``nukedatastore``, type: + +.. code-block:: bash + + $ pip install nukedatastore + +Open Nuke's ``init.py`` file and add: + +.. code-block:: python + + nuke.pluginAddPath('/path/to/your/local/python/site-packages') + +Getting Started +--------------- + +To get started with ``nukedatastore``, type in the Nuke Script Editor: + +.. code-block:: python + + import nukedatastore + +To initialise a ``NukeDataStore``, type: + +.. code-block:: python + + ds = nukedatastore.NukeDataStore('data_store') + +To store data in the ``NukeDataStore``, type: + +.. code-block:: python + + ds['project_data'] = {'id': 1234, 'name': 'project name'} + +To list all available keys in the ``NukeDataStore``, type: + +.. code-block:: python + + ds.list() + # ['project_data'] + +To retrieve stored data from the ``NukeDataStore``, type: + +.. code-block:: python + + ds['project_data'] + # {'id': 1234, 'name': 'project name'} + +A ``NukeDataStore`` can be frozen, to freeze, type: + +.. code-block:: python + + ds.freeze() + +Any further attempt to set data on the ``NukeDataStore`` will result in +an error: + +.. code-block:: python + + ds['color_data'] = {'id': 'AB-123', 'name': 'White'} + # nukedatastore.NukeDataStoreError: Cannot mutate frozen NukeDataStore + +To un-freeze, type: + +.. code-block:: python + + ds.unfreeze() + +.. _Full Documentation: http://nukedatastore.readthedocs.io/en/latest/ diff --git a/docs/Makefile b/docs/Makefile new file mode 100644 index 0000000..ee68685 --- /dev/null +++ b/docs/Makefile @@ -0,0 +1,225 @@ +# Makefile for Sphinx documentation +# + +# You can set these variables from the command line. +SPHINXOPTS = +SPHINXBUILD = sphinx-build +PAPER = +BUILDDIR = build + +# 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 +help: + @echo "Please use \`make ' where 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 " epub3 to make an epub3" + @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)" + @echo " dummy to check syntax errors of document sources" + +.PHONY: clean +clean: + rm -rf $(BUILDDIR)/* + +.PHONY: html +html: + $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html + @echo + @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." + +.PHONY: dirhtml +dirhtml: + $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml + @echo + @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." + +.PHONY: singlehtml +singlehtml: + $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml + @echo + @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." + +.PHONY: pickle +pickle: + $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle + @echo + @echo "Build finished; now you can process the pickle files." + +.PHONY: json +json: + $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json + @echo + @echo "Build finished; now you can process the JSON files." + +.PHONY: htmlhelp +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." + +.PHONY: qthelp +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/nukecontexts.qhcp" + @echo "To view the help file:" + @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/nukecontexts.qhc" + +.PHONY: applehelp +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." + +.PHONY: devhelp +devhelp: + $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp + @echo + @echo "Build finished." + @echo "To view the help file:" + @echo "# mkdir -p $$HOME/.local/share/devhelp/nukecontexts" + @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/nukecontexts" + @echo "# devhelp" + +.PHONY: epub +epub: + $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub + @echo + @echo "Build finished. The epub file is in $(BUILDDIR)/epub." + +.PHONY: epub3 +epub3: + $(SPHINXBUILD) -b epub3 $(ALLSPHINXOPTS) $(BUILDDIR)/epub3 + @echo + @echo "Build finished. The epub3 file is in $(BUILDDIR)/epub3." + +.PHONY: latex +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)." + +.PHONY: latexpdf +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." + +.PHONY: latexpdfja +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." + +.PHONY: text +text: + $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text + @echo + @echo "Build finished. The text files are in $(BUILDDIR)/text." + +.PHONY: man +man: + $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man + @echo + @echo "Build finished. The manual pages are in $(BUILDDIR)/man." + +.PHONY: texinfo +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)." + +.PHONY: info +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." + +.PHONY: gettext +gettext: + $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale + @echo + @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." + +.PHONY: changes +changes: + $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes + @echo + @echo "The overview file is in $(BUILDDIR)/changes." + +.PHONY: linkcheck +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." + +.PHONY: doctest +doctest: + $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest + @echo "Testing of doctests in the sources finished, look at the " \ + "results in $(BUILDDIR)/doctest/output.txt." + +.PHONY: coverage +coverage: + $(SPHINXBUILD) -b coverage $(ALLSPHINXOPTS) $(BUILDDIR)/coverage + @echo "Testing of coverage in the sources finished, look at the " \ + "results in $(BUILDDIR)/coverage/python.txt." + +.PHONY: xml +xml: + $(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml + @echo + @echo "Build finished. The XML files are in $(BUILDDIR)/xml." + +.PHONY: pseudoxml +pseudoxml: + $(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml + @echo + @echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml." + +.PHONY: dummy +dummy: + $(SPHINXBUILD) -b dummy $(ALLSPHINXOPTS) $(BUILDDIR)/dummy + @echo + @echo "Build finished. Dummy builder generates no files." diff --git a/docs/make.bat b/docs/make.bat new file mode 100644 index 0000000..3d24681 --- /dev/null +++ b/docs/make.bat @@ -0,0 +1,281 @@ +@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 ^` where ^ 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. epub3 to make an epub3 + 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 + echo. dummy to check syntax errors of document sources + 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% 1>NUL 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\nukecontexts.qhcp + echo.To view the help file: + echo.^> assistant -collectionFile %BUILDDIR%\qthelp\nukecontexts.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" == "epub3" ( + %SPHINXBUILD% -b epub3 %ALLSPHINXOPTS% %BUILDDIR%/epub3 + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The epub3 file is in %BUILDDIR%/epub3. + 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 +) + +if "%1" == "dummy" ( + %SPHINXBUILD% -b dummy %ALLSPHINXOPTS% %BUILDDIR%/dummy + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. Dummy builder generates no files. + goto end +) + +:end diff --git a/docs/source/api_documentation.rst b/docs/source/api_documentation.rst new file mode 100644 index 0000000..41eeba6 --- /dev/null +++ b/docs/source/api_documentation.rst @@ -0,0 +1,8 @@ +API Documentation +================= + +.. autoclass:: nukedatastore.NukeDataStoreError + :members: + +.. autoclass:: nukedatastore.NukeDataStore + :members: diff --git a/docs/source/conf.py b/docs/source/conf.py new file mode 100644 index 0000000..e767979 --- /dev/null +++ b/docs/source/conf.py @@ -0,0 +1,363 @@ +# -*- coding: utf-8 -*- +# +# nukedatastore documentation build configuration file, created by +# sphinx-quickstart on Thu Feb 9 15:53:41 2017. +# +# This file is execfile()d with the current directory set to its +# containing dir. +# +# Note that not all possible configuration values are present in this +# autogenerated file. +# +# All configuration values have a default; values that are commented out +# serve to show the default. + +# If extensions (or modules to document with autodoc) are in another directory, +# add these directories to sys.path here. If the directory is relative to the +# documentation root, use os.path.abspath to make it absolute, like shown here. +# +# import os +# import sys +# sys.path.insert(0, os.path.abspath('.')) + +import os +import sys +import sphinx_rtd_theme +os.environ['NON_PRODUCTION_CONTEXT'] = '1' + +cwd = os.getcwd() +project_root = os.path.dirname(cwd) +sys.path.insert(0, project_root) +import nukedatastore + +# -- 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.doctest', + 'sphinx.ext.intersphinx', + 'sphinx.ext.viewcode', +] + +# Add any paths that contain templates here, relative to this directory. +templates_path = ['_templates'] + +# The suffix(es) of source filenames. +# You can specify multiple suffix as a list of string: +# +# source_suffix = ['.rst', '.md'] +source_suffix = '.rst' + +# The encoding of source files. +# +# source_encoding = 'utf-8-sig' + +# The master toctree document. +master_doc = 'index' + +# General information about the project. +project = u'nukedatastore' +copyright = u"2017, Florian Einfalt" +author = u'Florian Einfalt' + +# 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 short X.Y version. +version = nukedatastore.__version__ +# The full version, including alpha/beta/rc tags. +release = nukedatastore.__version__ + +# The language for content autogenerated by Sphinx. Refer to documentation +# for a list of supported languages. +# +# This is also used if you do content translation via gettext catalogs. +# Usually you set "language" from the command line for these cases. +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. +# This patterns also effect to html_static_path and html_extra_path +exclude_patterns = ['_build'] + +# 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 + +# If true, `todo` and `todoList` produce output, else they produce nothing. +todo_include_todos = 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' +html_theme = 'sphinx_rtd_theme' + +# 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 = [] +html_theme_path = [sphinx_rtd_theme.get_html_theme_path()] + +# The name for this set of Sphinx documents. +# " v documentation" by default. +# +# 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 (relative to this directory) to use as a 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 None, a 'Last updated on:' timestamp is inserted at every page +# bottom, using the given strftime format. +# The empty string is equivalent to '%b %d, %Y'. +# +# html_last_updated_fmt = None + +# 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 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 + +# Language to be used for generating the HTML full-text search index. +# Sphinx supports the following languages: +# 'da', 'de', 'en', 'es', 'fi', 'fr', 'hu', 'it', 'ja' +# 'nl', 'no', 'pt', 'ro', 'ru', 'sv', 'tr', 'zh' +# +# html_search_language = 'en' + +# A dictionary with options for the search language support, empty by default. +# 'ja' uses this config value. +# 'zh' user can custom change `jieba` dictionary path. +# +# html_search_options = {'type': 'default'} + +# The name of a javascript file (relative to the configuration directory) that +# implements a search results scorer. If empty, the default will be used. +# +# html_search_scorer = 'scorer.js' + +# Output file base name for HTML help builder. +htmlhelp_basename = 'nukedatastoredoc' + +# -- 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': '', + + # Latex figure (float) alignment + # + # 'figure_align': 'htbp', +} + +# 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', 'nukedatastore.tex', u'nukedatastore Documentation', + u'Florian Einfalt', '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 = [] + +# It false, will not define \strong, \code, itleref, \crossref ... but only +# \sphinxstrong, ..., \sphinxtitleref, ... To help avoid clash with user added +# packages. +# +# latex_keep_old_macro_names = True + +# 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', 'nukedatastore', + u'nukedatastore Documentation', + [u'Florian Einfalt'], 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', 'nukedatastore', + u'nukedatastore Documentation', + u'Florian Einfalt', + 'nukedatastore', + '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 + + +# Example configuration for intersphinx: refer to the Python standard library. +intersphinx_mapping = {'https://docs.python.org/': None} diff --git a/docs/source/getting_started.rst b/docs/source/getting_started.rst new file mode 100644 index 0000000..e08ca4e --- /dev/null +++ b/docs/source/getting_started.rst @@ -0,0 +1,68 @@ +Getting Started +=============== + +To get started with ``nukedatastore``, type in the Nuke Script Editor: + +.. code-block:: python + + import nukedatastore + +To initialise a ``NukeDataStore``, type: + +.. code-block:: python + + ds = nukedatastore.NukeDataStore('data_store') + +.. note:: + + ``nukedatastore`` will try to find an existing data store with the same + name first, if that does not succeed, a new data store is created. + +To store data in the ``NukeDataStore``, type: + +.. code-block:: python + + ds['project_data'] = {'id': 1234, 'name': 'project name'} + +.. note:: + + If the key (i.e. ``project_data``) does not exists, then ``nukedatastore`` + will automatically create it. + +.. warning:: + + All data stored in ``NukeDataStore`` must be JSON serialisable. + +To list all available keys in the ``NukeDataStore``, type: + +.. code-block:: python + + ds.list() + # ['project_data'] + +To retrieve stored data from the ``NukeDataStore``, type: + +.. code-block:: python + + ds['project_data'] + # {'id': 1234, 'name': 'project name'} + +A ``NukeDataStore`` can be frozen, to freeze, type: + +.. code-block:: python + + ds.freeze() + +Any further attempt to set data on the ``NukeDataStore`` will result in +an error: + +.. code-block:: python + + ds['color_data'] = {'id': 'AB-123', 'name': 'White'} + # nukedatastore.NukeDataStoreError: Cannot mutate frozen NukeDataStore + +To un-freeze, type: + +.. code-block:: python + + ds.unfreeze() diff --git a/docs/source/index.rst b/docs/source/index.rst new file mode 100644 index 0000000..e0da454 --- /dev/null +++ b/docs/source/index.rst @@ -0,0 +1,21 @@ +Welcome to nukedatastore documentation! +======================================================= + +Contents: + +.. toctree:: + :maxdepth: 2 + + installation + getting_started + api_documentation + + + +Indices and tables +================== + +* :ref:`genindex` +* :ref:`modindex` +* :ref:`search` + diff --git a/docs/source/installation.rst b/docs/source/installation.rst new file mode 100644 index 0000000..8a8bb7a --- /dev/null +++ b/docs/source/installation.rst @@ -0,0 +1,14 @@ +Installation +============ + +To install ``nukedatastore``, type: + +.. code-block:: bash + + $ pip install nukedatastore + +Open Nuke's ``init.py`` file and add: + +.. code-block:: python + + nuke.pluginAddPath('/path/to/your/local/python/site-packages') diff --git a/manage.py b/manage.py new file mode 100644 index 0000000..8e2ab7e --- /dev/null +++ b/manage.py @@ -0,0 +1,69 @@ +import os +import sys +import click +import twine +import subprocess + + +project_root = os.path.dirname(os.path.abspath(__file__)) +NUKE_LOCATION = '/Applications/Nuke10.0v5/Nuke10.0v5.app/Contents/MacOS' + + +def run_tests(): + os.chdir(project_root) + test_env = os.environ.copy() + env = { + 'PYTHONDONTWRITEBYTECODE': '1', + 'COVERAGE_FILE': '{0}/.coverage'.format(project_root), + 'NUKE_INTERACTIVE': '1', + 'PATH': '{0}:{1}'.format(NUKE_LOCATION, test_env['PATH']), + 'PYTHONPATH': + '/Users/florian/bin/build/lib/python2.7/site-packages:' + '/Users/florian/_/_development/git/projects/nukeuuid:{0}'.format( + project_root) + } + for env_var, env_val in env.iteritems(): + test_env[env_var] = env_val + subprocess.Popen(['python', project_root+'/run_tests.py'], + env=test_env).wait() + + +def run_docs(): + os.chdir(project_root + '/docs') + docs_env = os.environ.copy() + env = { + 'PYTHONDONTWRITEBYTECODE': '1', + 'NON_PRODUCTION_CONTEXT': '1', + 'PYTHONPATH': + '/Users/florian/bin/build/lib/python2.7/site-packages:' + '/Users/florian/_/_development/git/projects/nukeuuid:{0}'.format( + project_root) + } + for env_var, env_val in env.iteritems(): + docs_env[env_var] = env_val + subprocess.Popen(['make', 'html'], env=docs_env).wait() + + +def run_deploy(): + os.chdir(project_root) + subprocess.Popen(['python', 'setup.py', 'sdist', 'bdist_wheel']).wait() + subprocess.Popen(['twine', 'upload', 'dist/*']).wait() + + +@click.command() +@click.option('--tests', is_flag=True) +@click.option('--docs', is_flag=True) +@click.option('--deploy', is_flag=True) +def cli(tests, docs, deploy): + if tests: + run_tests() + if docs: + run_docs() + if deploy: + run_tests() + run_docs() + run_deploy() + + +if __name__ == '__main__': + cli() diff --git a/nukedatastore/__init__.py b/nukedatastore/__init__.py new file mode 100644 index 0000000..c3ca102 --- /dev/null +++ b/nukedatastore/__init__.py @@ -0,0 +1,275 @@ +import os +import re +import sys +import json +import platform + +from nukeuuid import get_nodes, set_uuid, NukeUUIDError + + +def import_nuke(): + try: + import nuke + return nuke + except ImportError as e: + try: + os.environ['NON_PRODUCTION_CONTEXT'] + except KeyError: + raise e + + +try: + os.environ['NON_PRODUCTION_CONTEXT'] +except: + if platform.system() == 'Darwin': + application = r'Nuke\d+\.\d+v\d+.app' + elif platform.system() == 'Windows': + application = r'Nuke\d+\.\d+.exe' + else: + raise RuntimeError('OS {0} is not supported'.format(platform.system())) + match = re.search(application, sys.executable) + if not match: + raise RuntimeError('Import nukedatastore from within Nuke') + nuke = import_nuke() + +__version__ = '0.1.0' +__all__ = [] + +DS_PREFIX = 'ds_' +FROZEN_ATTR = 'nds_frozen' + + +class NukeDataStoreError(ValueError): + """ + Exception indicating an error related to the Nuke Data Store, + inherits from :class:`ValueError`. + """ + def __init__(self, message): + super(NukeDataStoreError, self).__init__(message) + + +class NukeDataStore(object): + """ + NukeDataStore class, wrapper around Nuke's NoOp node. + + :param name: Data store name + :type name: str + + Usage: + + >>> from nukedatastore import NukeDataStore + >>> ds = NukeDataStore('data_store') + >>> ds['project_data'] = {'id': 1234, 'name': 'project name'} + >>> print ds['project_data'] + >>> {'id': 1234, 'name': 'project name'} + """ + def __init__(self, name): + self.store = self._init(name) + + def __getitem__(self, key): + try: + return self._get_item(key) + except KeyError as e: + raise KeyError(e) + + def __setitem__(self, key, value): + if self.is_frozen(): + raise NukeDataStoreError('Cannot mutate frozen NukeDataStore') + self._set_item(key, value) + + @property + def store(self): + """ + Return the data store's Nuke node + + :return: Data store node + :rtype: :class:`~nuke.Node` + """ + try: + assert self._store + except (AssertionError, ValueError): + raise NukeDataStoreError('Data store node missing') + return self._store + + @store.setter + def store(self, node): + """ + Given a ``node``, set the ``store`` property. Raise + :class:`~nukedatastore.NukeDataStoreError` if ``node`` has an + incorrect type. + + :param node: Nuke node + :type node: :class:`~nuke.Node` + """ + if not isinstance(node, nuke.Node): + raise NukeDataStoreError('Data store must be a Nuke node') + self._store = node + + def _init(self, name): + """ + Given a ``name``, initialise a :class:`~nukedatastore.NukeDataStore` + with the same ``name``. Find existing + :class:`~nukedatastore.NukeDataStore` nodes or create a new node with + the same ``name``. + + :param node: Node name + :type node: str + :return: Data store node + :rtype: :class:`~nuke.Node` + """ + kw = {'': '356455a5-3e58-47b7-8d37-3bb37610187b'} + attrs = { + 'label': 'NukeDataStore', + 'hide_input': True, + 'tile_color': 4278190335, + FROZEN_ATTR: self._to_json(False) + } + store = None + try: + nodes = get_nodes(**kw) + for node in nodes: + if node.name() == name: + store = node + assert store + except (AssertionError, NukeUUIDError): + store = nuke.nodes.NoOp(name=name) + set_uuid(store, **kw) + store.addKnob(self._create_knob(FROZEN_ATTR)) + for attr, value in attrs.iteritems(): + store[attr].setValue(value) + return store + + def _create_knob(self, attr): + """ + Given an ``attr``, create and return a new :class:`~nuke.Text_Knob` of + the same name. + + :param attr: Attribute name + :type attr: str + :return: Nuke text knob + :rtype: :class:`~nuke.Text_Knob` + """ + knob = nuke.Text_Knob(attr, attr) + knob.setEnabled(False) + knob.setVisible(False) + return knob + + def _get_ds_attr(self, key): + """ + Given a ``key``, prefix with the data store prefix and return. + + :param key: Data store key + :type key: str + :return: Prefixed data store key + :rtype: str + """ + return '{ds_prefix}{key}'.format(ds_prefix=DS_PREFIX, key=key) + + def _strip_ds_attr(self, key): + """ + Given a ``key``, remove the data store prefix and return. + + :param key: Prefixed data store key + :type key: str + :return: Data store key + :rtype: str + """ + return key[len(DS_PREFIX):] + + def _to_json(self, value): + """ + Given a ``value``, encode to JSON and return. + + :param value: Decoded value + :type value: str + :return: JSON-encoded value + :rtype: str + """ + return json.dumps(value) + + def _from_json(self, value): + """ + Given a ``value``, decode from JSON and return. + + :param value: JSON-encoded value + :type value: str + :return: Decoded value + :rtype: str + """ + return json.loads(value) + + def _get_item(self, key, ds_attr=True): + """ + Given a ``key`` get data attribute ``key``. Raise :class:`KeyError`, if + key does not exist. + + :param key: Data store key + :type key: str + :param ds_attr: Prefix ``key`` with DS_PREFIX + :type ds_attr: bool + """ + try: + if ds_attr: + return self._from_json( + self.store[self._get_ds_attr(key)].value()) + else: + return self._from_json(self.store[key].value()) + except NameError: + raise KeyError(key) + + def _set_item(self, key, value, ds_attr=True): + """ + Given a ``key``, ``value`` pair, set ``value`` on attribute ``key``. + Raise :class:`~nukedatastore.NukeDataStoreError` is data is not JSON + serialisable. + + :param key: Data store key + :type key: str + :param value: Data + :type value: str, int, float, bool, list, dict + :param ds_attr: Prefix ``key`` with DS_PREFIX + :type ds_attr: bool + """ + if ds_attr: + key = self._get_ds_attr(key) + try: + serialised_data = self._to_json(value) + except TypeError: + raise NukeDataStoreError('Data not serialisable') + try: + self.store[key].setValue(serialised_data) + except NameError: + self.store.addKnob(self._create_knob(key)) + self.store[key].setValue(serialised_data) + + def list(self): + """ + List all available keys in the :class:`~nukedatastore.NukeDataStore`. + """ + return [self._strip_ds_attr(key) for key in self.store.knobs() + if key.startswith(DS_PREFIX)] + + def is_frozen(self): + """ + Return whether the data in the :class:`~nukedatastore.NukeDataStore` + is frozen and therefore unchangeable. + """ + return self._get_item(FROZEN_ATTR, ds_attr=False) + + def freeze(self): + """ + Freeze the data in the :class:`~nukedatastore.NukeDataStore` and make + it unchangeable. + """ + self._set_item(FROZEN_ATTR, True, ds_attr=False) + + def unfreeze(self): + """ + Unfreeze the data in the :class:`~nukedatastore.NukeDataStore` and + make it changeable. + """ + self._set_item(FROZEN_ATTR, False, ds_attr=False) + + def __repr__(self): + return ''.format(self.store.name(), + len(self.list())) diff --git a/run_tests.py b/run_tests.py new file mode 100644 index 0000000..8dfb50c --- /dev/null +++ b/run_tests.py @@ -0,0 +1,8 @@ +import os +import pytest + +dir_ = os.path.dirname(__file__) +pytest.main(['{0}/tests/'.format(dir_), + '--cov=nukedatastore', + '--cov-report', + 'term-missing']) diff --git a/setup.cfg b/setup.cfg new file mode 100644 index 0000000..4eef995 --- /dev/null +++ b/setup.cfg @@ -0,0 +1,10 @@ +[bdist_wheel] +universal = 0 + +[egg_info] +tag_build = +tag_date = 0 +tag_svn_revision = 0 + +[metadata] +license_file = LICENSE diff --git a/setup.py b/setup.py new file mode 100644 index 0000000..67e0e83 --- /dev/null +++ b/setup.py @@ -0,0 +1,35 @@ +from setuptools import setup, find_packages + +with open('README.rst', 'r') as f: + readme = f.read() + +requirements = ['nukeuuid'] +test_requirements = ['pytest', 'pytest-cov', + 'sphinx', 'sphinx_rtd_theme'] + +setup( + name = 'nukedatastore', + version = '0.1.0', + description='A library for basic data persistance in Nuke', + long_description=readme, + url='https://github.com/florianeinfalt/nukedatastore', + author='Florian Einfalt', + author_email='info@florianeinfalt.de', + license='Apache 2.0', + packages=find_packages(), + include_package_data=True, + zip_safe=False, + classifiers=[ + 'Development Status :: 3 - Alpha', + 'Intended Audience :: Developers', + 'Natural Language :: English', + 'Topic :: Software Development :: Build Tools', + 'License :: OSI Approved :: Apache Software License', + 'Programming Language :: Python', + 'Programming Language :: Python :: 2.6', + 'Programming Language :: Python :: 2.7', + 'Programming Language :: Python :: Implementation :: CPython', + ], + install_requires=requirements, + tests_require=test_requirements +) diff --git a/tests/conftest.py b/tests/conftest.py new file mode 100644 index 0000000..77a060d --- /dev/null +++ b/tests/conftest.py @@ -0,0 +1,14 @@ +# nukedatastore py.test configuration +import pytest +from nukedatastore import NukeDataStore + + +@pytest.fixture(scope='session') +def datastore(): + return NukeDataStore('data_store') + + +@pytest.fixture(scope='session') +def nuke(): + import nuke + return nuke diff --git a/tests/test_nukedatastore.py b/tests/test_nukedatastore.py new file mode 100644 index 0000000..d88bf27 --- /dev/null +++ b/tests/test_nukedatastore.py @@ -0,0 +1,41 @@ +# nukedatastore tests +import pytest +import datetime + +from nukedatastore import NukeDataStore, NukeDataStoreError + + +def test_datastore_crud(datastore): + datastore['project_data'] = {'id': 1234, 'name': 'project name'} + assert len(datastore.list()) == 1 + assert datastore.list()[0] == 'project_data' + assert datastore['project_data'] == {'id': 1234, 'name': 'project name'} + + +def test_datastore_crud_invalid_key(datastore): + with pytest.raises(KeyError): + datastore['invalid_key'] + + +def test_datastore_crud_invalid_data(datastore): + with pytest.raises(NukeDataStoreError): + datastore['data'] = datetime.datetime.now() + + +def test_datastore_crud_frozen(datastore): + datastore.freeze() + with pytest.raises(NukeDataStoreError): + datastore['project_data'] = {} + datastore.unfreeze() + + +def test_deleted_node(datastore, nuke): + nuke.delete(nuke.toNode('data_store')) + with pytest.raises(NukeDataStoreError): + datastore.store + + +def test_existing_node_init(nuke): + NukeDataStore('data_store') + x = NukeDataStore('data_store') + assert x