pax_global_header00006660000000000000000000000064145373361570014530gustar00rootroot0000000000000052 comment=a88523810ed257eb63bf782db15c217272e6dccd datatemplates-0.11.0/000077500000000000000000000000001453733615700144375ustar00rootroot00000000000000datatemplates-0.11.0/.github/000077500000000000000000000000001453733615700157775ustar00rootroot00000000000000datatemplates-0.11.0/.github/workflows/000077500000000000000000000000001453733615700200345ustar00rootroot00000000000000datatemplates-0.11.0/.github/workflows/check.yml000066400000000000000000000010671453733615700216400ustar00rootroot00000000000000name: Check on: - push - pull_request jobs: build: runs-on: ubuntu-latest if: ${{ !startsWith(github.ref, 'refs/tags') }} strategy: fail-fast: false matrix: tox-environment: - docs - linter - pkglint steps: - uses: actions/checkout@v2 with: fetch-depth: 0 - name: Set up Python uses: actions/setup-python@v4 - name: Install dependencies run: python -m pip install tox - name: Run run: tox -e ${{ matrix.tox-environment }} datatemplates-0.11.0/.github/workflows/python-publish.yaml000066400000000000000000000023501453733615700237050ustar00rootroot00000000000000# This workflows will upload a Python Package using Twine when a release is created # For more information see: https://help.github.com/en/actions/language-and-framework-guides/using-python-with-github-actions#publishing-to-package-registries name: Upload Python Package on: - push jobs: build-n-publish: name: Build and publish Python distributions to PyPI and TestPyPI if: ${{ github.repository_owner == 'sphinx-contrib' }} runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 with: fetch-depth: 0 - name: Set up Python uses: actions/setup-python@v4 with: python-version: '3.x' - name: Install dependencies run: | python -m pip install --upgrade pip pip install .[build] - name: Build sdist and wheel run: | python -m build # - name: Publish distribution to Test PyPI # uses: pypa/gh-action-pypi-publish@master # with: # password: ${{ secrets.test_pypi_password }} # repository_url: https://test.pypi.org/legacy/ - name: Publish distribution to PyPI if: startsWith(github.ref, 'refs/tags') uses: pypa/gh-action-pypi-publish@master with: password: ${{ secrets.pypi_password }} datatemplates-0.11.0/.github/workflows/test.yml000066400000000000000000000012431453733615700215360ustar00rootroot00000000000000name: Test on: - push - pull_request jobs: build: runs-on: ubuntu-latest if: ${{ !startsWith(github.ref, 'refs/tags') }} strategy: fail-fast: false matrix: python-version: - 3.8 - 3.9 - "3.10" - "3.11" - "3.12" steps: - uses: actions/checkout@v2 with: fetch-depth: 0 - name: Set up Python ${{ matrix.python-version }} uses: actions/setup-python@v4 with: python-version: ${{ matrix.python-version }} - name: Install dependencies run: python -m pip install tox - name: Run tests run: tox -e py datatemplates-0.11.0/.gitignore000066400000000000000000000003111453733615700164220ustar00rootroot00000000000000/.testrepository/ /.tox/ /AUTHORS /ChangeLog /*.egg-info/ /*.eggs/ /build/ /doc/build/ /.coverage /dist /venv/ /.vscode/ __pycache__ # Generated by setuptools_scm sphinxcontrib/datatemplates/version.pydatatemplates-0.11.0/.mergify.yml000066400000000000000000000017521453733615700167070ustar00rootroot00000000000000pull_request_rules: - name: Add CI label conditions: - or: - "title~=^tox:" - "title~=^ci:" - "files~=tox.ini" actions: label: add: - ci - name: Add Mergify label conditions: - or: - "title~=^mergify:" - "files~=.mergify.yml$" actions: label: add: - mergify - name: Automatic merge on approval conditions: - and: - "check-success=build (docs)" - "check-success=build (linter)" - "check-success=build (pkglint)" - "check-success=build (3.8)" - "check-success=build (3.9)" - "check-success=build (3.10)" - "check-success=build (3.11)" - "check-success=build (3.12)" - "-draft" - or: - "approved-reviews-by=dhellmann" - "author=dhellmann" - "approved-reviews-by=janbrohl" - "author=janbrohl" actions: merge: method: merge datatemplates-0.11.0/.readthedocs.yaml000066400000000000000000000002601453733615700176640ustar00rootroot00000000000000version: 2 build: os: "ubuntu-20.04" tools: python: "3.11" python: # Install our python package before building the docs install: - method: pip path: . datatemplates-0.11.0/LICENSE000066400000000000000000000027271453733615700154540ustar00rootroot00000000000000Copyright (c) 2015, Doug Hellmann All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of the nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL DOUG HELLMANN BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. datatemplates-0.11.0/README.rst000066400000000000000000000033341453733615700161310ustar00rootroot00000000000000.. -*- mode: rst -*- ============================= sphinxcontrib-datatemplates ============================= This package contains sphinxcontrb.datatemplates, an extension for Sphinx to render parts of reStructuredText pages from data files in formats like JSON, YAML, and CSV. * Repo: https://github.com/sphinxcontrib/sphinxcontrib.datatemplates * Docs: http://sphinxcontribdatatemplates.readthedocs.io/ Sample YAML Input ================= :: --- key1: value1 key2: - list item 1 - list item 2 - list item 3 nested-list: - ['a', 'b', 'c'] - ['A', 'B', 'C'] mapping-series: - cola: a colb: b colc: c - cola: A colb: B colc: C Sample Template =============== :: .. -*- mode: rst -*- Individual Item ~~~~~~~~~~~~~~~ {{ data['key1'] }} List of Items ~~~~~~~~~~~~~ {% for item in data['key2'] %} - {{item}} {% endfor %} Nested List Table ~~~~~~~~~~~~~~~~~ Rendering a table from a list of nested sequences using hard-coded headers. {{ make_list_table( ['One', 'Two', 'Three'], data['nested-list'], title='Table from nested lists', ) }} Mapping Series Table ~~~~~~~~~~~~~~~~~~~~ Rendering a table from a list of nested dictionaries using dynamic headers. {{ make_list_table_from_mappings( [('One', 'cola'), ('Two', 'colb'), ('Three', 'colc')], data['mapping-series'], title='Table from series of mappings', ) }} Rendered Output =============== See the `sphinx output `_ online. datatemplates-0.11.0/doc/000077500000000000000000000000001453733615700152045ustar00rootroot00000000000000datatemplates-0.11.0/doc/Makefile000066400000000000000000000165121453733615700166510ustar00rootroot00000000000000# 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 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 " 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/sphinxcontribdatatemplates.qhcp" @echo "To view the help file:" @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/sphinxcontribdatatemplates.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/sphinxcontribdatatemplates" @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/sphinxcontribdatatemplates" @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." datatemplates-0.11.0/doc/source/000077500000000000000000000000001453733615700165045ustar00rootroot00000000000000datatemplates-0.11.0/doc/source/_static/000077500000000000000000000000001453733615700201325ustar00rootroot00000000000000datatemplates-0.11.0/doc/source/_static/.placeholder000066400000000000000000000000001453733615700224030ustar00rootroot00000000000000datatemplates-0.11.0/doc/source/_templates/000077500000000000000000000000001453733615700206415ustar00rootroot00000000000000datatemplates-0.11.0/doc/source/_templates/csv-sample.tmpl000066400000000000000000000007641453733615700236200ustar00rootroot00000000000000.. -*- mode: rst -*- Static Heading -------------- Individual Cell in Row ~~~~~~~~~~~~~~~~~~~~~~ {{ data[0].a }} List of Cells in Row ~~~~~~~~~~~~~~~~~~~~ {% for item in data[0].items() %} - {{item[0]}}: {{item[1]}} {% endfor %} Mapping Series Table ~~~~~~~~~~~~~~~~~~~~ Rendering a table from a list of nested dictionaries using dynamic headers. {{ make_list_table_from_mappings( [('One', 'a'), ('Two', 'b'), ('Three', 'c')], data, title='Table from series of mappings', ) }}datatemplates-0.11.0/doc/source/_templates/dbm-sample.tmpl000066400000000000000000000004231453733615700235570ustar00rootroot00000000000000.. -*- mode: rst -*- Static Heading -------------- Individual Item ~~~~~~~~~~~~~~~ - With decoding {{ data['Hi'].decode('ascii') }} - Without decoding {{ data['Hi'] }} List of Items ~~~~~~~~~~~~~ {% for item in data.items() %} - {{item[0]}} -> {{item[1]}} {% endfor %} datatemplates-0.11.0/doc/source/_templates/import-module-sample.tmpl000066400000000000000000000004431453733615700256140ustar00rootroot00000000000000.. -*- mode: rst -*- Static Heading -------------- List of Directory Entries ~~~~~~~~~~~~~~~~~~~~~~~~~~ {% for item in data.scandir() %} - {{item.name}}'s size is {{item.stat().st_size}} Bytes {% endfor %} File Path of the Null Device ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ``{{data.devnull}}`` datatemplates-0.11.0/doc/source/_templates/inventory.tmpl000066400000000000000000000006251453733615700235770ustar00rootroot00000000000000.. -*- mode: rst -*- {# The details about parts in inventory are kept in a separate data file from the stock quantity. #} {% set parts = load('part-details.yaml') %} .. list-table:: What's in stock :header-rows: 1 * - part-num - quantity - description {% for item in data | sort %} * - {{ item[0] }} - {{ item[1] }} - {{ parts[item[0]].description }} {% endfor %} datatemplates-0.11.0/doc/source/_templates/sample-multiple.tmpl000066400000000000000000000007501453733615700246530ustar00rootroot00000000000000.. -*- mode: rst -*- Static Heading -------------- Individual Item ~~~~~~~~~~~~~~~ {{ data[0]|tojson }} List of Items ~~~~~~~~~~~~~ {% for item in data %} - {{item|tojson}} - {{item.key}} - {{item.key1}} {% endfor %} Mapping Series Table ~~~~~~~~~~~~~~~~~~~~ Rendering a table from a list of nested dictionaries using dynamic headers. {{ make_list_table_from_mappings( [('Key', 'key'), ('Key One', 'key1')], data, title='Table from series of mappings', ) }} datatemplates-0.11.0/doc/source/_templates/sample.tmpl000066400000000000000000000013171453733615700230220ustar00rootroot00000000000000.. -*- mode: rst -*- Static Heading -------------- Individual Item ~~~~~~~~~~~~~~~ {{ data['key1'] }} List of Items ~~~~~~~~~~~~~ {% for item in data['key2'] %} - {{item}} {% endfor %} Nested List Table ~~~~~~~~~~~~~~~~~ Rendering a table from a list of nested sequences using hard-coded headers. {{ make_list_table( ['One', 'Two', 'Three'], data['nested-list'], title='Table from nested lists', ) }} Mapping Series Table ~~~~~~~~~~~~~~~~~~~~ Rendering a table from a list of nested dictionaries using dynamic headers. {{ make_list_table_from_mappings( [('One', 'cola'), ('Two', 'colb'), ('Three', 'colc')], data['mapping-series'], title='Table from series of mappings', ) }} datatemplates-0.11.0/doc/source/_templates/xml-sample.tmpl000066400000000000000000000006521453733615700236210ustar00rootroot00000000000000.. -*- mode: rst -*- Static Heading -------------- Individual Item ~~~~~~~~~~~~~~~ {{ data.find('key1').text }} List of Items ~~~~~~~~~~~~~ {% for item in data.find('key2') %} - {{item.text}} {% endfor %} XPath for Items ~~~~~~~~~~~~~~~ See `XPath support `_ {% for item in data.findall(".//*[@special='yes']") %} - {{item.text}} {% endfor %}datatemplates-0.11.0/doc/source/cli.rst000066400000000000000000000021301453733615700200010ustar00rootroot00000000000000============== CLI Samples ============== Help ==== .. runcmd:: datatemplate --help Data File ========= .. include:: sample-multiple.yaml :literal: Template File ============= .. include:: _templates/sample-multiple.tmpl :literal: Rendering a Template ==================== .. code-block:: console $ datatemplate render -o multiple-documents \ doc/source/_templates/sample-multiple.tmpl \ doc/source/sample-multiple.yaml .. runcmd:: datatemplate render -o multiple-documents doc/source/_templates/sample-multiple.tmpl doc/source/sample-multiple.yaml Experimenting by Dumping Data ============================= CSV Data With Headers --------------------- .. code-block:: console $ datatemplate dump -o dialect:excel-tab \ -o headers \ doc/source/sample.csv .. runcmd:: datatemplate dump -o dialect:excel-tab -o headers doc/source/sample.csv CSV Data Without Headers ------------------------ .. code-block:: console $ datatemplate dump -o dialect:excel-tab \ doc/source/sample.csv .. runcmd:: datatemplate dump -o dialect:excel-tab doc/source/sample.csv datatemplates-0.11.0/doc/source/conf.py000066400000000000000000000232631453733615700200110ustar00rootroot00000000000000# -*- coding: utf-8 -*- # # sphinxcontrib.datatemplates documentation build configuration file, # created by sphinx-quickstart on Sun Sep 13 18:57:25 2015. # # 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. import pkg_resources # 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. # sys.path.insert(0, os.path.abspath('.')) # -- 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.intersphinx', 'sphinx.ext.autodoc', 'sphinxcontrib.datatemplates', "sphinxcontrib.runcmd", ] # Support linking to Python Docs intersphinx_mapping = { 'python': ('https://docs.python.org/', None), 'python3': ('https://docs.python.org/3', None), 'python2': ('https://docs.python.org/2', None) } # 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'sphinxcontrib.datatemplates' copyright = u'2015, Doug Hellmann' author = u'Doug Hellmann' # 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 = pkg_resources.get_distribution('sphinxcontrib.datatemplates').version # The full version, including alpha/beta/rc tags. release = '0.0.0' html_context = { 'sample': 'Sample context value set in conf.py', } # 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 = 'en' # 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 # 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' # 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 # " v 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 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' # html_search_language = 'en' # A dictionary with options for the search language support, empty by default. # Now only 'ja' uses this config value # 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 = 'sphinxcontribdatatemplatesdoc' # -- 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 = [ (master_doc, 'sphinxcontribdatatemplates.tex', u'sphinxcontrib.datatemplates Documentation', u'Doug Hellmann', '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 = [(master_doc, 'sphinxcontribdatatemplates', u'sphinxcontrib.datatemplates Documentation', [author], 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 = [ (master_doc, 'sphinxcontribdatatemplates', u'sphinxcontrib.datatemplates Documentation', author, 'sphinxcontribdatatemplates', '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 datatemplates-0.11.0/doc/source/csv.rst000066400000000000000000000010241453733615700200260ustar00rootroot00000000000000============== CSV Samples ============== Data File ========= .. literalinclude:: sample.csv :language: text Template File ============= .. literalinclude:: _templates/csv-sample.tmpl :language: jinja Loading the Template ==================== .. code-block:: rst .. datatemplate:csv:: sample.csv :template: csv-sample.tmpl :headers: :dialect: excel-tab Rendered Output =============== .. datatemplate:csv:: sample.csv :template: csv-sample.tmpl :headers: :dialect: excel-tab datatemplates-0.11.0/doc/source/dbm.rst000066400000000000000000000006611453733615700200030ustar00rootroot00000000000000============== DBM Samples ============== Creating Data File ================== .. include:: make_dbm.py :literal: Template File ============= .. include:: _templates/dbm-sample.tmpl :literal: Loading the Template ==================== .. code-block:: rst .. datatemplate:dbm:: sampledbm :template: dbm-sample.tmpl Rendered Output =============== .. datatemplate:dbm:: sampledbm :template: dbm-sample.tmpl datatemplates-0.11.0/doc/source/history.rst000066400000000000000000000104411453733615700207370ustar00rootroot00000000000000================= Release History ================= 0.10.0 ====== * Add python 3.12 to the test matrix and support list. * Add support for `custom template bridges `_. See `PR 92 `__ for details. (contribution by Ilya Boyazitov). 0.9.1 ===== * Fix dependency management in the directive so that directives with no source specified do not introduce a build dependency on a path that resolves to a directory. See `PR 83 `__ for details. (contributions by Øyvind Harboe) 0.9.0 ===== * Fix directive cross-reference management so it works in markdown files. See `PR 82 `__ for details. (contributions by Manuel Racle) 0.8.0 ===== * Add `load()` function to template context for loading data sources from within a template, to allow combining data from multiple sources. See :doc:`multiple-sources` for details. 0.7.2 ===== * update requirement for sphinxcontrib.runcmd to use the canonical form of the package name (contributions by Matthew Thode) 0.7.0 ===== * add sphinx builder environment to template context * cli: add a 'dump' subcommand * cli: create 'render' subcommand * treat flag options as special * add "datatemplate" console script * Update domain.py * pass the entire application config to the template * add sample for nothing * add 3.7 and 3.8 to list of supported python versions * add html\_context to template context * add data loaders registry * make directive option conversion results more intuitive * note source-file as dependency * pass all options to template, allow unknown options 0.6.1 ===== * pbr versioning 0.6.0 ===== * pbr is required not just for setup. See #43 * better option validators * Use directive head (arguments) for source path * Allow specifying template in directive body 0.5.0 ===== * Fix linting errors * Add domain for Python Modules * Move import to the top of the module * Use default template manager when the builder does not have one * Necessary method for parallel builds * list instead of tuple * Add option to load multiple documents from yaml * Restore Python3.6 compat * Add support for DBM formats * Set \_\_version\_\_ * ensure each directive page shows how to use the template 0.4.0 ===== * clarify/expand warning about legacy directive * add a doc page to show that the legacy form of the directive still works * turn off -W option in sphinx build * Wrap directives in minimal domain * stupid copy-paste merging * linting error * DataTemplate from 0.3.0 as DataTemplateLegacy for compat * method for path resolution * Add directive "datatemplate" for backwards compat * Update yaml.rst * Split datatemplate directive by file type * Ignore venv, vscode settings * add option for encoding 0.3.0 ===== * add examples to readme * add twine check to linter * fix packaging metadata * add a table to show the template input types * clean up bad comment in travis config * tell travis to use py3.6 and not ignore failures * remove extra doc format builds * remove superfluous travis command for go tools * tell git to ignore build artifacts * set up travis configuration * address flake8 errors * move dependency settings from tox to setup.cfg * Add dialect support, better dotumentation * Use yaml.safe\_load * Add a little bit of documentation for XML * Use defusedxml * Add XML support * Add CSV support 0.2.0 ===== * Use sphinx.util.logging for logging calls * Fix noqa flagging of import exception * optionally exec the conf.py file and pass settings to the template * make test-template support python 2 and 3 * update github URL in documentation * update the source repo URL in readme * update to python 3.5 * add license file * Add links to repo and docs from README and docs frontpage * add a command line tool to make testing templates easier 0.1.0 ===== * more protection against differences in builders * avoid errors for builders without template lookup * add usage instructions * add table helpers and samples * don't force a theme setting * remove debug print * add JSON support * add YAML support * fix flake8 warnings for sphinx conf.py * add ourself to the doc extensions we use * basic project setup datatemplates-0.11.0/doc/source/import-module.rst000066400000000000000000000006431453733615700220360ustar00rootroot00000000000000======================= Import-Module Samples ======================= Template File ============= .. include:: _templates/import-module-sample.tmpl :literal: Loading the Template ==================== .. code-block:: rst .. datatemplate:import-module:: os :template: import-module-sample.tmpl Rendered Output =============== .. datatemplate:import-module:: os :template: import-module-sample.tmpl datatemplates-0.11.0/doc/source/index.rst000066400000000000000000000014661453733615700203540ustar00rootroot00000000000000=========================================================== sphinxcontrib.datatemplates --- Render Your Data Readable =========================================================== ``sphinxcontrib.datatemplates`` helps you use static data in machine readable format in your documentation by letting you define Jinja2 templates to turn JSON, YAML, XML, or CSV data into reStructuredText for Sphinx to render as part of its output. * Repo: https://github.com/sphinxcontrib/sphinxcontrib.datatemplates * Docs: http://sphinxcontribdatatemplates.readthedocs.io/ .. toctree:: :maxdepth: 2 install using nodata json yaml xml import-module csv dbm inline multiple-sources legacy cli history Indices and tables ================== * :ref:`genindex` * :ref:`modindex` * :ref:`search` datatemplates-0.11.0/doc/source/inline.rst000066400000000000000000000024131453733615700205140ustar00rootroot00000000000000=============== Inline Sample =============== This example demonstrates how to use an inline template, as well as accessing the :ref:`HTML context ` available to all ``datatemplate`` directives, regardless of the data format. Data File ========= .. include:: sample.json :literal: HTML Context ============ .. code-block:: python # from conf.py html_context = { 'sample': 'Sample context value set in conf.py', } An Inline Template ================== .. code-block:: rst .. datatemplate:json:: :source: sample.json Individual Item ~~~~~~~~~~~~~~~ {{ data['key1'] }} List of Items ~~~~~~~~~~~~~ {% for item in data['key2'] %} - {{item}} {% endfor %} HTML Context ~~~~~~~~~~~~ {% for key, value in config.html_context.items() %} - ``{{key}}`` = ``{{value}}`` {% endfor %} Rendered Output =============== .. datatemplate:json:: :source: sample.json Individual Item ~~~~~~~~~~~~~~~ {{ data['key1'] }} List of Items ~~~~~~~~~~~~~ {% for item in data['key2'] %} - {{item}} {% endfor %} HTML Context ~~~~~~~~~~~~ {% for key, value in config.html_context.items() %} - ``{{key}}`` = ``{{value}}`` {% endfor %} datatemplates-0.11.0/doc/source/install.rst000066400000000000000000000007401453733615700207050ustar00rootroot00000000000000======================================== Installing sphinxcontrib.datatemplates ======================================== Install ``sphinxcontrib.datatemplates`` into the Python environment where Sphinx is installed. .. code-block:: console $ pip install sphinxcontrib.datatemplates Then modify the ``conf.py`` for the Sphinx project to add the package to the list of active extensions. .. code-block:: python extensions = [ 'sphinxcontrib.datatemplates', ] datatemplates-0.11.0/doc/source/inventory.csv000066400000000000000000000000431453733615700212530ustar00rootroot000000000000001WB0002,1001 2DR0013,401 1DX0077,14datatemplates-0.11.0/doc/source/json.rst000066400000000000000000000006321453733615700202100ustar00rootroot00000000000000============== JSON Samples ============== Data File ========= .. include:: sample.json :literal: Template File ============= .. include:: _templates/sample.tmpl :literal: Loading the Template ==================== .. code-block:: rst .. datatemplate:json:: sample.json :template: sample.tmpl Rendered Output =============== .. datatemplate:json:: sample.json :template: sample.tmpl datatemplates-0.11.0/doc/source/legacy.rst000066400000000000000000000006331453733615700205040ustar00rootroot00000000000000================ Legacy Samples ================ The ``datatemplate`` directive is should no longer be used. It is deprecated, and will be removed in the next release. Data File ========= .. include:: sample.yaml :literal: Template File ============= .. include:: _templates/sample.tmpl :literal: Rendered Output =============== .. datatemplate:: :source: sample.yaml :template: sample.tmpl datatemplates-0.11.0/doc/source/make_dbm.py000066400000000000000000000001621453733615700206140ustar00rootroot00000000000000import dbm.dumb with dbm.dumb.open("sampledbm", "c") as db: db[b"Hi"] = b"Hello" db[b"Bye"] = b"Goodbye" datatemplates-0.11.0/doc/source/multiple-sources.rst000066400000000000000000000026641453733615700225620ustar00rootroot00000000000000======================= Multiple Data Sources ======================= Data Files ========== Part details, indexed by a part number: .. include:: part-details.yaml :literal: Inventory counts: .. include:: inventory.csv :literal: Using ``load()`` in a Template ============================== The ``load()`` function visible in the template context can be used to load static data sources. .. literalinclude:: _templates/inventory.tmpl :language: rst ``load()`` will attempt to guess the format for a data source based on the name by looking at file extensions. To explicitly select a format, pass the name in the ``data_format`` argument. .. code-block:: rst {% set parts = load('part-details.dat', data_format='yaml') %} The arguments given to the ``datatemplate`` directive are also passed to the loader used by ``load()``. To override those settings, or provide different values for a different format, pass the arguments directly to ``load()``. .. code-block:: rst {% set parts = load('part-details.dat', data_format='json', encoding='UTF-8') %} .. note:: Database formats like ``dbm`` are not supported, and should be used as the primary data source for a ``datatemplate`` directive. Loading the Template ==================== .. code-block:: rst .. datatemplate:csv:: inventory.csv :template: inventory.tmpl Rendered Output =============== .. datatemplate:csv:: inventory.csv :template: inventory.tmpl datatemplates-0.11.0/doc/source/nodata.rst000066400000000000000000000011051453733615700205010ustar00rootroot00000000000000================ No Data Sample ================ Loading the Template ==================== .. code-block:: rst .. datatemplate:nodata:: Inline data: - {{ data }} Document titles from the Sphinx environment: {% for doc, title in env.titles.items() %} - ``{{ title }} ({{ doc }})`` {% endfor %} Rendered Output =============== .. datatemplate:nodata:: Inline data: - {{ data }} Document titles from the Sphinx environment: {% for doc, title in env.titles.items() %} - ``{{ title }} ({{ doc }})`` {% endfor %} datatemplates-0.11.0/doc/source/part-details.yaml000066400000000000000000000001631453733615700217610ustar00rootroot000000000000001WB0002: description: "Rear Window" 2DR0013: description: "Rear Door" 1DX0077: description: "Hatchback Door" datatemplates-0.11.0/doc/source/sample-multiple.yaml000066400000000000000000000000671453733615700225050ustar00rootroot00000000000000--- key1: value1 --- key: value key1: different value datatemplates-0.11.0/doc/source/sample.csv000066400000000000000000000000441453733615700205000ustar00rootroot00000000000000a b c Eins Zwei Drei 1 2 3 I II III datatemplates-0.11.0/doc/source/sample.json000066400000000000000000000004771453733615700206700ustar00rootroot00000000000000{ "key1": "value1", "key2": [ "list item 1", "list item 2", "list item 3" ], "nested-list": [ ["a", "b", "c"], ["A", "B", "C"] ], "mapping-series": [ {"cola": "a", "colb": "b", "colc": "c"}, {"cola": "A", "colb": "B", "colc": "C"} ] } datatemplates-0.11.0/doc/source/sample.xml000066400000000000000000000007431453733615700205130ustar00rootroot00000000000000 value1 list item 1 list item 2 list item 3 a b c A B C datatemplates-0.11.0/doc/source/sample.yaml000066400000000000000000000003241453733615700206500ustar00rootroot00000000000000--- key1: value1 key2: - list item 1 - list item 2 - list item 3 nested-list: - ['a', 'b', 'c'] - ['A', 'B', 'C'] mapping-series: - cola: a colb: b colc: c - cola: A colb: B colc: C datatemplates-0.11.0/doc/source/sampledbm.dat000066400000000000000000000010071453733615700211400ustar00rootroot00000000000000HelloGoodbyedatatemplates-0.11.0/doc/source/sampledbm.dir000066400000000000000000000000351453733615700211460ustar00rootroot00000000000000'Hi', (0, 5) 'Bye', (512, 7) datatemplates-0.11.0/doc/source/using.rst000066400000000000000000000042541453733615700203700ustar00rootroot00000000000000==================== Using datatemplate ==================== The ``datatemplate`` directive is the interface between the data source and the rendering template. Directives ========== .. datatemplate:import-module:: :source: sphinxcontrib.datatemplates.domain {% for key,directive in data.DataTemplateDomain.directives.items()|sort() %} {{directive.usage()}} {% endfor %} Template Files ============== The ``datatemplate`` directive uses Sphinx's `templates_path`_ configuration setting to search for template files. .. _templates_path: https://www.sphinx-doc.org/en/master/usage/configuration.html#confval-templates_path .. _template_context: Template Context ================ When a ``datatemplate`` directive is processed, the data from the ``source`` is passed to the template through its context so that the symbol ``data`` is available as a global variable. .. important:: The data is loaded from the source and passed directly to the template. No pre-processing is done on the data, so the template needs to handle aspects like ``None`` values and fields that have values that may interfere with parsing reStructuredText. The `application configuration`_ for a project will be passed to the template as the symbol ``config``. This can be used, for example, to access `HTML context`_ via ``config.html_context``. Refer to the :doc:`inline` for an example. The `Sphinx build environment`_ for a project will be passed to the template as the symbol ``env``. This can be used to access all of the information that Sphinx has about the current build, including settings, and document names. Refer to the :doc:`nodata` for an example. .. _HTML context: https://www.sphinx-doc.org/en/master/usage/configuration.html#confval-html_context .. _application configuration: https://www.sphinx-doc.org/en/master/usage/configuration.html .. _Sphinx build environment: https://www.sphinx-doc.org/en/master/extdev/envapi.html#sphinx.environment.BuildEnvironment Template Helpers ================ These helper functions are exposed using their short name (without the module prefix) in the template context. .. automodule:: sphinxcontrib.datatemplates.helpers :members: datatemplates-0.11.0/doc/source/xml.rst000066400000000000000000000006401453733615700200360ustar00rootroot00000000000000============== XML Samples ============== Data File ========= .. include:: sample.xml :literal: Template File ============= .. include:: _templates/xml-sample.tmpl :literal: Loading the Template ==================== .. code-block:: rst .. datatemplate:xml:: sample.xml :template: xml-sample.tmpl Rendered Output =============== .. datatemplate:xml:: sample.xml :template: xml-sample.tmpl datatemplates-0.11.0/doc/source/yaml.rst000066400000000000000000000017271453733615700202070ustar00rootroot00000000000000============== YAML Samples ============== Single Document +++++++++++++++ Data File ========= .. include:: sample.yaml :literal: Template File ============= .. include:: _templates/sample.tmpl :literal: Loading the Template ==================== .. code-block:: rst .. datatemplate:yaml:: sample.yaml :template: sample.tmpl Rendered Output =============== .. datatemplate:yaml:: sample.yaml :template: sample.tmpl Multiple Documents in One Source ++++++++++++++++++++++++++++++++ Data File ========= .. include:: sample-multiple.yaml :literal: Template File ============= .. include:: _templates/sample-multiple.tmpl :literal: Loading the Template ==================== .. code-block:: rst .. datatemplate:yaml:: sample-multiple.yaml :template: sample-multiple.tmpl :multiple-documents: Rendered Output =============== .. datatemplate:yaml:: sample-multiple.yaml :template: sample-multiple.tmpl :multiple-documents: datatemplates-0.11.0/pyproject.toml000066400000000000000000000031501453733615700173520ustar00rootroot00000000000000[build-system] requires = ["setuptools", "setuptools_scm[toml]>=6.2"] build-backend = "setuptools.build_meta" [project] name = "sphinxcontrib.datatemplates" readme = "README.rst" authors = [ {name = "Doug Hellmann", email = "doug@doughellmann.com"}, ] description = "Sphinx extension for rendering data files as nice HTML" dynamic = ["version"] classifiers = [ "Development Status :: 4 - Beta", "Environment :: Console", "Environment :: Web Environment", "Framework :: Sphinx :: Extension", "Intended Audience :: Developers", "License :: OSI Approved :: BSD License", "Operating System :: OS Independent", "Programming Language :: Python", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Topic :: Documentation", "Topic :: Utilities", ] requires-python = ">=3.8" dependencies = [ "Sphinx", "PyYAML", "defusedxml", "sphinxcontrib-runcmd", ] [project.scripts] datatemplate = "sphinxcontrib.datatemplates.cli:main" [project.urls] homepage = "https://sphinxcontribdatatemplates.readthedocs.io/en/latest/" repository = "http://github.com/sphinx-contrib/datatemplates" [project.optional-dependencies] linter = [ "flake8", ] test = [ "pytest", "beautifulsoup4", ] build = [ "build", "twine", ] [tools.setuptools] packages = [ "sphinxcontrib.datatemplates", ] # https://github.com/pypa/setuptools_scm/ [tool.setuptools_scm] write_to = "sphinxcontrib/datatemplates/version.py" datatemplates-0.11.0/pytest.ini000066400000000000000000000000631453733615700164670ustar00rootroot00000000000000[pytest] log_format = %(message)s log_level = debugdatatemplates-0.11.0/sphinxcontrib/000077500000000000000000000000001453733615700173315ustar00rootroot00000000000000datatemplates-0.11.0/sphinxcontrib/datatemplates/000077500000000000000000000000001453733615700221615ustar00rootroot00000000000000datatemplates-0.11.0/sphinxcontrib/datatemplates/__init__.py000066400000000000000000000007211453733615700242720ustar00rootroot00000000000000from sphinx.util import logging from . import directive, domain, version __version__ = version.__version__ LOG = logging.getLogger(__name__) def setup(app): LOG.info('initializing sphinxcontrib.datatemplates') app.add_directive('datatemplate', directive.DataTemplateLegacy) app.add_domain(domain.DataTemplateDomain) return { 'version': version.__version__, 'parallel_read_safe': True, 'parallel_write_safe': True, } datatemplates-0.11.0/sphinxcontrib/datatemplates/cli.py000066400000000000000000000066761453733615700233210ustar00rootroot00000000000000from __future__ import print_function import argparse import io import os.path import pprint import jinja2 from sphinxcontrib.datatemplates import helpers from sphinxcontrib.datatemplates import loaders def main(): parser = argparse.ArgumentParser() parser.add_argument( '--config-file', help='the path to conf.py', ) subparsers = parser.add_subparsers( title='commands', description='valid commands', dest='command', ) do_render = subparsers.add_parser( 'render', help='render a template to stdout', ) do_render.add_argument( '--option', '-o', action='append', default=[], help='options given as key:value passed through to loader and template' ) do_render.add_argument( 'template', help='the path to the template file', ) do_render.add_argument( 'source', help='the path to the data file', ) do_render.set_defaults(func=render) do_dump = subparsers.add_parser( 'dump', help='dump the data to stdout without a template', ) do_dump.add_argument( '--option', '-o', action='append', default=[], help='options given as key:value passed through to loader and template' ) do_dump.add_argument( 'source', help='the path to the data file', ) do_dump.set_defaults(func=dump) args = parser.parse_args() # no arguments, print help messaging, then exit with error(1) if not args.command: parser.print_help() return 1 conf = {} if args.config_file: with io.open(args.config_file, 'r', encoding='utf-8-sig') as f: config_body = f.read() exec(config_body, conf) return args.func(args, conf) def _parse_options(options): # Process the sequence of options. If there is a colon, use it to # separate the option name from its value. If there is no colon, # treat the option as a flag. results = {} for opt in options: if ':' in opt: k, _, v = opt.partition(':') else: k = opt v = True results[k.replace('-', '_')] = v return results def render(args, conf): conf.update(_parse_options(args.option)) conf.update({ "source": args.source, "template": args.template, "absolute_resolved_path": os.path.abspath(args.source) }) load = loaders.loader_for_source(args.source) if load is None: print('Could not find loader for {}'.format(args.source)) return 1 with io.open(args.template, 'r', encoding='utf-8-sig') as f: template_body = f.read() template = jinja2.Template(template_body) with load(**conf) as data: rendered = template.render( make_list_table=helpers.make_list_table, make_list_table_from_mappings=helpers. make_list_table_from_mappings, data=data, **conf ) print(rendered) def dump(args, conf): conf.update(_parse_options(args.option)) conf.update({ "source": args.source, "absolute_resolved_path": os.path.abspath(args.source) }) load = loaders.loader_for_source(args.source) if load is None: print('Could not find loader for {}'.format(args.source)) return 1 with load(**conf) as data: pprint.pprint(data) if __name__ == '__main__': main() datatemplates-0.11.0/sphinxcontrib/datatemplates/directive.py000066400000000000000000000436431453733615700245230ustar00rootroot00000000000000import codecs import csv import json import mimetypes from collections import defaultdict import defusedxml.ElementTree as ET import jinja2 import yaml from docutils import nodes from docutils.parsers import rst from docutils.statemachine import ViewList from sphinx.jinja2glue import BuiltinTemplateLoader from sphinx.util import logging, import_object from sphinx.util.nodes import nested_parse_with_titles from sphinxcontrib.datatemplates import helpers, loaders LOG = logging.getLogger(__name__) _default_templates = None def _templates(builder): global _default_templates # Some builders have no templates manager at all, and some # have the attribute set to None. templates = getattr(builder, 'templates', None) if not templates: if not _default_templates: # Initialize default templates manager once if builder.config.template_bridge: _default_templates = import_object( objname=builder.config.template_bridge, source="template_bridge setting", )() else: _default_templates = BuiltinTemplateLoader() _default_templates.init(builder) templates = _default_templates return templates def flag_true(argument): """ Check for a valid flag option (no argument) and return ``True``. (Directive option conversion function.) Raise ``ValueError`` if an argument is found. """ if argument and argument.strip(): raise ValueError('no argument is allowed; "%s" supplied' % argument) else: return True def unknown_option(argument): """ Check for a valid flag option (no argument) and return ``True``, else return argument stripped. (Directive option conversion function.) For unknown options we cannot know if they should be passed to the loader as flags or strings. We could pass ``None`` if the option string contains nothing except whitespace but this would not be intuitive for keyword argument flags as ``bool(None) is False``. """ if argument: stripped = argument.strip() if stripped: return stripped return True def unchanged_factory(): return unknown_option class DataTemplateBase(rst.Directive): optional_arguments = 1 final_argument_whitespace = True option_spec = defaultdict(unchanged_factory, { 'source': rst.directives.path, 'template': rst.directives.path, }) has_content = True @staticmethod def loader(): return NotImplemented def _make_context(self, data, config, env): return { 'make_list_table': helpers.make_list_table, 'make_list_table_from_mappings': helpers.make_list_table_from_mappings, 'escape_rst': helpers.escape_rst, 'escape_rst_url': helpers.escape_rst_url, 'data': data, 'config': config, 'options': self.options, 'env': env, 'load': self._dynamic_load, } def _dynamic_load(self, source, data_format=None, **input_loader_options): # FIXME: This does not work for dbm or other databases because # the handle is closed. env = self.state.document.settings.env relative_resolved_path, absolute_resolved_path = env.relfn2path(source) # Only add a dependency if we were given an explicit # source. Otherwise, we end up adding a directory as a # dependency, which is illegal. See # https://github.com/sphinx-contrib/datatemplates/pull/83 if source: env.note_dependency(absolute_resolved_path) if data_format is not None: loader = loaders.loader_by_name(data_format) if loader is None: raise ValueError('Could not find loader named {!r}'.format( data_format)) else: loader = loaders.loader_for_source(source, default=self.loader) loader_options = { "source": source, "relative_resolved_path": relative_resolved_path, "absolute_resolved_path": absolute_resolved_path, } if loader == self.loader: for k, v in self.options.items(): # make identifier-compatible if trivially possible k = k.lower().replace( "-", "_") loader_options.setdefault(k, v) # do not overwrite loader_options.update(input_loader_options) with loader(**loader_options) as data: return data def run(self): env = self.state.document.settings.env app = env.app builder = app.builder if 'source' in self.options: source = self.options['source'] elif self.arguments: source = self.arguments[0] elif self.loader in {loaders.load_import_module, loaders.load_nodata}: source = "" else: error = self.state_machine.reporter.error( 'Source file is required', nodes.literal_block(self.block_text, self.block_text), line=self.lineno) return [error] relative_resolved_path, absolute_resolved_path = env.relfn2path(source) # Only add a dependency if we were given an explicit # source. Otherwise, we end up adding a directory as a # dependency, which is illegal. See # https://github.com/sphinx-contrib/datatemplates/pull/83 if source: env.note_dependency(absolute_resolved_path) if 'template' in self.options: template = self.options['template'] render_function = _templates(builder).render else: template = '\n'.join(self.content) render_function = _templates(builder).render_string if not template: error = self.state_machine.reporter.error( "Template is empty", nodes.literal_block(self.block_text, self.block_text), line=self.lineno) return [error] loader_options = { "source": source, "relative_resolved_path": relative_resolved_path, "absolute_resolved_path": absolute_resolved_path, } for k, v in self.options.items(): k = k.lower().replace( "-", "_") # make identifier-compatible if trivially possible loader_options.setdefault(k, v) # do not overwrite try: with self.loader(**loader_options) as data: context = self._make_context(data, app.config, env) rendered_template = render_function( template, context, ) except FileNotFoundError: error = self.state_machine.reporter.error( f"Source file '{relative_resolved_path}' not found", nodes.literal_block(self.block_text, self.block_text), line=self.lineno) return [error] except loaders.LoaderError as err: error = self.state_machine.reporter.error( f"Error in source '{relative_resolved_path}': {err}", nodes.literal_block(self.block_text, self.block_text), line=self.lineno) return [error] except jinja2.exceptions.TemplateNotFound: error = self.state_machine.reporter.error( f"Template file '{template}' not found", nodes.literal_block(self.block_text, self.block_text), line=self.lineno) return [error] except jinja2.exceptions.TemplateSyntaxError as err: error = self.state_machine.reporter.error( f"Error in template file '{template}' line {err.lineno}: " f"{err.message}", nodes.literal_block(self.block_text, self.block_text), line=self.lineno) return [error] result = ViewList() for line in rendered_template.splitlines(): result.append(line, source) node = nodes.section() node.document = self.state.document nested_parse_with_titles(self.state, result, node) return node.children @classmethod def usage(cls): _, sep, doc = cls.__doc__.partition(".. rst:directive::") return sep + doc class DataTemplateWithEncoding(DataTemplateBase): option_spec = defaultdict(unchanged_factory, DataTemplateBase.option_spec, **{ 'encoding': rst.directives.encoding, }) class DataTemplateNoData(DataTemplateBase): """ .. rst:directive:: .. datatemplate:nodata:: Load ``None`` as ``data`` and render using ``template`` given in directive body. .. rst:directive:option:: template: template name, optional The name of a template file on the Sphinx template search path. Overrides directive body. """ loader = staticmethod(loaders.load_nodata) class DataTemplateJSON(DataTemplateWithEncoding): """ .. rst:directive:: .. datatemplate:json:: source-path Load file at ``source-path`` (relative to the documentation build directory) via :py:func:`json.load` and render using ``template`` given in directive body. .. rst:directive:option:: template: template name, optional The name of a template file on the Sphinx template search path. Overrides directive body. .. rst:directive:option:: encoding: optional, defaults to ``utf-8-sig`` The text encoding that will be used to read the source file. See :any:`standard-encodings` """ loader = staticmethod(loaders.load_json) def _handle_dialect_option(argument): return rst.directives.choice(argument, ["auto"] + csv.list_dialects()) class DataTemplateCSV(DataTemplateWithEncoding): """ .. rst:directive:: .. datatemplate:csv:: source-path Load file at ``source-path`` (relative to the documentation build directory) via :py:func:`csv.reader` or :py:class:`csv.DictReader` depending on ``header`` and render using ``template`` given in directive body. .. rst:directive:option:: template: template name, optional The name of a template file on the Sphinx template search path. Overrides directive body. .. rst:directive:option:: encoding: optional, defaults to ``utf-8-sig`` The text encoding that will be used to read the source file. See :any:`standard-encodings` .. rst:directive:option:: header: flag, optional Set to use :py:class:`csv.DictReader` for reading the file. If not set :py:func:`csv.reader` is used. .. rst:directive:option:: dialect: optional Set to select a specific :py:class:`csv.Dialect`. Set to ``auto``, to try autodetection. If not set the default dialect is used. """ option_spec = defaultdict( unchanged_factory, DataTemplateBase.option_spec, **{ 'headers': flag_true, 'dialect': _handle_dialect_option, }) loader = staticmethod(loaders.load_csv) class DataTemplateYAML(DataTemplateWithEncoding): """ .. rst:directive:: .. datatemplate:yaml:: source-path Load file at ``source-path`` (relative to the documentation build directory) via PyYAML_ (:py:func:`yaml.safe_load`) and render using ``template`` given in directive body. .. _PyYAML: https://pyyaml.org .. rst:directive:option:: template: template name, optional The name of a template file on the Sphinx template search path. Overrides directive body. .. rst:directive:option:: encoding: optional, defaults to ``utf-8-sig`` The text encoding that will be used to read the source file. See :any:`standard-encodings` .. rst:directive:option:: multiple-documents: flag, optional Set to read multiple documents from the file into a :py:class:`list` """ option_spec = defaultdict(unchanged_factory, DataTemplateBase.option_spec, **{ 'multiple-documents': flag_true, }) loader = staticmethod(loaders.load_yaml) class DataTemplateXML(DataTemplateBase): """ .. rst:directive:: .. datatemplate:xml:: source-path Load file at ``source-path`` (relative to the documentation build directory) via :py:func:`xml.etree.ElementTree.parse` (actually using ``defusedxml``) and render using ``template`` given in directive body. .. rst:directive:option:: template: template name, optional The name of a template file on the Sphinx template search path. Overrides directive body. """ loader = staticmethod(loaders.load_xml) class DataTemplateDBM(DataTemplateBase): """ .. rst:directive:: datatemplate:dbm:: source-path Load DB at ``source-path`` (relative to the documentation build directory) via :py:func:`dbm.open` and render using ``template`` given in directive body. .. rst:directive:option:: template: template name, optional The name of a template file on the Sphinx template search path. Overrides directive body. """ loader = staticmethod(loaders.load_dbm) class DataTemplateImportModule(DataTemplateBase): """ .. rst:directive:: .. datatemplate:import-module:: module-name Load module ``module-name`` (must be importable in ``conf.py``) via :py:func:`importlib.import_module` and render using ``template`` given in directive body. .. rst:directive:option:: template: template name, optional The name of a template file on the Sphinx template search path. Overrides directive body. """ loader = staticmethod(loaders.load_import_module) class DataTemplateLegacy(rst.Directive): option_spec = { 'source': rst.directives.path, 'template': rst.directives.path, 'csvheaders': rst.directives.flag, 'csvdialect': _handle_dialect_option, 'encoding': rst.directives.encoding, } has_content = False def _load_csv(self, filename, encoding): try: if encoding is None: f = open(filename, 'r', newline='') else: f = codecs.open(filename, 'r', newline='', encoding=encoding) dialect = self.options.get('csvdialect') if dialect == "auto": sample = f.read(8192) f.seek(0) sniffer = csv.Sniffer() dialect = sniffer.sniff(sample) if 'csvheaders' in self.options: if dialect is None: r = csv.DictReader(f) else: r = csv.DictReader(f, dialect=dialect) else: if dialect is None: r = csv.reader(f) else: r = csv.reader(f, dialect=dialect) return list(r) finally: f.close() def _load_json(self, filename, encoding): try: if encoding is None: f = open(filename, 'r') else: f = codecs.open(filename, 'r', encoding=encoding) return json.load(f) finally: f.close() def _load_yaml(self, filename, encoding): try: if encoding is None: f = open(filename, 'r') else: f = codecs.open(filename, 'r', encoding=encoding) return yaml.safe_load(f) finally: f.close() def _load_data(self, env, data_source, encoding): rel_filename, filename = env.relfn2path(data_source) if data_source.endswith('.yaml'): return self._load_yaml(filename, encoding) elif data_source.endswith('.json'): return self._load_json(filename, encoding) elif data_source.endswith('.csv'): return self._load_csv(filename, encoding) elif "xml" in mimetypes.guess_type(data_source)[0]: # there are many XML based formats return ET.parse(filename).getroot() else: raise NotImplementedError('cannot load file type of %s' % data_source) def run(self): env = self.state.document.settings.env app = env.app builder = app.builder try: data_source = self.options['source'] except KeyError: error = self.state_machine.reporter.error( 'No source set for datatemplate directive', nodes.literal_block(self.block_text, self.block_text), line=self.lineno) return [error] try: template_name = self.options['template'] except KeyError: error = self.state_machine.reporter.error( 'No template set for datatemplate directive', nodes.literal_block(self.block_text, self.block_text), line=self.lineno) return [error] encoding = self.options.get('encoding', None) data = self._load_data(env, data_source, encoding) context = { 'make_list_table': helpers.make_list_table, 'make_list_table_from_mappings': helpers.make_list_table_from_mappings, 'data': data, } rendered_template = _templates(builder).render( template_name, context, ) result = ViewList() for line in rendered_template.splitlines(): result.append(line, data_source) node = nodes.section() node.document = self.state.document nested_parse_with_titles(self.state, result, node) return node.children datatemplates-0.11.0/sphinxcontrib/datatemplates/domain.py000066400000000000000000000015521453733615700240050ustar00rootroot00000000000000from sphinx.domains import Domain from . import directive class DataTemplateDomain(Domain): name = 'datatemplate' label = 'DataTemplate Replacement' directives = { 'nodata': directive.DataTemplateNoData, 'json': directive.DataTemplateJSON, 'yaml': directive.DataTemplateYAML, 'csv': directive.DataTemplateCSV, 'xml': directive.DataTemplateXML, 'dbm': directive.DataTemplateDBM, 'import-module': directive.DataTemplateImportModule, } def get_objects(self): return [] def resolve_xref(self, env, fromdocname, builder, typ, target, node, contnode): return None def resolve_any_xref(self, env, fromdocname, builder, target, node, contnode): return [] def merge_domaindata(self, docnames, otherdata): pass datatemplates-0.11.0/sphinxcontrib/datatemplates/helpers.py000066400000000000000000000035631453733615700242040ustar00rootroot00000000000000def make_list_table(headers, data, title='', columns=None): """Build a list-table directive. :param headers: List of header values. :param data: Iterable of row data, yielding lists or tuples with rows. :param title: Optional text to show as the table title. :param columns: Optional widths for the columns. """ results = [] add = results.append add('.. list-table:: %s' % title) add(' :header-rows: 1') if columns: add(' :widths: %s' % (','.join(str(c) for c in columns))) add('') add(' - * %s' % headers[0]) for h in headers[1:]: add(' * %s' % h) for row in data: add(' - * %s' % row[0]) for r in row[1:]: add(' * %s' % r) add('') return '\n'.join(results) def make_list_table_from_mappings(headers, data, title, columns=None): """Build a list-table directive. :param headers: List of tuples containing header title and key value. :param data: Iterable of row data, yielding mappings with rows. :param title: Optional text to show as the table title. :param columns: Optional widths for the columns. """ header_names = [h[0] for h in headers] header_keys = [h[1] for h in headers] row_data = ([d.get(k) for k in header_keys] for d in data) return make_list_table(header_names, row_data, title, columns) def escape_rst(s): """Escape string for inclusion in RST documents. See https://docutils.sourceforge.io/docs/ref/rst/restructuredtext.html#escaping-mechanism :param s: String for escaping """ return "".join(c if c.isspace() else "\\" + c for c in s) def escape_rst_url(s): """Escape string for inclusion in URLs in RST documents. See https://docutils.sourceforge.io/docs/ref/rst/restructuredtext.html#escaping-mechanism :param s: String for escaping """ return "\\".join(s) datatemplates-0.11.0/sphinxcontrib/datatemplates/loaders.py000066400000000000000000000116501453733615700241670ustar00rootroot00000000000000import contextlib import csv import dbm import defusedxml.ElementTree as ET import importlib import json import mimetypes import pathlib import yaml registered_loaders = [] class LoaderError(Exception): pass class LoaderEntry: def __init__(self, loader, name, match_source): self.loader = loader self.name = name self.match_source = match_source def loader_for_source(source, default=None): "Return the loader for the named source." for e in registered_loaders: if e.match_source is not None and e.match_source(source): return e.loader return default def loader_by_name(name, default=None): "Return the loader registered with the given name." for e in registered_loaders: if e.match_source is not None and e.name == name: return e.loader return default def mimetype_loader(name, mimetype): "A data loader for the exact mimetype." def check_mimetype(source): guess = mimetypes.guess_type(source)[0] if not guess: return False return guess == mimetype return data_source_loader(name, check_mimetype) def lenient_mimetype_loader(name, mimetype_fragment): "A data loader for a mimetype containing the given substring." def check_mimetype(source): guess = mimetypes.guess_type(source)[0] if not guess: return False return mimetype_fragment in guess return data_source_loader(name, check_mimetype) def file_extension_loader(name, extensions): "A data loader for filenames ending with one of the given extensions." def check_ext(filename): return pathlib.Path(filename).suffix.lower() in set( e.lower() for e in extensions) return data_source_loader(name, check_ext) def data_source_loader(name, match_source=None): """Add a named loader Add a named data loader with an optional function for matching to source names. """ def wrap(loader_func): registered_loaders.append(LoaderEntry(loader_func, name, match_source)) return loader_func return wrap @data_source_loader("nodata") @contextlib.contextmanager def load_nodata(source, **options): yield None @file_extension_loader("csv", [".csv"]) @contextlib.contextmanager def load_csv(source, absolute_resolved_path, headers=False, dialect=None, encoding='utf-8-sig', **options): with open(absolute_resolved_path, 'r', newline='', encoding=encoding) as f: if dialect == "auto": sample = f.read(8192) f.seek(0) sniffer = csv.Sniffer() dialect = sniffer.sniff(sample) if headers: if dialect is None: r = csv.DictReader(f) else: r = csv.DictReader(f, dialect=dialect) else: if dialect is None: r = csv.reader(f) else: r = csv.reader(f, dialect=dialect) yield list(r) @mimetype_loader("json", "application/json") @contextlib.contextmanager def load_json(source, absolute_resolved_path, encoding='utf-8-sig', **options): with open(absolute_resolved_path, 'r', encoding=encoding) as f: try: yield json.load(f) except json.decoder.JSONDecodeError as error: raise LoaderError(str(error)) from error @file_extension_loader("yaml", ['.yml', '.yaml']) @contextlib.contextmanager def load_yaml(source, absolute_resolved_path, encoding='utf-8-sig', multiple_documents=False, **options): with open(absolute_resolved_path, 'r', encoding=encoding) as f: try: if multiple_documents: yield list( yaml.safe_load_all(f) ) # force loading all documents now so the file can be closed else: yield yaml.safe_load(f) except yaml.error.MarkedYAMLError as error: if error.context_mark.name == absolute_resolved_path: error.context_mark.name = source error.problem_mark.name = source raise LoaderError(str(error)) from error @lenient_mimetype_loader('xml', 'xml') @contextlib.contextmanager def load_xml(source, absolute_resolved_path, **options): try: yield ET.parse(absolute_resolved_path).getroot() except ET.ParseError as error: raise LoaderError(str(error)) from error @file_extension_loader("dbm", ['.dbm']) def load_dbm(source, absolute_resolved_path, **options): try: return dbm.open(absolute_resolved_path, "r") except dbm.error[0] as error: raise LoaderError(str(error)) from error @data_source_loader("import-module") @contextlib.contextmanager def load_import_module(source, **options): try: yield importlib.import_module(source) except ModuleNotFoundError as error: raise LoaderError(str(error)) from error datatemplates-0.11.0/tests/000077500000000000000000000000001453733615700156015ustar00rootroot00000000000000datatemplates-0.11.0/tests/conftest.py000066400000000000000000000010261453733615700177770ustar00rootroot00000000000000import pytest from pathlib import Path from sphinx import version_info as sphinx_version_info pytest_plugins = "sphinx.testing.fixtures" @pytest.fixture(scope="session") def rootdir(): """ Fixture for 'pytest.mark.sphinx'. Test data is stored in the 'testdata/test-'. """ if sphinx_version_info >= (7, 2): abs_path = Path(__file__).parent.absolute() else: from sphinx.testing.path import path abs_path = path(__file__).parent.abspath() return abs_path / "testdata" datatemplates-0.11.0/tests/test_custom_template_bridge.py000066400000000000000000000011241453733615700237310ustar00rootroot00000000000000from __future__ import annotations import pytest from pathlib import Path from typing import TYPE_CHECKING from bs4 import BeautifulSoup if TYPE_CHECKING: from sphinx.testing.util import SphinxTestApp @pytest.mark.sphinx("html", testroot="custom-template-bridge") def test_custom_template_bridge(app: SphinxTestApp): app.builder.build_all() assert app._warncount == 0, "\n".join(app.messagelog) result = Path(app.outdir, "index.html").read_text() soup = BeautifulSoup(result, "html.parser") tag = soup.select("div.body > p")[0] assert tag.text == "SOME_VALUE" datatemplates-0.11.0/tests/test_errors.py000066400000000000000000000103431453733615700205270ustar00rootroot00000000000000from __future__ import annotations from typing import TYPE_CHECKING import pytest if TYPE_CHECKING: from io import StringIO from sphinx.testing.util import SphinxTestApp @pytest.mark.sphinx("html", testroot="empty-source") def test_empty_source(app: SphinxTestApp, warning: StringIO): app.builder.build_all() expected_error_str = ( f"{app.srcdir / 'index.rst'}:1: ERROR: Source file is required" ) assert expected_error_str in warning.getvalue() @pytest.mark.sphinx("html", testroot="nonexistent-source") def test_nonexisting_source(app: SphinxTestApp, warning: StringIO): app.builder.build_all() expected_error_str = ( f"{app.srcdir / 'index.rst'}:1: " "ERROR: Source file 'sample1.json' not found" ) assert expected_error_str in warning.getvalue() @pytest.mark.sphinx("html", testroot="empty-template") def test_empty_template(app: SphinxTestApp, warning: StringIO): app.builder.build_all() expected_error_str = ( f"{app.srcdir / 'index.rst'}:1: ERROR: Template is empty" ) assert expected_error_str in warning.getvalue() @pytest.mark.sphinx("html", testroot="nonexistent-template") def test_nonexistent_template(app: SphinxTestApp, warning: StringIO): app.builder.build_all() expected_error_str = ( f"{app.srcdir / 'index.rst'}:1: " "ERROR: Template file 'sample1.tmpl' not found" ) assert expected_error_str in warning.getvalue() @pytest.mark.sphinx("html", testroot="nonexistent-template-filter") def test_nonexistent_template_filter(app: SphinxTestApp, warning: StringIO): app.builder.build_all() expected_error_str = ( f"{app.srcdir / 'index.rst'}:1: " "ERROR: Error in template file 'sample.tmpl' line 1: " "No filter named 'some_filter'." ) assert expected_error_str in warning.getvalue() @pytest.mark.sphinx("html", testroot="incorrect-template-syntax") def test_incorrect_template_syntax(app: SphinxTestApp, warning: StringIO): app.builder.build_all() expected_error_str = ( f"{app.srcdir / 'index.rst'}:1: " "ERROR: Error in template file 'sample.tmpl' line 1: " "unexpected '}'" ) assert expected_error_str in warning.getvalue() @pytest.mark.sphinx("html", testroot="incorrect-json-syntax") def test_incorrect_json_syntax(app: SphinxTestApp, warning: StringIO): app.builder.build_all() expected_error_str = ( f"{app.srcdir / 'index.rst'}:1: " "ERROR: Error in source 'sample.json': " "Invalid control character at: line 2 column 28 (char 29)" ) assert expected_error_str in warning.getvalue() @pytest.mark.sphinx("html", testroot="incorrect-yaml-syntax") def test_incorrect_yaml_syntax(app: SphinxTestApp, warning: StringIO): app.builder.build_all() expected_error_str = ( f"{app.srcdir / 'index.rst'}:1: " "ERROR: Error in source 'sample.yaml': " "while parsing a block collection\n" ' in "sample.yaml", line 11, column 3\n' "expected , but found '?'\n" ' in "sample.yaml", line 12, column 3' ) assert expected_error_str in warning.getvalue() @pytest.mark.sphinx("html", testroot="incorrect-xml-syntax") def test_incorrect_xml_syntax(app: SphinxTestApp, warning: StringIO): app.builder.build_all() expected_error_str = ( f"{app.srcdir / 'index.rst'}:1: " "ERROR: Error in source 'sample.xml': " "not well-formed (invalid token): line 2, column 4" ) assert expected_error_str in warning.getvalue() @pytest.mark.sphinx("html", testroot="incorrect-import-module") def test_incorrect_import_module(app: SphinxTestApp, warning: StringIO): app.builder.build_all() expected_error_str = ( f"{app.srcdir / 'index.rst'}:1: " "ERROR: Error in source 'some_module': No module named 'some_module'" ) assert expected_error_str in warning.getvalue() @pytest.mark.sphinx("html", testroot="incorrect-dbm") def test_incorrect_dbm(app: SphinxTestApp, warning: StringIO): app.builder.build_all() expected_error_str = ( f"{app.srcdir / 'index.rst'}:1: " "ERROR: Error in source 'sampledbm': " "db type could not be determined" ) assert expected_error_str in warning.getvalue() datatemplates-0.11.0/tests/test_loaders.py000066400000000000000000000013571453733615700206510ustar00rootroot00000000000000from sphinxcontrib.datatemplates import loaders def test_lookup_json(): actual = loaders.loader_for_source('source.json') assert actual == loaders.load_json def test_lookup_yaml(): actual = loaders.loader_for_source('source.yaml') assert actual == loaders.load_yaml def test_lookup_yml(): actual = loaders.loader_for_source('source.yml') assert actual == loaders.load_yaml def test_lookup_xml(): actual = loaders.loader_for_source('source.xml') assert actual == loaders.load_xml def test_lookup_csv(): actual = loaders.loader_for_source('source.csv') assert actual == loaders.load_csv def test_lookup_dbm(): actual = loaders.loader_for_source('source.dbm') assert actual == loaders.load_dbm datatemplates-0.11.0/tests/test_loaders_csv.py000066400000000000000000000006101453733615700215130ustar00rootroot00000000000000import pathlib from sphinxcontrib.datatemplates import loaders def get_source_path(source): return (pathlib.Path('doc') / 'source' / source).resolve() def test_load_csv(): source = 'sample.csv' abs_path = get_source_path(source) with loaders.load_csv(source, abs_path, dialect='excel-tab') as data: assert len(data) == 4 assert data[0] == ['a', 'b', 'c'] datatemplates-0.11.0/tests/testdata/000077500000000000000000000000001453733615700174125ustar00rootroot00000000000000datatemplates-0.11.0/tests/testdata/test-custom-template-bridge/000077500000000000000000000000001453733615700247445ustar00rootroot00000000000000datatemplates-0.11.0/tests/testdata/test-custom-template-bridge/conf.py000066400000000000000000000003041453733615700262400ustar00rootroot00000000000000import os import sys sys.path.append(os.path.abspath("lib")) extensions = ["sphinxcontrib.datatemplates"] templates_path = ["templates"] template_bridge = "template_bridge.CustomTemplateLoader" datatemplates-0.11.0/tests/testdata/test-custom-template-bridge/index.rst000066400000000000000000000000761453733615700266100ustar00rootroot00000000000000.. datatemplate:json:: sample.json :template: sample.tmpl datatemplates-0.11.0/tests/testdata/test-custom-template-bridge/lib/000077500000000000000000000000001453733615700255125ustar00rootroot00000000000000datatemplates-0.11.0/tests/testdata/test-custom-template-bridge/lib/template_bridge.py000066400000000000000000000012051453733615700312110ustar00rootroot00000000000000from __future__ import annotations from typing import TYPE_CHECKING from sphinx.jinja2glue import BuiltinTemplateLoader if TYPE_CHECKING: from typing import List, Optional from sphinx.builders import Builder from sphinx.theming import Theme def upperstring(input: str): """Custom filter""" return input.upper() class CustomTemplateLoader(BuiltinTemplateLoader): def init( self, builder: Builder, theme: Optional[Theme] = None, dirs: Optional[List[str]] = None, ) -> None: super().init(builder, theme, dirs) self.environment.filters["upperstring"] = upperstring datatemplates-0.11.0/tests/testdata/test-custom-template-bridge/sample.json000066400000000000000000000000411453733615700271130ustar00rootroot00000000000000{ "some_key": "some_value" } datatemplates-0.11.0/tests/testdata/test-custom-template-bridge/templates/000077500000000000000000000000001453733615700267425ustar00rootroot00000000000000datatemplates-0.11.0/tests/testdata/test-custom-template-bridge/templates/sample.tmpl000066400000000000000000000000401453733615700311130ustar00rootroot00000000000000{{data.some_key | upperstring}} datatemplates-0.11.0/tests/testdata/test-empty-source/000077500000000000000000000000001453733615700230235ustar00rootroot00000000000000datatemplates-0.11.0/tests/testdata/test-empty-source/conf.py000066400000000000000000000001141453733615700243160ustar00rootroot00000000000000extensions = ["sphinxcontrib.datatemplates"] templates_path = ["templates"] datatemplates-0.11.0/tests/testdata/test-empty-source/index.rst000066400000000000000000000000621453733615700246620ustar00rootroot00000000000000.. datatemplate:json:: :template: sample.tmpl datatemplates-0.11.0/tests/testdata/test-empty-source/sample.json000066400000000000000000000000411453733615700251720ustar00rootroot00000000000000{ "some_key": "some_value" } datatemplates-0.11.0/tests/testdata/test-empty-source/templates/000077500000000000000000000000001453733615700250215ustar00rootroot00000000000000datatemplates-0.11.0/tests/testdata/test-empty-source/templates/sample.tmpl000066400000000000000000000000221453733615700271720ustar00rootroot00000000000000{{data.some_key}} datatemplates-0.11.0/tests/testdata/test-empty-template/000077500000000000000000000000001453733615700233365ustar00rootroot00000000000000datatemplates-0.11.0/tests/testdata/test-empty-template/conf.py000066400000000000000000000001141453733615700246310ustar00rootroot00000000000000extensions = ["sphinxcontrib.datatemplates"] templates_path = ["templates"] datatemplates-0.11.0/tests/testdata/test-empty-template/index.rst000066400000000000000000000000431453733615700251740ustar00rootroot00000000000000.. datatemplate:json:: sample.json datatemplates-0.11.0/tests/testdata/test-empty-template/sample.json000066400000000000000000000000411453733615700255050ustar00rootroot00000000000000{ "some_key": "some_value" } datatemplates-0.11.0/tests/testdata/test-empty-template/templates/000077500000000000000000000000001453733615700253345ustar00rootroot00000000000000datatemplates-0.11.0/tests/testdata/test-empty-template/templates/sample.tmpl000066400000000000000000000000221453733615700275050ustar00rootroot00000000000000{{data.some_key}} datatemplates-0.11.0/tests/testdata/test-incorrect-dbm/000077500000000000000000000000001453733615700231175ustar00rootroot00000000000000datatemplates-0.11.0/tests/testdata/test-incorrect-dbm/conf.py000066400000000000000000000001141453733615700244120ustar00rootroot00000000000000extensions = ["sphinxcontrib.datatemplates"] templates_path = ["templates"] datatemplates-0.11.0/tests/testdata/test-incorrect-dbm/index.rst000066400000000000000000000000731453733615700247600ustar00rootroot00000000000000.. datatemplate:dbm:: sampledbm :template: sample.tmpl datatemplates-0.11.0/tests/testdata/test-incorrect-dbm/sampledbm000066400000000000000000000000131453733615700250000ustar00rootroot00000000000000sample textdatatemplates-0.11.0/tests/testdata/test-incorrect-dbm/templates/000077500000000000000000000000001453733615700251155ustar00rootroot00000000000000datatemplates-0.11.0/tests/testdata/test-incorrect-dbm/templates/sample.tmpl000066400000000000000000000000111453733615700272640ustar00rootroot00000000000000{{data}} datatemplates-0.11.0/tests/testdata/test-incorrect-import-module/000077500000000000000000000000001453733615700251525ustar00rootroot00000000000000datatemplates-0.11.0/tests/testdata/test-incorrect-import-module/conf.py000066400000000000000000000001141453733615700264450ustar00rootroot00000000000000extensions = ["sphinxcontrib.datatemplates"] templates_path = ["templates"] datatemplates-0.11.0/tests/testdata/test-incorrect-import-module/index.rst000066400000000000000000000001071453733615700270110ustar00rootroot00000000000000.. datatemplate:import-module:: some_module :template: sample.tmpl datatemplates-0.11.0/tests/testdata/test-incorrect-import-module/templates/000077500000000000000000000000001453733615700271505ustar00rootroot00000000000000datatemplates-0.11.0/tests/testdata/test-incorrect-import-module/templates/sample.tmpl000066400000000000000000000000111453733615700313170ustar00rootroot00000000000000{{data}} datatemplates-0.11.0/tests/testdata/test-incorrect-json-syntax/000077500000000000000000000000001453733615700246525ustar00rootroot00000000000000datatemplates-0.11.0/tests/testdata/test-incorrect-json-syntax/conf.py000066400000000000000000000001141453733615700261450ustar00rootroot00000000000000extensions = ["sphinxcontrib.datatemplates"] templates_path = ["templates"] datatemplates-0.11.0/tests/testdata/test-incorrect-json-syntax/index.rst000066400000000000000000000000761453733615700265160ustar00rootroot00000000000000.. datatemplate:json:: sample.json :template: sample.tmpl datatemplates-0.11.0/tests/testdata/test-incorrect-json-syntax/sample.json000066400000000000000000000000401453733615700270200ustar00rootroot00000000000000{ "some_key": "some_value } datatemplates-0.11.0/tests/testdata/test-incorrect-json-syntax/templates/000077500000000000000000000000001453733615700266505ustar00rootroot00000000000000datatemplates-0.11.0/tests/testdata/test-incorrect-json-syntax/templates/sample.tmpl000066400000000000000000000000221453733615700310210ustar00rootroot00000000000000{{data.some_key}} datatemplates-0.11.0/tests/testdata/test-incorrect-template-syntax/000077500000000000000000000000001453733615700255145ustar00rootroot00000000000000datatemplates-0.11.0/tests/testdata/test-incorrect-template-syntax/conf.py000066400000000000000000000001141453733615700270070ustar00rootroot00000000000000extensions = ["sphinxcontrib.datatemplates"] templates_path = ["templates"] datatemplates-0.11.0/tests/testdata/test-incorrect-template-syntax/index.rst000066400000000000000000000000761453733615700273600ustar00rootroot00000000000000.. datatemplate:json:: sample.json :template: sample.tmpl datatemplates-0.11.0/tests/testdata/test-incorrect-template-syntax/sample.json000066400000000000000000000000411453733615700276630ustar00rootroot00000000000000{ "some_key": "some_value" } datatemplates-0.11.0/tests/testdata/test-incorrect-template-syntax/templates/000077500000000000000000000000001453733615700275125ustar00rootroot00000000000000datatemplates-0.11.0/tests/testdata/test-incorrect-template-syntax/templates/sample.tmpl000066400000000000000000000000211453733615700316620ustar00rootroot00000000000000{{data.some_key} datatemplates-0.11.0/tests/testdata/test-incorrect-xml-syntax/000077500000000000000000000000001453733615700245015ustar00rootroot00000000000000datatemplates-0.11.0/tests/testdata/test-incorrect-xml-syntax/conf.py000066400000000000000000000001141453733615700257740ustar00rootroot00000000000000extensions = ["sphinxcontrib.datatemplates"] templates_path = ["templates"] datatemplates-0.11.0/tests/testdata/test-incorrect-xml-syntax/index.rst000066400000000000000000000000741453733615700263430ustar00rootroot00000000000000.. datatemplate:xml:: sample.xml :template: sample.tmpl datatemplates-0.11.0/tests/testdata/test-incorrect-xml-syntax/sample.xml000066400000000000000000000007421453733615700265070ustar00rootroot00000000000000value1 list item 1 list item 2 list item 3 a b c A B C datatemplates-0.11.0/tests/testdata/test-incorrect-xml-syntax/templates/000077500000000000000000000000001453733615700264775ustar00rootroot00000000000000datatemplates-0.11.0/tests/testdata/test-incorrect-xml-syntax/templates/sample.tmpl000066400000000000000000000000331453733615700306520ustar00rootroot00000000000000{{data.find('key1').text}} datatemplates-0.11.0/tests/testdata/test-incorrect-yaml-syntax/000077500000000000000000000000001453733615700246435ustar00rootroot00000000000000datatemplates-0.11.0/tests/testdata/test-incorrect-yaml-syntax/conf.py000066400000000000000000000001141453733615700261360ustar00rootroot00000000000000extensions = ["sphinxcontrib.datatemplates"] templates_path = ["templates"] datatemplates-0.11.0/tests/testdata/test-incorrect-yaml-syntax/index.rst000066400000000000000000000000761453733615700265070ustar00rootroot00000000000000.. datatemplate:yaml:: sample.yaml :template: sample.tmpl datatemplates-0.11.0/tests/testdata/test-incorrect-yaml-syntax/sample.yaml000066400000000000000000000003221453733615700270050ustar00rootroot00000000000000--- key1: value1 key2: - list item 1 - list item 2 - list item 3 nested-list: - ['a', 'b', 'c'] - ['A', 'B', 'C'] mapping-series: - cola: a colb: b colc: c - cola: A colb: B colc: C datatemplates-0.11.0/tests/testdata/test-incorrect-yaml-syntax/templates/000077500000000000000000000000001453733615700266415ustar00rootroot00000000000000datatemplates-0.11.0/tests/testdata/test-incorrect-yaml-syntax/templates/sample.tmpl000066400000000000000000000000161453733615700310150ustar00rootroot00000000000000{{data.key1}} datatemplates-0.11.0/tests/testdata/test-nonexistent-source/000077500000000000000000000000001453733615700242435ustar00rootroot00000000000000datatemplates-0.11.0/tests/testdata/test-nonexistent-source/conf.py000066400000000000000000000001141453733615700255360ustar00rootroot00000000000000extensions = ["sphinxcontrib.datatemplates"] templates_path = ["templates"] datatemplates-0.11.0/tests/testdata/test-nonexistent-source/index.rst000066400000000000000000000000771453733615700261100ustar00rootroot00000000000000.. datatemplate:json:: sample1.json :template: sample.tmpl datatemplates-0.11.0/tests/testdata/test-nonexistent-source/sample.json000066400000000000000000000000411453733615700264120ustar00rootroot00000000000000{ "some_key": "some_value" } datatemplates-0.11.0/tests/testdata/test-nonexistent-source/templates/000077500000000000000000000000001453733615700262415ustar00rootroot00000000000000datatemplates-0.11.0/tests/testdata/test-nonexistent-source/templates/sample.tmpl000066400000000000000000000000221453733615700304120ustar00rootroot00000000000000{{data.some_key}} datatemplates-0.11.0/tests/testdata/test-nonexistent-template-filter/000077500000000000000000000000001453733615700260415ustar00rootroot00000000000000datatemplates-0.11.0/tests/testdata/test-nonexistent-template-filter/conf.py000066400000000000000000000001141453733615700273340ustar00rootroot00000000000000extensions = ["sphinxcontrib.datatemplates"] templates_path = ["templates"] datatemplates-0.11.0/tests/testdata/test-nonexistent-template-filter/index.rst000066400000000000000000000000761453733615700277050ustar00rootroot00000000000000.. datatemplate:json:: sample.json :template: sample.tmpl datatemplates-0.11.0/tests/testdata/test-nonexistent-template-filter/sample.json000066400000000000000000000000411453733615700302100ustar00rootroot00000000000000{ "some_key": "some_value" } datatemplates-0.11.0/tests/testdata/test-nonexistent-template-filter/templates/000077500000000000000000000000001453733615700300375ustar00rootroot00000000000000datatemplates-0.11.0/tests/testdata/test-nonexistent-template-filter/templates/sample.tmpl000066400000000000000000000000361453733615700322150ustar00rootroot00000000000000{{data.some_key|some_filter}} datatemplates-0.11.0/tests/testdata/test-nonexistent-template/000077500000000000000000000000001453733615700245565ustar00rootroot00000000000000datatemplates-0.11.0/tests/testdata/test-nonexistent-template/conf.py000066400000000000000000000001141453733615700260510ustar00rootroot00000000000000extensions = ["sphinxcontrib.datatemplates"] templates_path = ["templates"] datatemplates-0.11.0/tests/testdata/test-nonexistent-template/index.rst000066400000000000000000000000771453733615700264230ustar00rootroot00000000000000.. datatemplate:json:: sample.json :template: sample1.tmpl datatemplates-0.11.0/tests/testdata/test-nonexistent-template/sample.json000066400000000000000000000000411453733615700267250ustar00rootroot00000000000000{ "some_key": "some_value" } datatemplates-0.11.0/tests/testdata/test-nonexistent-template/templates/000077500000000000000000000000001453733615700265545ustar00rootroot00000000000000datatemplates-0.11.0/tests/testdata/test-nonexistent-template/templates/sample.tmpl000066400000000000000000000000221453733615700307250ustar00rootroot00000000000000{{data.some_key}} datatemplates-0.11.0/tox.ini000066400000000000000000000010371453733615700157530ustar00rootroot00000000000000[tox] envlist=py,linter,docs,pkglint [testenv] deps= .[test] commands= pytest tests [testenv:linter] deps= .[linter] commands= flake8 sphinxcontrib [testenv:pkglint] deps= .[build] check-python-versions commands= python -m build twine check dist/*.tar.gz check-python-versions --only pyproject.toml,.github/workflows/test.yml [flake8] show-source = True exclude = .tox,dist,doc,*.egg,build [testenv:docs] setenv = BUILD=docs commands= python -m sphinx.cmd.build -E -W -v -T doc/source doc/build