Skip to content

Commit

Permalink
Merge pull request googleapis#2738 from dhermes/sphinx-doctest-datastore
Browse files Browse the repository at this point in the history
Adding ability to run doctests with datastore system tests.
  • Loading branch information
dhermes committed Dec 2, 2016
2 parents 6be983e + 3cb5f0b commit 6224c08
Show file tree
Hide file tree
Showing 6 changed files with 105 additions and 19 deletions.
24 changes: 18 additions & 6 deletions datastore/google/cloud/datastore/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,26 @@
You'll typically use these to get started with the API:
.. code-block:: python
.. testsetup:: constructors
from google.cloud import datastore
import os
os.environ['GOOGLE_CLOUD_PROJECT'] = u'my-project'
client = datastore.Client()
key = client.key('EntityKind', 1234)
entity = datastore.Entity(key)
query = client.query(kind='EntityKind')
.. doctest:: constructors
>>> from google.cloud import datastore
>>>
>>> client = datastore.Client()
>>> print(client.project)
my-project
>>> key = client.key('EntityKind', 1234)
>>> key
<Key('EntityKind', 1234), project=my-project>
>>> entity = datastore.Entity(key)
>>> entity['answer'] = 42
>>> entity
<Entity('EntityKind', 1234) {'answer': 42}>
>>> query = client.query(kind='EntityKind')
The main concepts with this API are:
Expand Down
4 changes: 2 additions & 2 deletions datastore/google/cloud/datastore/entity.py
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ def exclude_from_indexes(self):

def __repr__(self):
if self.key:
return '<Entity%s %s>' % (self.key.path,
return '<Entity%s %s>' % (self.key._flat_path,
super(Entity, self).__repr__())
else:
return '<Entity %s>' % (super(Entity, self).__repr__())
return '<Entity %s>' % (super(Entity, self).__repr__(),)
2 changes: 1 addition & 1 deletion datastore/google/cloud/datastore/key.py
Original file line number Diff line number Diff line change
Expand Up @@ -380,7 +380,7 @@ def parent(self):
return self._parent

def __repr__(self):
return '<Key%s, project=%s>' % (self.path, self.project)
return '<Key%s, project=%s>' % (self._flat_path, self.project)


def _validate_project(project, parent):
Expand Down
13 changes: 6 additions & 7 deletions datastore/unit_tests/test_entity.py
Original file line number Diff line number Diff line change
Expand Up @@ -190,10 +190,13 @@ def test___repr___no_key_empty(self):

def test___repr___w_key_non_empty(self):
key = _Key()
key._path = '/bar/baz'
flat_path = ('bar', 12, 'baz', 'himom')
key._flat_path = flat_path
entity = self._make_one(key=key)
entity['foo'] = 'Foo'
self.assertEqual(repr(entity), "<Entity/bar/baz {'foo': 'Foo'}>")
entity_vals = {'foo': 'Foo'}
entity.update(entity_vals)
expected = '<Entity%s %s>' % (flat_path, entity_vals)
self.assertEqual(repr(entity), expected)


class _Key(object):
Expand All @@ -206,7 +209,3 @@ class _Key(object):

def __init__(self, project=_PROJECT):
self.project = project

@property
def path(self):
return self._path
75 changes: 75 additions & 0 deletions system_tests/datastore.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@

import datetime
import os
import pkgutil
import tempfile
import unittest

import httplib2
Expand All @@ -31,6 +33,23 @@
from system_test_utils import unique_resource_id


SPHINX_CONF = """\
extensions = [
'sphinx.ext.autodoc',
'sphinx.ext.doctest',
]
"""

SPHINX_SECTION_TEMPLATE = """\
Section %02d
===========
.. automodule:: google.cloud.%s
:members:
"""


class Config(object):
"""Run-time configuration to be modified at set-up.
Expand Down Expand Up @@ -495,3 +514,59 @@ def test_failure_with_contention(self):
# transaction.
entity_in_txn[contention_prop_name] = u'inside'
txn.put(entity_in_txn)


class TestDoctest(unittest.TestCase):

def _submodules(self):
pkg_iter = pkgutil.iter_modules(datastore.__path__)
result = []
for _, mod_name, ispkg in pkg_iter:
if mod_name == '_generated':
self.assertTrue(ispkg)
else:
self.assertFalse(ispkg)
result.append(mod_name)

self.assertNotIn('__init__', result)
return result

@staticmethod
def _add_section(index, mod_name, file_obj):
mod_part = 'datastore'
if mod_name != '__init__':
mod_part += '.' + mod_name
content = SPHINX_SECTION_TEMPLATE % (index, mod_part)
file_obj.write(content)

def _make_temp_docs(self):
docs_dir = tempfile.mkdtemp(prefix='datastore-')

conf_file = os.path.join(docs_dir, 'conf.py')

with open(conf_file, 'w') as file_obj:
file_obj.write(SPHINX_CONF)

index_file = os.path.join(docs_dir, 'contents.rst')
datastore_modules = self._submodules()
with open(index_file, 'w') as file_obj:
self._add_section(0, '__init__', file_obj)
for index, datastore_module in enumerate(datastore_modules):
self._add_section(index + 1, datastore_module, file_obj)

return docs_dir

def test_it(self):
from sphinx import application

docs_dir = self._make_temp_docs()
outdir = os.path.join(docs_dir, 'doctest', 'out')
doctreedir = os.path.join(docs_dir, 'doctest', 'doctrees')

app = application.Sphinx(
srcdir=docs_dir, confdir=docs_dir,
outdir=outdir, doctreedir=doctreedir,
buildername='doctest', warningiserror=True, parallel=1)

app.build()
self.assertEqual(app.statuscode, 0)
6 changes: 3 additions & 3 deletions tox.ini
Original file line number Diff line number Diff line change
Expand Up @@ -265,6 +265,7 @@ commands =
python {toxinidir}/system_tests/attempt_system_tests.py {posargs}
deps =
{[testing]deps}
Sphinx
passenv =
{[testing]passenv}
encrypted_*
Expand All @@ -273,10 +274,9 @@ passenv =
basepython =
python3.5
commands =
{[testing]localdeps}
python {toxinidir}/system_tests/attempt_system_tests.py {posargs}
{[testenv:system-tests]commands}
deps =
{[testing]deps}
{[testenv:system-tests]deps}
passenv =
{[testenv:system-tests]passenv}

Expand Down

0 comments on commit 6224c08

Please sign in to comment.