From c3bebeb62e56c78a3ea0ef076b8695fc78a5f064 Mon Sep 17 00:00:00 2001 From: Victor Cabezas Date: Mon, 21 Mar 2016 19:39:52 +0100 Subject: [PATCH 1/5] Added default Sphinx Docs --- doc/Makefile | 216 ++++++++++++++++++++++++++++++++++++++ doc/conf.py | 286 ++++++++++++++++++++++++++++++++++++++++++++++++++ doc/index.rst | 22 ++++ doc/make.bat | 263 ++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 787 insertions(+) create mode 100644 doc/Makefile create mode 100644 doc/conf.py create mode 100644 doc/index.rst create mode 100644 doc/make.bat diff --git a/doc/Makefile b/doc/Makefile new file mode 100644 index 0000000..56494eb --- /dev/null +++ b/doc/Makefile @@ -0,0 +1,216 @@ +# 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) . +# the i18n builder cannot share the environment and doctrees with the others +I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . + +.PHONY: help +help: + @echo "Please use \`make ' where is one of" + @echo " html to make standalone HTML files" + @echo " dirhtml to make HTML files named index.html in directories" + @echo " singlehtml to make a single large HTML file" + @echo " pickle to make pickle files" + @echo " json to make JSON files" + @echo " htmlhelp to make HTML files and a HTML help project" + @echo " qthelp to make HTML files and a qthelp project" + @echo " applehelp to make an Apple Help Book" + @echo " devhelp to make HTML files and a Devhelp project" + @echo " epub to make an epub" + @echo " 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)" + +.PHONY: clean +clean: + rm -rf $(BUILDDIR)/* + +.PHONY: html +html: + $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html + @echo + @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." + +.PHONY: dirhtml +dirhtml: + $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml + @echo + @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." + +.PHONY: singlehtml +singlehtml: + $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml + @echo + @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." + +.PHONY: pickle +pickle: + $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle + @echo + @echo "Build finished; now you can process the pickle files." + +.PHONY: json +json: + $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json + @echo + @echo "Build finished; now you can process the JSON files." + +.PHONY: htmlhelp +htmlhelp: + $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp + @echo + @echo "Build finished; now you can run HTML Help Workshop with the" \ + ".hhp project file in $(BUILDDIR)/htmlhelp." + +.PHONY: qthelp +qthelp: + $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp + @echo + @echo "Build finished; now you can run "qcollectiongenerator" with the" \ + ".qhcp project file in $(BUILDDIR)/qthelp, like this:" + @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/json2py.qhcp" + @echo "To view the help file:" + @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/json2py.qhc" + +.PHONY: applehelp +applehelp: + $(SPHINXBUILD) -b applehelp $(ALLSPHINXOPTS) $(BUILDDIR)/applehelp + @echo + @echo "Build finished. The help book is in $(BUILDDIR)/applehelp." + @echo "N.B. You won't be able to view it unless you put it in" \ + "~/Library/Documentation/Help or install it in your application" \ + "bundle." + +.PHONY: devhelp +devhelp: + $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp + @echo + @echo "Build finished." + @echo "To view the help file:" + @echo "# mkdir -p $$HOME/.local/share/devhelp/json2py" + @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/json2py" + @echo "# devhelp" + +.PHONY: epub +epub: + $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub + @echo + @echo "Build finished. The epub file is in $(BUILDDIR)/epub." + +.PHONY: latex +latex: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo + @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." + @echo "Run \`make' in that directory to run these through (pdf)latex" \ + "(use \`make latexpdf' here to do that automatically)." + +.PHONY: latexpdf +latexpdf: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo "Running LaTeX files through pdflatex..." + $(MAKE) -C $(BUILDDIR)/latex all-pdf + @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." + +.PHONY: latexpdfja +latexpdfja: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo "Running LaTeX files through platex and dvipdfmx..." + $(MAKE) -C $(BUILDDIR)/latex all-pdf-ja + @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." + +.PHONY: text +text: + $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text + @echo + @echo "Build finished. The text files are in $(BUILDDIR)/text." + +.PHONY: man +man: + $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man + @echo + @echo "Build finished. The manual pages are in $(BUILDDIR)/man." + +.PHONY: texinfo +texinfo: + $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo + @echo + @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." + @echo "Run \`make' in that directory to run these through makeinfo" \ + "(use \`make info' here to do that automatically)." + +.PHONY: info +info: + $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo + @echo "Running Texinfo files through makeinfo..." + make -C $(BUILDDIR)/texinfo info + @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." + +.PHONY: gettext +gettext: + $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale + @echo + @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." + +.PHONY: changes +changes: + $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes + @echo + @echo "The overview file is in $(BUILDDIR)/changes." + +.PHONY: linkcheck +linkcheck: + $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck + @echo + @echo "Link check complete; look for any errors in the above output " \ + "or in $(BUILDDIR)/linkcheck/output.txt." + +.PHONY: doctest +doctest: + $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest + @echo "Testing of doctests in the sources finished, look at the " \ + "results in $(BUILDDIR)/doctest/output.txt." + +.PHONY: coverage +coverage: + $(SPHINXBUILD) -b coverage $(ALLSPHINXOPTS) $(BUILDDIR)/coverage + @echo "Testing of coverage in the sources finished, look at the " \ + "results in $(BUILDDIR)/coverage/python.txt." + +.PHONY: xml +xml: + $(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml + @echo + @echo "Build finished. The XML files are in $(BUILDDIR)/xml." + +.PHONY: pseudoxml +pseudoxml: + $(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml + @echo + @echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml." diff --git a/doc/conf.py b/doc/conf.py new file mode 100644 index 0000000..d3ea49f --- /dev/null +++ b/doc/conf.py @@ -0,0 +1,286 @@ +# -*- coding: utf-8 -*- +# +# json2py documentation build configuration file, created by +# sphinx-quickstart on Mon Mar 21 19:36:55 2016. +# +# 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 sys +import os + +# 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.todo', + 'sphinx.ext.coverage', +] + +# 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'json2py' +copyright = u'2016, Víctor Cabezas' +author = u'Víctor Cabezas' + +# 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 = u'0.1' +# The full version, including alpha/beta/rc tags. +release = u'0.1a' + +# The language for content autogenerated by Sphinx. Refer to documentation +# for a list of supported languages. +# +# This is also used if you do content translation via gettext catalogs. +# Usually you set "language" from the command line for these cases. +language = None + +# There are two options for replacing |today|: either, you set today to some +# non-false value, then it is used: +#today = '' +# Else, today_fmt is used as the format for a strftime call. +#today_fmt = '%B %d, %Y' + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +exclude_patterns = ['_build'] + +# The reST default role (used for this markup: `text`) to use for all +# documents. +#default_role = None + +# If true, '()' will be appended to :func: etc. cross-reference text. +#add_function_parentheses = True + +# If true, the current module name will be prepended to all description +# unit titles (such as .. function::). +#add_module_names = True + +# If true, sectionauthor and moduleauthor directives will be shown in the +# output. They are ignored by default. +#show_authors = False + +# The name of the Pygments (syntax highlighting) style to use. +pygments_style = 'sphinx' + +# A list of ignored prefixes for module index sorting. +#modindex_common_prefix = [] + +# If true, keep warnings as "system message" paragraphs in the built documents. +#keep_warnings = False + +# If true, `todo` and `todoList` produce output, else they produce nothing. +todo_include_todos = True + + +# -- 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 (relative to this directory) to use as a favicon of +# the docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 +# pixels large. +#html_favicon = None + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +html_static_path = ['_static'] + +# Add any extra paths that contain custom files (such as robots.txt or +# .htaccess) here, relative to this directory. These files are copied +# directly to the root of the documentation. +#html_extra_path = [] + +# If not '', 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 = 'json2pydoc' + +# -- 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, 'json2py.tex', u'json2py Documentation', + u'Víctor Cabezas', '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, 'json2py', u'json2py 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, 'json2py', u'json2py Documentation', + author, 'json2py', 'One line description of project.', + 'Miscellaneous'), +] + +# Documents to append as an appendix to all manuals. +#texinfo_appendices = [] + +# If false, no module index is generated. +#texinfo_domain_indices = True + +# How to display URL addresses: 'footnote', 'no', or 'inline'. +#texinfo_show_urls = 'footnote' + +# If true, do not generate a @detailmenu in the "Top" node's menu. +#texinfo_no_detailmenu = False diff --git a/doc/index.rst b/doc/index.rst new file mode 100644 index 0000000..4a4af13 --- /dev/null +++ b/doc/index.rst @@ -0,0 +1,22 @@ +.. json2py documentation master file, created by + sphinx-quickstart on Mon Mar 21 19:36:55 2016. + You can adapt this file completely to your liking, but it should at least + contain the root `toctree` directive. + +Welcome to json2py's documentation! +=================================== + +Contents: + +.. toctree:: + :maxdepth: 2 + + + +Indices and tables +================== + +* :ref:`genindex` +* :ref:`modindex` +* :ref:`search` + diff --git a/doc/make.bat b/doc/make.bat new file mode 100644 index 0000000..ea0c481 --- /dev/null +++ b/doc/make.bat @@ -0,0 +1,263 @@ +@ECHO OFF + +REM Command file for Sphinx documentation + +if "%SPHINXBUILD%" == "" ( + set SPHINXBUILD=sphinx-build +) +set BUILDDIR=_build +set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% . +set I18NSPHINXOPTS=%SPHINXOPTS% . +if NOT "%PAPER%" == "" ( + set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS% + set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS% +) + +if "%1" == "" goto help + +if "%1" == "help" ( + :help + echo.Please use `make ^` where ^ is one of + echo. html to make standalone HTML files + echo. dirhtml to make HTML files named index.html in directories + echo. singlehtml to make a single large HTML file + echo. pickle to make pickle files + echo. json to make JSON files + echo. htmlhelp to make HTML files and a HTML help project + echo. qthelp to make HTML files and a qthelp project + echo. devhelp to make HTML files and a Devhelp project + echo. epub to make an epub + echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter + echo. text to make text files + echo. man to make manual pages + echo. texinfo to make Texinfo files + echo. gettext to make PO message catalogs + echo. changes to make an overview over all changed/added/deprecated items + echo. xml to make Docutils-native XML files + echo. pseudoxml to make pseudoxml-XML files for display purposes + echo. linkcheck to check all external links for integrity + echo. doctest to run all doctests embedded in the documentation if enabled + echo. coverage to run coverage check of the documentation if enabled + goto end +) + +if "%1" == "clean" ( + for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i + del /q /s %BUILDDIR%\* + goto end +) + + +REM Check if sphinx-build is available and fallback to Python version if any +%SPHINXBUILD% 1>NUL 2>NUL +if errorlevel 9009 goto sphinx_python +goto sphinx_ok + +:sphinx_python + +set SPHINXBUILD=python -m sphinx.__init__ +%SPHINXBUILD% 2> nul +if errorlevel 9009 ( + echo. + echo.The 'sphinx-build' command was not found. Make sure you have Sphinx + echo.installed, then set the SPHINXBUILD environment variable to point + echo.to the full path of the 'sphinx-build' executable. Alternatively you + echo.may add the Sphinx directory to PATH. + echo. + echo.If you don't have Sphinx installed, grab it from + echo.http://sphinx-doc.org/ + exit /b 1 +) + +:sphinx_ok + + +if "%1" == "html" ( + %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The HTML pages are in %BUILDDIR%/html. + goto end +) + +if "%1" == "dirhtml" ( + %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml. + goto end +) + +if "%1" == "singlehtml" ( + %SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml. + goto end +) + +if "%1" == "pickle" ( + %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle + if errorlevel 1 exit /b 1 + echo. + echo.Build finished; now you can process the pickle files. + goto end +) + +if "%1" == "json" ( + %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json + if errorlevel 1 exit /b 1 + echo. + echo.Build finished; now you can process the JSON files. + goto end +) + +if "%1" == "htmlhelp" ( + %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp + if errorlevel 1 exit /b 1 + echo. + echo.Build finished; now you can run HTML Help Workshop with the ^ +.hhp project file in %BUILDDIR%/htmlhelp. + goto end +) + +if "%1" == "qthelp" ( + %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp + if errorlevel 1 exit /b 1 + echo. + echo.Build finished; now you can run "qcollectiongenerator" with the ^ +.qhcp project file in %BUILDDIR%/qthelp, like this: + echo.^> qcollectiongenerator %BUILDDIR%\qthelp\json2py.qhcp + echo.To view the help file: + echo.^> assistant -collectionFile %BUILDDIR%\qthelp\json2py.ghc + goto end +) + +if "%1" == "devhelp" ( + %SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. + goto end +) + +if "%1" == "epub" ( + %SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The epub file is in %BUILDDIR%/epub. + goto end +) + +if "%1" == "latex" ( + %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex + if errorlevel 1 exit /b 1 + echo. + echo.Build finished; the LaTeX files are in %BUILDDIR%/latex. + goto end +) + +if "%1" == "latexpdf" ( + %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex + cd %BUILDDIR%/latex + make all-pdf + cd %~dp0 + echo. + echo.Build finished; the PDF files are in %BUILDDIR%/latex. + goto end +) + +if "%1" == "latexpdfja" ( + %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex + cd %BUILDDIR%/latex + make all-pdf-ja + cd %~dp0 + echo. + echo.Build finished; the PDF files are in %BUILDDIR%/latex. + goto end +) + +if "%1" == "text" ( + %SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The text files are in %BUILDDIR%/text. + goto end +) + +if "%1" == "man" ( + %SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The manual pages are in %BUILDDIR%/man. + goto end +) + +if "%1" == "texinfo" ( + %SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo. + goto end +) + +if "%1" == "gettext" ( + %SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The message catalogs are in %BUILDDIR%/locale. + goto end +) + +if "%1" == "changes" ( + %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes + if errorlevel 1 exit /b 1 + echo. + echo.The overview file is in %BUILDDIR%/changes. + goto end +) + +if "%1" == "linkcheck" ( + %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck + if errorlevel 1 exit /b 1 + echo. + echo.Link check complete; look for any errors in the above output ^ +or in %BUILDDIR%/linkcheck/output.txt. + goto end +) + +if "%1" == "doctest" ( + %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest + if errorlevel 1 exit /b 1 + echo. + echo.Testing of doctests in the sources finished, look at the ^ +results in %BUILDDIR%/doctest/output.txt. + goto end +) + +if "%1" == "coverage" ( + %SPHINXBUILD% -b coverage %ALLSPHINXOPTS% %BUILDDIR%/coverage + if errorlevel 1 exit /b 1 + echo. + echo.Testing of coverage in the sources finished, look at the ^ +results in %BUILDDIR%/coverage/python.txt. + goto end +) + +if "%1" == "xml" ( + %SPHINXBUILD% -b xml %ALLSPHINXOPTS% %BUILDDIR%/xml + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The XML files are in %BUILDDIR%/xml. + goto end +) + +if "%1" == "pseudoxml" ( + %SPHINXBUILD% -b pseudoxml %ALLSPHINXOPTS% %BUILDDIR%/pseudoxml + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The pseudo-XML files are in %BUILDDIR%/pseudoxml. + goto end +) + +:end From 6210ca62f12ebe9fd7fcd40db826c6f72d18f155 Mon Sep 17 00:00:00 2001 From: Victor Cabezas Date: Mon, 21 Mar 2016 21:54:54 +0100 Subject: [PATCH 2/5] Committed first revision of docs, fixed some code styling. --- doc/Changelog.rst | 4 ++ doc/conf.py | 7 +++- doc/doc_coverage.rst | 29 +++++++++++++ doc/examples.rst | 6 +++ doc/exceptions.rst | 10 +++++ doc/index.rst | 9 ++++ doc/models.rst | 97 ++++++++++++++++++++++++++++++++++++++++++++ json2py/models.py | 92 +++++++++++++++++++++++++++++++++++++++-- 8 files changed, 249 insertions(+), 5 deletions(-) create mode 100644 doc/Changelog.rst create mode 100644 doc/doc_coverage.rst create mode 100644 doc/examples.rst create mode 100644 doc/exceptions.rst create mode 100644 doc/models.rst diff --git a/doc/Changelog.rst b/doc/Changelog.rst new file mode 100644 index 0000000..ccad2d7 --- /dev/null +++ b/doc/Changelog.rst @@ -0,0 +1,4 @@ +.. + +Changelog +=================== diff --git a/doc/conf.py b/doc/conf.py index d3ea49f..a518d04 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -31,6 +31,9 @@ extensions = [ 'sphinx.ext.todo', 'sphinx.ext.coverage', + 'sphinx.ext.autodoc', + 'sphinx.ext.viewcode', + 'sphinx.ext.intersphinx' ] # Add any paths that contain templates here, relative to this directory. @@ -110,7 +113,7 @@ # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. -html_theme = 'alabaster' +html_theme = 'sphinx_rtd_theme' # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the @@ -284,3 +287,5 @@ # If true, do not generate a @detailmenu in the "Top" node's menu. #texinfo_no_detailmenu = False + +intersphinx_mapping = {'python': ('https://docs.python.org/2.7', None)} \ No newline at end of file diff --git a/doc/doc_coverage.rst b/doc/doc_coverage.rst new file mode 100644 index 0000000..c5d16e8 --- /dev/null +++ b/doc/doc_coverage.rst @@ -0,0 +1,29 @@ +.. _doc_coverage: + +Documentation coverage +====================== + +json2py.models +-------------- +Classes: + * BaseField -- missing methods: + + - parse + * ListField -- missing methods: + + - append + - count + - extend + - index + - insert + - parse + - pop + - remove + - reverse + - sort + * NestedField -- missing methods: + + - items + - parse + * NumberField + diff --git a/doc/examples.rst b/doc/examples.rst new file mode 100644 index 0000000..4a4a9b2 --- /dev/null +++ b/doc/examples.rst @@ -0,0 +1,6 @@ +.. _examples: + +Examples +======== + +Coming next! \ No newline at end of file diff --git a/doc/exceptions.rst b/doc/exceptions.rst new file mode 100644 index 0000000..a39b051 --- /dev/null +++ b/doc/exceptions.rst @@ -0,0 +1,10 @@ +.. + +Exceptions +==================== + +.. py:module:: json2py.models + +ParseException +-------------- +.. autoclass:: ParseException \ No newline at end of file diff --git a/doc/index.rst b/doc/index.rst index 4a4af13..87cc481 100644 --- a/doc/index.rst +++ b/doc/index.rst @@ -6,11 +6,20 @@ Welcome to json2py's documentation! =================================== +The goal of this module is to map plain ``json`` strings and ``json.loads`` structures into +Python objects. + Contents: +--------- .. toctree:: :maxdepth: 2 + models + exceptions + examples + Changelog + doc_coverage Indices and tables diff --git a/doc/models.rst b/doc/models.rst new file mode 100644 index 0000000..a35eaa0 --- /dev/null +++ b/doc/models.rst @@ -0,0 +1,97 @@ +.. _models: + + +Usage +===== + +.. note:: For extended and more in depth examples, refer to :ref:`examples` + +The following example illustrates how this module works. + +.. code-block:: python + :linenos: + + from json2py.models import * + class Example(NestedField): + hello = TextField(name = 'hi') + integer = IntegerField() + floating = FloatField() + + class ExampleList(ListField): + __model__ = Example + + dict_var = {'hi': 'world', 'integer': 1000, 'floating': 10.5, 'ignored': "you won't see me"} + list_var = [dict_var] * 3 + + myMappedList = ExampleList(list_var) + + print myMappedList.json_encode(indent = 4) + +Should return something like: + +.. code-block:: json + + [ + { + "integer": 1000, + "floating": 10.5, + "hello": "world" + }, + { + "integer": 1000, + "floating": 10.5, + "hello": "world" + }, + { + "integer": 1000, + "floating": 10.5, + "hello": "world" + } + ] + +Models +______ + +.. note:: The classes of this modules are intended to be reimplemented in order to make use of this module. + +Models represent basic JSON data types. The usage of this models is intended +to be subclassed in order to fully map the original JSON structure. + +.. py:module:: json2py.models + +BaseField +--------- + +.. autoclass:: BaseField + :members: + +TextField +--------- + +.. autoclass:: TextField + :members: + +IntegerField +------------ + +.. autoclass:: IntegerField + :members: + + +FloatField +---------- + +.. autoclass:: FloatField + :members: + +NestedField +----------- + +.. autoclass:: NestedField + :members: + +ListField +--------- + +.. autoclass:: ListField + :members: diff --git a/json2py/models.py b/json2py/models.py index 8a7fde5..64cc42d 100644 --- a/json2py/models.py +++ b/json2py/models.py @@ -3,22 +3,52 @@ __author__ = 'Victor' -class ParseException(Exception): pass +class ParseException(Exception): + """ + Exception raised when an error occur trying to parse data on any + of :class:`.BaseField` subclasses. + """ + pass class BaseField(object): + """ + Base Class holding and defining common features for all the other subclasses. + + :arg name: Name of the field in source data. + :note: This class must be treated as abstract class and should not be reimplemented. + """ def __init__(self, **kwargs): + """ + :class:`.BaseField` constructor + :param name: Name of the field in source data. + """ self.name = kwargs.get('name', None) def json_encode(self, **kwargs): + """ + Converts an object of class :class:`.BaseField` into JSON representation (string) + using :class:`.BaseEncoder` JSONEncoder. + + :param kwargs: Parameters passed to :py:func:`json.dumps` + :return: JSON-string representation of this object. + """ kwargs.pop('cls', None) return json.dumps(self, cls = BaseEncoder, **kwargs) def json_decode(self, data, **kwargs): + """ + Parses a JSON-string into this object. This method is intended to build + the JSON to Object map, so it doesn't return any value, instead, the object + is built into self. + + :param data: JSON-string passed to :py:func:`json.loads` + :param kwargs: Parameters passed to :py:func:`json.loads` + """ kwargs.pop('object_hook', None) - json.loads(data, object_hook = self._dictToObj, **kwargs) + json.loads(data, object_hook = self._dict_to_obj, **kwargs) - def _dictToObj(self, d): + def _dict_to_obj(self, d): self.__init__(d) @staticmethod @@ -26,7 +56,15 @@ def parse(data, cls): obj = cls(data) return obj + class TextField(BaseField): + """ + Class representing a string field in JSON. + + :arg name: It has the same meaning as in :class:`.BaseField` + :arg value: It is the raw data that is this object will represent once parsed. + :raise ParseException: If ``value`` is not a string nor None + """ def __init__(self, *args, **kwargs): super(TextField, self).__init__(**kwargs) self.value = args[0] if len(args) > 0 else kwargs.get('value') @@ -34,11 +72,24 @@ def __init__(self, *args, **kwargs): if not isinstance(self.value, (str, unicode)) and self.value is not None: raise ParseException('TextField cannot parse non string') + class NumberField(BaseField): + """ + Abstract class for representing JSON numbers. + It really does nothing + """ def __init__(self, *args, **kwargs): super(NumberField, self).__init__(**kwargs) + class IntegerField(NumberField): + """ + Class representing an integer field in JSON. + + :arg name: It has the same meaning as in :class:`.BaseField` + :arg value: It is the raw data that is this object will represent once parsed. + :raise ParseException: If ``value`` is not a integer nor None + """ def __init__(self, *args, **kwargs): super(NumberField, self).__init__(**kwargs) self.value = args[0] if len(args) > 0 else kwargs.get('value') @@ -46,7 +97,15 @@ def __init__(self, *args, **kwargs): if not isinstance(self.value, (int, long)) and self.value is not None: raise ParseException('IntegerField cannot parse non integer') + class FloatField(NumberField): + """ + Class representing a float field in JSON. + + :arg name: It has the same meaning as in :class:`.BaseField` + :arg value: It is the raw data that is this object will represent once parsed. + :raise ParseException: If ``value`` is not a float nor None + """ def __init__(self, *args, **kwargs): super(NumberField, self).__init__(**kwargs) self.value = args[0] if len(args) > 0 else kwargs.get('value') @@ -54,7 +113,15 @@ def __init__(self, *args, **kwargs): if not isinstance(self.value, (float, int, long)) and self.value is not None: raise ParseException('FloatField cannot parse non float') + class NestedField(BaseField): + """ + Class representing a document field in JSON. + + :arg name: It has the same meaning as in :class:`.BaseField` + :arg value: It is the raw data that is this object will represent once parsed. + :raise ParseException: If ``value`` is not a dict nor None + """ def __init__(self, *args, **kwargs): super(NestedField, self).__setattr__('value', {}) super(NestedField, self).__setattr__('name', kwargs.get('name', None)) @@ -111,6 +178,23 @@ def items(self): return super(NestedField, self).__getattribute__('value').items() class ListField(BaseField): + """ + Class representing a list field in JSON. This class implements :mod:`list` interface so you + can slicing, appending, popping, etc. + + :arg name: It has the same meaning as in :class:`.BaseField` + :arg value: It is the raw data that is this object will represent once parsed. + :raise ParseException: If ``value`` is not a list nor None + + :note: Hinting the structure of values of the list should be done using the meta variable :attr:`__model__` + inside class reimplementation. + + :note: JSON lists' values can be of any type even in the same list, but + in real world apps, every JSON lists' values should be of the same type, this + behaviour also simplifies this module, so this class expects that all values in + lists must have the same structure. + + """ def __init__(self, value = None, *args, **kwargs): super(ListField, self).__init__(**kwargs) @@ -130,7 +214,7 @@ def __init__(self, value = None, *args, **kwargs): self.value = [elementClass(d) for d in value] if value is not None else [] - def _dictToObj(self, d): + def _dict_to_obj(self, d): self.value.append(self.__model__(d)) return self.value[-1] From 80fe14287e996a32696c474fc2b9d1b5d4335970 Mon Sep 17 00:00:00 2001 From: Victor Cabezas Date: Mon, 21 Mar 2016 23:15:45 +0100 Subject: [PATCH 3/5] Added setup.py to repository --- setup.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 setup.py diff --git a/setup.py b/setup.py new file mode 100644 index 0000000..de0bfa0 --- /dev/null +++ b/setup.py @@ -0,0 +1,12 @@ +from distutils.core import setup + +setup( + name = 'json2py', + version = '0.1', + packages = ['json2py'], + url = 'https://github.com/Wiston999/json2py', + license = '', + author = 'Victor Cabezas', + author_email = 'wiston666@gmail.com', + description = 'Convert JSON/dict to python object and viceversa' +) From 027e38fcb7b437251555bfe281ea5041abcb6577 Mon Sep 17 00:00:00 2001 From: Victor Cabezas Date: Tue, 22 Mar 2016 22:16:42 +0100 Subject: [PATCH 4/5] Improved simple example. Added todo to NestedField documentation. --- doc/conf.py | 2 +- doc/models.rst | 9 ++++++++- json2py/models.py | 7 +++++++ 3 files changed, 16 insertions(+), 2 deletions(-) diff --git a/doc/conf.py b/doc/conf.py index a518d04..9ba62ff 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -18,7 +18,7 @@ # 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('.')) +sys.path.insert(0, os.path.abspath('..')) # -- General configuration ------------------------------------------------ diff --git a/doc/models.rst b/doc/models.rst index a35eaa0..1710f33 100644 --- a/doc/models.rst +++ b/doc/models.rst @@ -25,11 +25,14 @@ The following example illustrates how this module works. myMappedList = ExampleList(list_var) + myMappedList[1].integer.value = 1234 + print myMappedList.json_encode(indent = 4) Should return something like: .. code-block:: json + :emphasize-lines: 8 [ { @@ -38,7 +41,7 @@ Should return something like: "hello": "world" }, { - "integer": 1000, + "integer": 1234, "floating": 10.5, "hello": "world" }, @@ -84,6 +87,10 @@ FloatField .. autoclass:: FloatField :members: +.. todo:: + + Document how to access elements in :class:`.NestedField` with same name than Python's reserved keywords. + NestedField ----------- diff --git a/json2py/models.py b/json2py/models.py index 64cc42d..6e83bc1 100644 --- a/json2py/models.py +++ b/json2py/models.py @@ -118,6 +118,7 @@ class NestedField(BaseField): """ Class representing a document field in JSON. + :arg name: It has the same meaning as in :class:`.BaseField` :arg value: It is the raw data that is this object will represent once parsed. :raise ParseException: If ``value`` is not a dict nor None @@ -169,6 +170,12 @@ def __getattribute__(self, item): else: raise AttributeError(item) + def __getitem__(self, item): + return self.__getattribute__(item) + + def __setitem__(self, key, value): + self.__setattr__(key, value) + @staticmethod def parse(data, cls): obj = cls(data) From 331a54845eaf00277efa3630ae73f82cae30a3f0 Mon Sep 17 00:00:00 2001 From: Victor Cabezas Date: Wed, 23 Mar 2016 21:48:21 +0100 Subject: [PATCH 5/5] Added BooleanField. Added example.py file. Updated tests. Added examples to docs. --- doc/Changelog.rst | 1 + doc/doc_coverage.rst | 3 - doc/examples.rst | 226 ++++++++++++++++++++++++++++++++++++++++++- doc/index.rst | 4 +- doc/models.rst | 7 ++ example.py | 67 +++++++++++++ json2py/models.py | 39 ++++++-- tests.py | 34 +++++++ 8 files changed, 365 insertions(+), 16 deletions(-) create mode 100644 example.py diff --git a/doc/Changelog.rst b/doc/Changelog.rst index ccad2d7..4254de5 100644 --- a/doc/Changelog.rst +++ b/doc/Changelog.rst @@ -2,3 +2,4 @@ Changelog =================== +* **0.1**: First version, base implementation done. Added docs and tests. \ No newline at end of file diff --git a/doc/doc_coverage.rst b/doc/doc_coverage.rst index c5d16e8..71f3fc3 100644 --- a/doc/doc_coverage.rst +++ b/doc/doc_coverage.rst @@ -6,9 +6,6 @@ Documentation coverage json2py.models -------------- Classes: - * BaseField -- missing methods: - - - parse * ListField -- missing methods: - append diff --git a/doc/examples.rst b/doc/examples.rst index 4a4a9b2..f470eb1 100644 --- a/doc/examples.rst +++ b/doc/examples.rst @@ -3,4 +3,228 @@ Examples ======== -Coming next! \ No newline at end of file +In the examples below, we will try to learn how to model JSON with :mod:`json2py`'. +We will cover how to re-utilize models into bigger ones, like JSON support sub-documents. +We will also learn how to model a list of JSON documents. + +Modeling Github API +------------------- + +For the examples we will try to model Github's public API (or at least a part of it). +We will be model the *user* response from https://api.github.com/users/{user} +using my user account, we will model this *repo* information on https://api.github.com/users/{user}/{repo_name} +And with a bit more effort we will model the *repo* listing on +https://api.github.com/users/{user}/repos. In this example, :mod:`requests` +module will be used for simplicity, but the way of requesting remote resources is up to you. + +Let's begin! + +User modelling +______________ + +The user data used on this example will be extracted from https://api.github.com/users/wiston999 + +Let's suppose we want to grab the user's id, login, url, type and if user is admin. +This task can be done with the following code. + +We will map the *type* key into a field named *user_type* into our model. + +.. code-block:: python + :linenos: + :caption: models.py + :name: models.py + + from json2py.models import * + + class User(NestedField): + login = TextField() + id = IntegerField() + url = TextField() + user_type = TextField(name = 'type') + site_admin = BooleanField() + +And we are all done! Now let's request the Github's user info endpoint. + +.. code-block:: python + :linenos: + :caption: example1.py + :name: example1.py + + import requests + from models import User + + response = requests.get('https://api.github.com/users/wiston999') + my_user = User(response.json()) + print my_user.login.value, "'s stats:" + print "id:", my_user.id.value + print "login:", my_user.login.value + print "url:", my_user.url.value + print "type:", my_user.user_type.value + print "site_admin:", my_user.site_admin.value + +Output after executing this code is + +.. code-block:: text + + Wiston999 's stats: + id: 1099504 + login: Wiston999 + url: https://api.github.com/users/Wiston999 + type: User + site_admin: False + +This is how modeling works, all you have to do is define class variables into +the class inheriting from :class:`json2py.models.NestedField`. + +Repository modeling +___________________ +The next step will be modeling a repository information from Github. +We will use the information from this repository, https://api.github.com/repos/wiston999/json2py. +We want to get the id, name, full_name, is_private, description, size, language, default_branch +and the owner fields. One can notice that owner nested document looks familiar, as it shares several fields +with the data on https://api.github.com/users/wiston999. We notice too that shared data is +already modeled into the previous example, so, let's use a bit of code re-utilization. + +.. code-block:: python + :linenos: + :caption: models.py + :name: models.py + :emphasize-lines: 8- + + class User(NestedField): + login = TextField() + id = IntegerField() + url = TextField() + user_type = TextField(name = 'type') + site_admin = BooleanField() + + class Repo(NestedField): + id = IntegerField() + name = TextField() + full_name = TextField() + owner = User() + is_private = BooleanField(name = 'private') + description = TextField() + size = IntegerField() + language = TextField() + default_branch = TextField() + +Notice how the **owner** field is an instance of **User** class defined above. + +Let's try these models + +.. code-block:: python + :linenos: + :caption: example2.py + :name: example2.py + :emphasize-lines: 9 + + import requests + from models import User, Repo + + response = requests.get('https://api.github.com/repos/wiston999/json2py') + this_repo = Repo(response.json()) + print this_repo.name.value, "'s stats:" + print "id:", this_repo.id.value + print "full_name:", this_repo.full_name.value + print "owner:", this_repo.owner.login.value + print "private:", this_repo.is_private.value + print "description:", this_repo.description.value + print "language:", this_repo.language.value + print "default_branch:", this_repo.default_branch.value + +Will output + +.. code-block:: text + + json2py 's stats: + id: 54333024 + full_name: Wiston999/json2py + owner: Wiston999 + private: False + description: Convert JSON/dict to python object and viceversa + language: Python + default_branch: master + +Repository list modeling +________________________ + +As a last example, lest loop the loop, we are going to model the data +returned by https://api.github.com/users/Wiston999/repos request. We see that this is +a list of repositories, which we have already modeled, so, this should be as simple as + +.. code-block:: python + :linenos: + :caption: models.py + :name: models.py + :emphasize-lines: 19- + + class User(NestedField): + login = TextField() + id = IntegerField() + url = TextField() + user_type = TextField(name = 'type') + site_admin = BooleanField() + + class Repo(NestedField): + id = IntegerField() + name = TextField() + full_name = TextField() + owner = User() + is_private = BooleanField(name = 'private') + description = TextField() + size = IntegerField() + language = TextField() + default_branch = TextField() + + class RepoList(ListField): + __model__ = Repo + +Everything done! Let's try it + +.. code-block:: python + :linenos: + :caption: example3.py + :name: example3.py + :emphasize-lines: 9 + + import requests + from models import RepoList + + response = requests.get('https://api.github.com/users/wiston999/repos') + user_repo_list = RepoList(response.json()) + print "wiston999's repositories:" + for repo in user_repo_list: + print "Repository name:", repo.name.value, "with id:", repo.id.value, "written in", repo.language.value + print "Repository Owner:", repo.owner.login.value + print '-'*70 + +And the output + +.. code-block:: text + + wiston999 repositories: + Repository name: BRTMT with id: 24468609 written in JavaScript + Repository Owner: Wiston999 + ---------------------------------------------------------------------- + Repository name: cursoJS with id: 14053600 written in JavaScript + Repository Owner: Wiston999 + ---------------------------------------------------------------------- + Repository name: DDSBox with id: 36035006 written in Java + Repository Owner: Wiston999 + ---------------------------------------------------------------------- + Repository name: DSS with id: 20038644 written in Python + Repository Owner: Wiston999 + ---------------------------------------------------------------------- + Repository name: ISIII with id: 3630135 written in None + Repository Owner: Wiston999 + ---------------------------------------------------------------------- + Repository name: json2py with id: 54333024 written in Python + Repository Owner: Wiston999 + ---------------------------------------------------------------------- + Repository name: Plataforma with id: 2506501 written in Python + Repository Owner: Wiston999 + ---------------------------------------------------------------------- + Repository name: repos-git with id: 20038280 written in Python + Repository Owner: Wiston999 + ---------------------------------------------------------------------- diff --git a/doc/index.rst b/doc/index.rst index 87cc481..37ee7c1 100644 --- a/doc/index.rst +++ b/doc/index.rst @@ -13,14 +13,12 @@ Contents: --------- .. toctree:: - :maxdepth: 2 + :maxdepth: 3 models exceptions examples Changelog - doc_coverage - Indices and tables ================== diff --git a/doc/models.rst b/doc/models.rst index 1710f33..aba2665 100644 --- a/doc/models.rst +++ b/doc/models.rst @@ -87,6 +87,13 @@ FloatField .. autoclass:: FloatField :members: +BooleanField +------------ + +.. autoclass:: BooleanField + :members: + + .. todo:: Document how to access elements in :class:`.NestedField` with same name than Python's reserved keywords. diff --git a/example.py b/example.py new file mode 100644 index 0000000..4a20919 --- /dev/null +++ b/example.py @@ -0,0 +1,67 @@ +import requests +from json2py.models import * + +__author__ = 'Victor' + +class User(NestedField): + login = TextField() + id = IntegerField() + url = TextField() + user_type = TextField(name = 'type') + site_admin = BooleanField() + +class Repo(NestedField): + id = IntegerField() + name = TextField() + full_name = TextField() + owner = User() + is_private = BooleanField(name = 'private') + description = TextField() + size = IntegerField() + language = TextField() + default_branch = TextField() + + +class RepoList(ListField): + __model__ = Repo + + +github_user = 'wiston999' +github_repo = 'json2py' + +response = requests.get('https://api.github.com/users/%s' % github_user) +if response.status_code == 200: + my_user = User(response.json()) + print my_user.login.value, "'s stats:" + print "id:", my_user.id.value + print "login:", my_user.login.value + print "url:", my_user.url.value + print "type:", my_user.user_type.value + print "site_admin:", my_user.site_admin.value +else: + print "User response status code", response.status_code + +response = requests.get('https://api.github.com/repos/%s/%s' %(github_user, github_repo)) +if response.status_code == 200: + this_repo = Repo(response.json()) + print this_repo.name.value, "'s stats:" + print "id:", this_repo.id.value + print "full_name:", this_repo.full_name.value + print "owner:", this_repo.owner.login.value + print "private:", this_repo.is_private.value + print "description:", this_repo.description.value + print "language:", this_repo.language.value + print "default_branch:", this_repo.default_branch.value +else: + print "Repo response status code", response.status_code + +response = requests.get('https://api.github.com/users/%s/repos' % github_user) +if response.status_code == 200: + user_repo_list = RepoList(response.json()) + print github_user, "repositories:" + for repo in user_repo_list: + print "Repository name:", repo.name.value, "with id:", repo.id.value, "written in", repo.language.value + print "Repository Owner:", repo.owner.login.value + print '-'*70 +else: + print "RepoList response status code", response.status_code \ No newline at end of file diff --git a/json2py/models.py b/json2py/models.py index 6e83bc1..eeca7e7 100644 --- a/json2py/models.py +++ b/json2py/models.py @@ -51,11 +51,27 @@ def json_decode(self, data, **kwargs): def _dict_to_obj(self, d): self.__init__(d) - @staticmethod - def parse(data, cls): - obj = cls(data) - return obj +class BooleanField(BaseField): + """ + Class representing boolean field in JSON. + + :arg name: It has the same meaning as in :class:`.BaseField` + :arg value: It is the raw data that is this object will represent once parsed. + :raise `ParseException`: If ``value`` is not boolean nor None + """ + def __init__(self, *args, **kwargs): + super(BooleanField, self).__init__(**kwargs) + self.value = args[0] if len(args) > 0 else kwargs.get('value') + + if not isinstance(self.value, bool) and self.value is not None: + raise ParseException('BooleanField cannot parse non bool') + + def __str__(self): + return str(self.value) + + def __repr__(self): + return self.__str__() class TextField(BaseField): """ @@ -72,6 +88,11 @@ def __init__(self, *args, **kwargs): if not isinstance(self.value, (str, unicode)) and self.value is not None: raise ParseException('TextField cannot parse non string') + def __str__(self): + return str(self.value) ## Use str() to avoid None's + + def __repr__(self): + return self.__str__() class NumberField(BaseField): """ @@ -81,6 +102,11 @@ class NumberField(BaseField): def __init__(self, *args, **kwargs): super(NumberField, self).__init__(**kwargs) + def __str__(self): + return str(self.value) + + def __repr__(self): + return self.__str__() class IntegerField(NumberField): """ @@ -225,11 +251,6 @@ def _dict_to_obj(self, d): self.value.append(self.__model__(d)) return self.value[-1] - @staticmethod - def parse(data, cls): - obj = cls(data) - return obj - def append(self, x): return self.value.append(x) diff --git a/tests.py b/tests.py index 632ba09..559c5c9 100644 --- a/tests.py +++ b/tests.py @@ -18,6 +18,38 @@ class NestedObjTest(NestedField): class ListObjTest(ListField): __model__ = NestedObjTest +class NoneTest(unittest.TestCase): + def test_value(self): + self.assertEqual(TextField(None).value, None) + self.assertEqual(IntegerField(None).value, None) + self.assertEqual(FloatField(None).value, None) + self.assertEqual(NestedField(None).value, {}) + self.assertEqual(len(ListObjTest(None)), 0) + + def test_encode(self): + self.assertEqual(TextField(None).json_encode(), "null") + self.assertEqual(IntegerField(None).json_encode(), "null") + self.assertEqual(FloatField(None).json_encode(), "null") + self.assertEqual(NestedField(None).json_encode(), "{}") + self.assertEqual(ListObjTest(None).json_encode(), "[]") + + def test_decode(self): + t = TextField(None) + t.json_decode("null") + self.assertEqual(t.value, None) + t = IntegerField(None) + t.json_decode("null") + self.assertEqual(t.value, None) + t = FloatField(None) + t.json_decode("null") + self.assertEqual(t.value, None) + t = NestedField(None) + t.json_decode("null") + self.assertEqual(t.value, {}) + t = ListObjTest(None) + t.json_decode("null") + self.assertEqual(t.value, []) + class TextTest(unittest.TestCase): def test_init(self): @@ -32,6 +64,8 @@ def test_encode(self): self.assertEqual(TextField("aBc").json_encode(), '"aBc"') self.assertEqual(TextField("5").json_encode(), '"5"') + self.assertEqual(TextField(None).json_encode(), 'null') + class IntegerTest(unittest.TestCase): def test_init(self):