From 0b9694df5ff070b8075f1c391ac44be6e8104896 Mon Sep 17 00:00:00 2001 From: "STATION\\mf" Date: Thu, 27 Aug 2020 17:48:59 -0400 Subject: [PATCH 1/5] feat: Introduced `docs` target --- .gitignore | 3 + docs/README.rst | 1 + docs/_static/custom.css | 4 + docs/api-reference.rst | 4 + docs/changelog.md | 1 + docs/conf.py | 369 ++++++++++++++++++++++++++++++++++++++ docs/connection-usage.rst | 32 ++++ docs/index.rst | 27 +++ noxfile.py | 23 +++ 9 files changed, 464 insertions(+) create mode 100644 docs/README.rst create mode 100644 docs/_static/custom.css create mode 100644 docs/api-reference.rst create mode 100644 docs/changelog.md create mode 100644 docs/conf.py create mode 100644 docs/connection-usage.rst create mode 100644 docs/index.rst diff --git a/.gitignore b/.gitignore index 863e1d3d77..0b5859361d 100644 --- a/.gitignore +++ b/.gitignore @@ -14,3 +14,6 @@ django_tests # JetBrains .idea + +# Built documentation +docs/_build diff --git a/docs/README.rst b/docs/README.rst new file mode 100644 index 0000000000..32d46ee883 --- /dev/null +++ b/docs/README.rst @@ -0,0 +1 @@ +../README.md \ No newline at end of file diff --git a/docs/_static/custom.css b/docs/_static/custom.css new file mode 100644 index 0000000000..9a6f9f8ddc --- /dev/null +++ b/docs/_static/custom.css @@ -0,0 +1,4 @@ +div#python2-eol { + border-color: red; + border-width: medium; +} \ No newline at end of file diff --git a/docs/api-reference.rst b/docs/api-reference.rst new file mode 100644 index 0000000000..593383df41 --- /dev/null +++ b/docs/api-reference.rst @@ -0,0 +1,4 @@ +API Reference +============= + +[The following classes and methods constitute the Spanner DB API connection.] diff --git a/docs/changelog.md b/docs/changelog.md new file mode 100644 index 0000000000..825c32f0d0 --- /dev/null +++ b/docs/changelog.md @@ -0,0 +1 @@ +# Changelog diff --git a/docs/conf.py b/docs/conf.py new file mode 100644 index 0000000000..a8e6d35cce --- /dev/null +++ b/docs/conf.py @@ -0,0 +1,369 @@ +# -*- coding: utf-8 -*- +# +# Copyright 2020 Google LLC +# +# Use of this source code is governed by a BSD-style +# license that can be found in the LICENSE file or at +# https://developers.google.com/open-source/licenses/bsd + +# google-cloud-spanner documentation build configuration file +# +# 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("..")) + +# For plugins that can not read conf.py. +# See also: https://github.com/docascode/sphinx-docfx-yaml/issues/85 +sys.path.insert(0, os.path.abspath(".")) + +__version__ = "" + +# -- General configuration ------------------------------------------------ + +# If your documentation needs a minimal Sphinx version, state it here. +needs_sphinx = "1.6.3" + +# Add any Sphinx extension module names here, as strings. They can be +# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom +# ones. +extensions = [ + "sphinx.ext.autodoc", + "sphinx.ext.autosummary", + "sphinx.ext.intersphinx", + "sphinx.ext.coverage", + "sphinx.ext.napoleon", + "sphinx.ext.todo", + "sphinx.ext.viewcode", + "recommonmark", +] + +# autodoc/autosummary flags +autoclass_content = "both" +autodoc_default_options = {"members": True} +autosummary_generate = True + + +# 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", ".md"] + +# The encoding of source files. +# source_encoding = 'utf-8-sig' + +# The master toctree document. +master_doc = "index" + +# General information about the project. +project = u"google-cloud-spanner-django" +copyright = u"2020, Google" +author = u"Google APIs" + +# 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 full version, including alpha/beta/rc tags. +release = __version__ +# The short X.Y version. +version = ".".join(release.split(".")[0:2]) + +# 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", + "samples/AUTHORING_GUIDE.md", + "samples/CONTRIBUTING.md", + "samples/snippets/README.md", +] + +# 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 = { + "description": "Google Cloud Client Libraries for google-cloud-spanner", + "github_user": "googleapis", + "github_repo": "python-spanner-django", + "github_banner": True, + "font_family": "'Roboto', Georgia, sans", + "head_font_family": "'Roboto', Georgia, serif", + "code_font_family": "'Roboto Mono', 'Consolas', monospace", +} + +# 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 = "google-cloud-spanner-django-doc" + +# -- Options for warnings ------------------------------------------------------ + + +suppress_warnings = [ + # Temporarily suppress this to avoid "more than one target found for + # cross-reference" warning, which are intractable for us to avoid while in + # a mono-repo. + # See https://github.com/sphinx-doc/sphinx/blob + # /2a65ffeef5c107c19084fabdd706cdff3f52d93c/sphinx/domains/python.py#L843 + "ref.python" +] + +# -- 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, + "google-cloud-spanner-django.tex", + u"google-cloud-spanner-django Documentation", + author, + "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, + "google-cloud-spanner-django", + u"google-cloud-spanner-django 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, + "google-cloud-spanner-django", + u"google-cloud-spanner-django Documentation", + author, + "google-cloud-spanner-django", + "google-cloud-spanner-django Library", + "APIs", + ) +] + +# Documents to append as an appendix to all manuals. +# texinfo_appendices = [] + +# If false, no module index is generated. +# texinfo_domain_indices = True + +# How to display URL addresses: 'footnote', 'no', or 'inline'. +# texinfo_show_urls = 'footnote' + +# If true, do not generate a @detailmenu in the "Top" node's menu. +# texinfo_no_detailmenu = False + + +# Example configuration for intersphinx: refer to the Python standard library. +intersphinx_mapping = { + "python": ("http://python.readthedocs.org/en/latest/", None), + "google-auth": ("https://google-auth.readthedocs.io/en/stable", None), + "google.api_core": ("https://googleapis.dev/python/google-api-core/latest/", None), + "grpc": ("https://grpc.io/grpc/python/", None), +} + + +# Napoleon settings +napoleon_google_docstring = True +napoleon_numpy_docstring = True +napoleon_include_private_with_doc = False +napoleon_include_special_with_doc = True +napoleon_use_admonition_for_examples = False +napoleon_use_admonition_for_notes = False +napoleon_use_admonition_for_references = False +napoleon_use_ivar = False +napoleon_use_param = True +napoleon_use_rtype = True diff --git a/docs/connection-usage.rst b/docs/connection-usage.rst new file mode 100644 index 0000000000..9049e3e2b2 --- /dev/null +++ b/docs/connection-usage.rst @@ -0,0 +1,32 @@ +DB API Connection +================= + +.. _spanner-client: + + +Creating a Connection +--------------------- + +To use the API, the :class:`~google.cloud.spanner_django.connection.Connection` +class defines a high-level interface which handles connection to a Spanner +databse: + +.. code:: python + + from google.cloud.spanner import connection + conn = connection.Connection() + +Configuration +------------- + +- For an overview of authentication in ``google.cloud-python``, + see `Authentication + `_. + +- In addition to any authentication configuration, you can also set the + :envvar:`GCLOUD_PROJECT` environment variable for the Google Cloud Console + project you'd like to interact with. If your code is running in Google App + Engine or Google Compute Engine the project will be detected automatically. + (Setting this environment variable is not required, you may instead pass the + ``project`` explicitly when constructing a + :class:`~google.cloud.spanner_django.connection.Connection`). diff --git a/docs/index.rst b/docs/index.rst new file mode 100644 index 0000000000..58fbbf18bc --- /dev/null +++ b/docs/index.rst @@ -0,0 +1,27 @@ +.. include:: README.rst + +Usage Documentation +------------------- +.. toctree:: + :maxdepth: 1 + :titlesonly: + + connection-usage + +API Documentation +----------------- +.. toctree:: + :maxdepth: 1 + :titlesonly: + + api-reference + +Changelog +--------- + +For a list of all ``google-cloud-spanner-django`` releases: + +.. toctree:: + :maxdepth: 2 + + changelog diff --git a/noxfile.py b/noxfile.py index 1f6b4df1e5..5e77709063 100644 --- a/noxfile.py +++ b/noxfile.py @@ -11,6 +11,7 @@ import nox import os +import shutil def default(session): @@ -31,3 +32,25 @@ def default(session): def unit(session): """Run the unit test suite.""" default(session) + + +@nox.session(python="3.7") +def docs(session): + """Build the docs for this library.""" + + session.install("-e", ".") + session.install("sphinx<3.0.0", "alabaster", "recommonmark") + + shutil.rmtree(os.path.join("docs", "_build"), ignore_errors=True) + session.run( + "sphinx-build", + "-W", # warnings as errors + "-T", # show full traceback on exception + "-N", # no colors + "-b", + "html", + "-d", + os.path.join("docs", "_build", "doctrees", ""), + os.path.join("docs", ""), + os.path.join("docs", "_build", "html", ""), + ) From 786abad8be145f988a6390fffd97c117426406b4 Mon Sep 17 00:00:00 2001 From: "STATION\\mf" Date: Thu, 27 Aug 2020 18:31:48 -0400 Subject: [PATCH 2/5] feat: Added layout template + revised Sphinx configuration --- docs/_templates/layout.html | 50 +++++++++++++++ docs/conf.py | 121 ++++++++++++++++++------------------ 2 files changed, 110 insertions(+), 61 deletions(-) create mode 100644 docs/_templates/layout.html diff --git a/docs/_templates/layout.html b/docs/_templates/layout.html new file mode 100644 index 0000000000..95e9c77fcf --- /dev/null +++ b/docs/_templates/layout.html @@ -0,0 +1,50 @@ + +{% extends "!layout.html" %} +{%- block content %} +{%- if theme_fixed_sidebar|lower == 'true' %} +
+ {{ sidebar() }} + {%- block document %} +
+ {%- if render_sidebar %} +
+ {%- endif %} + + {%- block relbar_top %} + {%- if theme_show_relbar_top|tobool %} + + {%- endif %} + {% endblock %} + +
+
+ As of January 1, 2020 this library no longer supports Python 2 on the latest released version. + Library versions released prior to that date will continue to be available. For more information please + visit Python 2 support on Google Cloud. +
+ {% block body %} {% endblock %} +
+ + {%- block relbar_bottom %} + {%- if theme_show_relbar_bottom|tobool %} + + {%- endif %} + {% endblock %} + + {%- if render_sidebar %} +
+ {%- endif %} +
+ {%- endblock %} +
+
+{%- else %} +{{ super() }} +{%- endif %} +{%- endblock %} diff --git a/docs/conf.py b/docs/conf.py index a8e6d35cce..ce82afdabf 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -6,13 +6,12 @@ # license that can be found in the LICENSE file or at # https://developers.google.com/open-source/licenses/bsd -# google-cloud-spanner documentation build configuration file +# python-spanner-django documentation build configuration file # -# This file is execfile()d with the current directory set to its -# containing dir. +# This file is executedd with the current directory set to its containing dir. # -# Note that not all possible configuration values are present in this -# autogenerated file. +# Note that not all possible configuration values are present +# in the autogenerated file. # # All configuration values have a default; values that are commented out # serve to show the default. @@ -21,7 +20,7 @@ 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 +# add this directory 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("..")) @@ -29,7 +28,7 @@ # See also: https://github.com/docascode/sphinx-docfx-yaml/issues/85 sys.path.insert(0, os.path.abspath(".")) -__version__ = "" +__version__ = "alpha" # -- General configuration ------------------------------------------------ @@ -60,7 +59,7 @@ templates_path = ["_templates"] # The suffix(es) of source filenames. -# You can specify multiple suffix as a list of string: +# You can specify multiple suffixes as a list of string: # source_suffix = ['.rst', '.md'] source_suffix = [".rst", ".md"] @@ -130,7 +129,7 @@ # 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. +# If True, `todo` and `todoList` produce output, else they produce nothing. todo_include_todos = True @@ -144,7 +143,7 @@ # further. For a list of options available for each theme, see the # documentation. html_theme_options = { - "description": "Google Cloud Client Libraries for google-cloud-spanner", + "description": "Django API Libraries for google-cloud-spanner", "github_user": "googleapis", "github_repo": "python-spanner-django", "github_banner": True, @@ -156,19 +155,19 @@ # 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 +# 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. +# 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. +# 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 +# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 # pixels large. # html_favicon = None @@ -186,36 +185,36 @@ # using the given strftime format. # html_last_updated_fmt = '%b %d, %Y' -# If true, SmartyPants will be used to convert quotes and dashes to +# 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. +# Additional templates that should be rendered to pages, +# maps page names to template names. # html_additional_pages = {} -# If false, no module index is generated. +# If False, no module index is generated. # html_domain_indices = True -# If false, no index is generated. +# If False, no index is generated. # html_use_index = True -# If true, the index is split into individual pages for each letter. +# 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. +# 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. +# 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. +# 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 +# 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 = '' @@ -233,7 +232,7 @@ # Now only 'ja' uses this config value # html_search_options = {'type': 'default'} -# The name of a javascript file (relative to the configuration directory) that +# 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' @@ -245,8 +244,8 @@ suppress_warnings = [ # Temporarily suppress this to avoid "more than one target found for - # cross-reference" warning, which are intractable for us to avoid while in - # a mono-repo. + # cross-reference" warning, which are intractable for us to avoid + # while in a mono-repo. # See https://github.com/sphinx-doc/sphinx/blob # /2a65ffeef5c107c19084fabdd706cdff3f52d93c/sphinx/domains/python.py#L843 "ref.python" @@ -255,35 +254,35 @@ # -- 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', + # # 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, - "google-cloud-spanner-django.tex", - u"google-cloud-spanner-django Documentation", - author, - "manual", - ) -] - -# The name of an image file (relative to this directory) to place at the top of -# the title page. +# (source_start_file, target_name, title, author, +# documentclass ["howto", "manual", or "own class"]). E.g., +# latex_documents = [ +# ( +# master_doc, +# "python-spanner-django.tex", +# u"Spanner Django Documentation", +# author, +# "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. +# 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. @@ -302,12 +301,12 @@ # -- Options for manual page output --------------------------------------- # One entry per manual page. List of tuples -# (source start file, name, description, authors, manual section). +# (source_start_file, name, description, authors, manual_section). man_pages = [ ( master_doc, - "google-cloud-spanner-django", - u"google-cloud-spanner-django Documentation", + "python-spanner-django", + u"python-spanner-django Documentation", [author], 1, ) @@ -320,16 +319,16 @@ # -- 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) +# (source_start_file, target_name, title, author, +# dir_menu_entry, description, category) texinfo_documents = [ ( master_doc, - "google-cloud-spanner-django", - u"google-cloud-spanner-django Documentation", + "python-spanner-django", + u"python-spanner-django Documentation", author, - "google-cloud-spanner-django", - "google-cloud-spanner-django Library", + "python-spanner-django", + "python-spanner-django Library", "APIs", ) ] From e9c28d7f6a52f02f0ea7c4effc9c8140c538170e Mon Sep 17 00:00:00 2001 From: "STATION\\mf" Date: Fri, 28 Aug 2020 16:25:05 -0400 Subject: [PATCH 3/5] chore: refactoring --- README.md | 203 ----------------------------- README.rst | 252 ++++++++++++++++++++++++++++++++++++ docs/_static/custom.css | 4 - docs/_templates/layout.html | 5 - docs/api-reference.rst | 4 +- docs/conf.py | 2 +- noxfile.py | 2 +- setup.py | 2 +- 8 files changed, 258 insertions(+), 216 deletions(-) delete mode 100644 README.md create mode 100644 README.rst delete mode 100644 docs/_static/custom.css diff --git a/README.md b/README.md deleted file mode 100644 index 55ff6105d0..0000000000 --- a/README.md +++ /dev/null @@ -1,203 +0,0 @@ -# django-spanner -ORM plugin for using Cloud Spanner as a database for Django. - -# 🚨THIS CODE IS STILL UNDER DEVELOPMENT🚨 - -## Table of contents -- [Installing it](#installing-it) -- [Using it](#using-it) - - [Format](#format) - - [Example](#example) -- [Functional tests](#functional-tests) -- [Django integration tests](#django-integration-tests) - - [django_test_suite.sh](#django_test_suitesh) - - [Environment variables](#environment-variables) - - [Example run](#example-run) - - [Parallelization script](#parallelization-script) - - [Environment variables](#environment-variables) - - [Example run](#example-run) -- [Limitations](#limitations) -- [How it works](#how-it-works) - - [Overall design](#overall-design) - - [Internals](#internals) - - -## Installing it - -Use the version of django-spanner that corresponds to your version of Django. -For example, django-spanner 2.2.x works with Django 2.2.y. (This is the only -supported version at this time.) - -The minor release number of Django doesn't correspond to the minor release -number of django-spanner. Use the latest minor release of each. - -```shell -pip3 install --user . -``` - -## Using it -After [installing it](#installing-it), you'll need to edit your Django `settings.py` file: - -* Add `django_spanner` as the very first entry in the `INSTALLED_APPS` setting -```python -INSTALLED_APPS = [ - 'django_spanner', - ... -] -``` - -* Edit the `DATABASES` setting to point to an EXISTING database - -### Format - -```python -DATABASES = { - 'default': { - 'ENGINE': 'django_spanner', - 'PROJECT': '', - 'INSTANCE': '', - 'NAME': '', - # Only include this if you need to specify where to retrieve the - # service account JSON for the credentials to connect to Cloud Spanner. - 'OPTIONS': { - 'credentials_uri': '', - }, - }, -} -``` - -### Example -For example: - -```python -DATABASES = { - 'default': { - 'ENGINE': 'django_spanner', - 'PROJECT': 'appdev-soda-spanner-staging', # Or the GCP project-id - 'INSTANCE': 'django-dev1', # Or the Cloud Spanner instance - 'NAME': 'db1', # Or the Cloud Spanner database to use - } -} -``` - -## Limitations - -### Transaction management isn't supported - -django-spanner always works in Django's default transaction behavior, -`autocommit` mode. Transactions cannot be controlled manually with -calls like `django.db.transaction.atomic()`. - -### `AutoField` generates random IDs - -Spanner doesn't have support for auto-generating primary key values. Therefore, -django-spanner monkey-patches `AutoField` to generate a random UUID4. It -generates a default using `Field`'s `default` option which means `AutoField`s -will have a value when a model instance is created. For example: - -``` ->>> ExampleModel() ->>> ExampleModel.pk -4229421414948291880 -``` - -To avoid [hotspotting](https://cloud.google.com/spanner/docs/schema-design#uuid_primary_key), -these IDs are not monotonically increasing. This means that sorting models by -ID isn't guaranteed to return them in the order in which they were created. - -### `ForeignKey` constraints aren't created - -Spanner doesn't support `ON DELETE CASCADE` when creating foreign-key constraints so -django-spanner [doesn't support foreign key constraints](https://github.com/googleapis/python-spanner-django/issues/313). - -### Check constraints aren't supported - -Spanner doesn't support `CHECK` constraints so one isn't created for -[`PositiveIntegerField`](https://docs.djangoproject.com/en/stable/ref/models/fields/#positiveintegerfield) -and [`CheckConstraint`](https://docs.djangoproject.com/en/stable/ref/models/constraints/#checkconstraint) -can't be used. - -### `DecimalField` isn't supported - -Spanner doesn't support a NUMERIC data type that allows storing high precision -decimal values without the possibility of data loss. - -### `Variance` and `StdDev` database functions aren't supported - -Spanner doesn't support these functions. - -### `Meta.order_with_respect_to` model option isn't supported - -This feature uses a column name that starts with an underscore (`_order`) which -Spanner doesn't allow. - -### Random `QuerySet` ordering isn't supported - -Spanner doesn't support it. For example: - -``` ->>> ExampleModel.objects.order_by('?') -... -django.db.utils.ProgrammingError: 400 Function not found: RANDOM ... FROM -example_model ORDER BY RANDOM() ASC -``` - -### Schema migrations - -Spanner has some limitations on schema changes which you must respect: - -* Renaming tables and columns isn't supported. -* A column's type can't be changed. -* A table's primary key can't be altered. -* Migrations aren't atomic since django-spanner doesn't support transactions. - -### `DurationField` arithmetic doesn't work with `DateField` values ([#253](https://github.com/googleapis/python-spanner-django/issues/253)) - -Spanner requires using different functions for arithmetic depending on the -column type: - -* `TIMESTAMP` columns (`DateTimeField`) require `TIMESTAMP_ADD` or - `TIMESTAMP_SUB` -* `DATE` columns (`DateField`) require `DATE_ADD` or `DATE_SUB` - -Django doesn't provide a way to determine which database function to use. -`DatabaseOperations.combine_duration_expression()` arbitrary uses -`TIMESTAMP_ADD` and `TIMESTAMP_SUB`. Therefore, if you use a `DateField` in a -`DurationField` expression, you'll see an error like: "No matching signature -for function TIMESTAMP_ADD for argument types: DATE, INTERVAL INT64 -DATE_TIME_PART." - -### Computations that yield FLOAT64 values can't be assigned to INT64 columns - -Spanner [doesn't support this](https://github.com/googleapis/python-spanner-django/issues/331). - -For example, if `integer` is `IntegerField`: - -``` ->>> ExampleModel.objects.update(integer=F('integer') / 2) -... -django.db.utils.ProgrammingError: 400 Value of type FLOAT64 cannot be -assigned to integer, which has type INT64 [at 1:46]\nUPDATE -example_model SET integer = (example_model.integer /... -``` - -### Addition with null values crash - -For example: - -``` ->>> Book.objects.annotate(adjusted_rating=F('rating') + None) -... -google.api_core.exceptions.InvalidArgument: 400 Operands of + cannot be literal -NULL ... -``` - -## How it works - -### Overall design -![](./assets/overview.png) - -### Internals -![](./assets/internals.png) - -# 🚨THIS CODE IS STILL UNDER DEVELOPMENT🚨 diff --git a/README.rst b/README.rst new file mode 100644 index 0000000000..c50e5a79a0 --- /dev/null +++ b/README.rst @@ -0,0 +1,252 @@ +django-spanner +============== + +ORM plugin for using Cloud Spanner as a database for Django. + +🚨THIS CODE IS STILL UNDER DEVELOPMENT🚨 +======================================== + +Table of contents +----------------- + +- `Installing it <#installing-it>`__ +- `Using it <#using-it>`__ + + - `Format <#format>`__ + - `Example <#example>`__ + +- `Functional tests <#functional-tests>`__ +- `Django integration tests <#django-integration-tests>`__ + + - `django\_test\_suite.sh <#django_test_suitesh>`__ + + - `Environment variables <#environment-variables>`__ + - `Example run <#example-run>`__ + + - `Parallelization script <#parallelization-script>`__ + + - `Environment variables <#environment-variables>`__ + - `Example run <#example-run>`__ + +- `Limitations <#limitations>`__ +- `How it works <#how-it-works>`__ + + - `Overall design <#overall-design>`__ + - `Internals <#internals>`__ + +Installing it +------------- + +Use the version of django-spanner that corresponds to your version of +Django. For example, django-spanner 2.2.x works with Django 2.2.y. (This +is the only supported version at this time.) + +The minor release number of Django doesn't correspond to the minor +release number of django-spanner. Use the latest minor release of each. + +.. code:: shell + + pip3 install --user . + +Using it +-------- + +After `installing it <#installing-it>`__, you'll need to edit your +Django ``settings.py`` file: + +- Add ``django_spanner`` as the very first entry in the + ``INSTALLED_APPS`` setting + + .. code:: python + + INSTALLED_APPS = [ + 'spanner_django', + ... + ] + +- Edit the ``DATABASES`` setting to point to an EXISTING database + +Format +~~~~~~ + +.. code:: python + + DATABASES = { + 'default': { + 'ENGINE': 'spanner_django', + 'PROJECT': '', + 'INSTANCE': '', + 'NAME': '', + # Only include this if you need to specify where to retrieve the + # service account JSON for the credentials to connect to Cloud Spanner. + 'OPTIONS': { + 'credentials_uri': '', + }, + }, + } + +Example +~~~~~~~ + +For example: + +.. code:: python + + DATABASES = { + 'default': { + 'ENGINE': 'spanner_django', + 'PROJECT': 'appdev-soda-spanner-staging', # Or the GCP project-id + 'INSTANCE': 'django-dev1', # Or the Cloud Spanner instance + 'NAME': 'db1', # Or the Cloud Spanner database to use + } + } + +Limitations +----------- + +Transaction management isn't supported +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +django-spanner always works in Django's default transaction behavior, +``autocommit`` mode. Transactions cannot be controlled manually with +calls like ``django.db.transaction.atomic()``. + +``AutoField`` generates random IDs +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Spanner doesn't have support for auto-generating primary key values. +Therefore, django-spanner monkey-patches ``AutoField`` to generate a +random UUID4. It generates a default using ``Field``'s ``default`` +option which means ``AutoField``\ s will have a value when a model +instance is created. For example: + +:: + + >>> ExampleModel() + >>> ExampleModel.pk + 4229421414948291880 + +To avoid +`hotspotting `__, +these IDs are not monotonically increasing. This means that sorting +models by ID isn't guaranteed to return them in the order in which they +were created. + +``ForeignKey`` constraints aren't created +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Spanner doesn't support ``ON DELETE CASCADE`` when creating foreign-key +constraints so django-spanner `doesn't support foreign key +constraints `__. + +Check constraints aren't supported +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Spanner doesn't support ``CHECK`` constraints so one isn't created for +```PositiveIntegerField`` `__ +and +```CheckConstraint`` `__ +can't be used. + +``DecimalField`` isn't supported +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Spanner doesn't support a NUMERIC data type that allows storing high +precision decimal values without the possibility of data loss. + +``Variance`` and ``StdDev`` database functions aren't supported +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Spanner doesn't support these functions. + +``Meta.order_with_respect_to`` model option isn't supported +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This feature uses a column name that starts with an underscore +(``_order``) which Spanner doesn't allow. + +Random ``QuerySet`` ordering isn't supported +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Spanner doesn't support it. For example: + +:: + + >>> ExampleModel.objects.order_by('?') + ... + django.db.utils.ProgrammingError: 400 Function not found: RANDOM ... FROM + example_model ORDER BY RANDOM() ASC + +Schema migrations +~~~~~~~~~~~~~~~~~ + +Spanner has some limitations on schema changes which you must respect: + +- Renaming tables and columns isn't supported. +- A column's type can't be changed. +- A table's primary key can't be altered. +- Migrations aren't atomic since django-spanner doesn't support + transactions. + +``DurationField`` arithmetic doesn't work with ``DateField`` values (`#253 `__) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Spanner requires using different functions for arithmetic depending on +the column type: + +- ``TIMESTAMP`` columns (``DateTimeField``) require ``TIMESTAMP_ADD`` + or ``TIMESTAMP_SUB`` +- ``DATE`` columns (``DateField``) require ``DATE_ADD`` or ``DATE_SUB`` + +Django doesn't provide a way to determine which database function to +use. ``DatabaseOperations.combine_duration_expression()`` arbitrary uses +``TIMESTAMP_ADD`` and ``TIMESTAMP_SUB``. Therefore, if you use a +``DateField`` in a ``DurationField`` expression, you'll see an error +like: "No matching signature for function TIMESTAMP\_ADD for argument +types: DATE, INTERVAL INT64 DATE\_TIME\_PART." + +Computations that yield FLOAT64 values can't be assigned to INT64 columns +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Spanner `doesn't support +this `__. + +For example, if ``integer`` is ``IntegerField``: + +:: + + >>> ExampleModel.objects.update(integer=F('integer') / 2) + ... + django.db.utils.ProgrammingError: 400 Value of type FLOAT64 cannot be + assigned to integer, which has type INT64 [at 1:46]\nUPDATE + example_model SET integer = (example_model.integer /... + +Addition with null values crash +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +For example: + +:: + + >>> Book.objects.annotate(adjusted_rating=F('rating') + None) + ... + google.api_core.exceptions.InvalidArgument: 400 Operands of + cannot be literal + NULL ... + +How it works +------------ + +Overall design +~~~~~~~~~~~~~~ + +.. figure:: ./assets/overview.png + :alt: + +Internals +~~~~~~~~~ + +.. figure:: ./assets/internals.png + :alt: + +🚨🚨THIS CODE IS STILL UNDER DEVELOPMENT🚨🚨 +============================================ diff --git a/docs/_static/custom.css b/docs/_static/custom.css deleted file mode 100644 index 9a6f9f8ddc..0000000000 --- a/docs/_static/custom.css +++ /dev/null @@ -1,4 +0,0 @@ -div#python2-eol { - border-color: red; - border-width: medium; -} \ No newline at end of file diff --git a/docs/_templates/layout.html b/docs/_templates/layout.html index 95e9c77fcf..bfdcc4759c 100644 --- a/docs/_templates/layout.html +++ b/docs/_templates/layout.html @@ -20,11 +20,6 @@ {% endblock %}
-
- As of January 1, 2020 this library no longer supports Python 2 on the latest released version. - Library versions released prior to that date will continue to be available. For more information please - visit Python 2 support on Google Cloud. -
{% block body %} {% endblock %}
diff --git a/docs/api-reference.rst b/docs/api-reference.rst index 593383df41..7da735f86f 100644 --- a/docs/api-reference.rst +++ b/docs/api-reference.rst @@ -1,4 +1,6 @@ API Reference ============= -[The following classes and methods constitute the Spanner DB API connection.] +The following classes and methods constitute the Spanner DB API connection. + +[this page is under construction] diff --git a/docs/conf.py b/docs/conf.py index ce82afdabf..de7819031d 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -102,7 +102,7 @@ "_build", "samples/AUTHORING_GUIDE.md", "samples/CONTRIBUTING.md", - "samples/snippets/README.md", + "samples/snippets/README.rst", ] # The reST default role (used for this markup: `text`) to use for all diff --git a/noxfile.py b/noxfile.py index 5e77709063..04b4694086 100644 --- a/noxfile.py +++ b/noxfile.py @@ -34,7 +34,7 @@ def unit(session): default(session) -@nox.session(python="3.7") +@nox.session(python="3.8") def docs(session): """Build the docs for this library.""" diff --git a/setup.py b/setup.py index e82752e4c4..d5515b05d5 100644 --- a/setup.py +++ b/setup.py @@ -30,7 +30,7 @@ package_root = os.path.abspath(os.path.dirname(__file__)) -readme_filename = os.path.join(package_root, "README.md") +readme_filename = os.path.join(package_root, "README.rst") with io.open(readme_filename, encoding="utf-8") as readme_file: readme = readme_file.read() From 8b904b0f61de01c52ad4707e6e416a260fe5dd04 Mon Sep 17 00:00:00 2001 From: "STATION\\mf" Date: Fri, 28 Aug 2020 17:05:27 -0400 Subject: [PATCH 4/5] fix: disabling unnecessary stylesheet override --- docs/conf.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/conf.py b/docs/conf.py index de7819031d..fe79f1e098 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -174,7 +174,7 @@ # 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"] +# 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 From 24b854a0c2fe7710b19e5e0bc0060fec1336a07b Mon Sep 17 00:00:00 2001 From: "STATION\\mf" Date: Fri, 28 Aug 2020 20:37:10 -0400 Subject: [PATCH 5/5] fix: broken README link --- docs/README.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/README.rst b/docs/README.rst index 32d46ee883..89a0106941 100644 --- a/docs/README.rst +++ b/docs/README.rst @@ -1 +1 @@ -../README.md \ No newline at end of file +../README.rst \ No newline at end of file