Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding ability to run doctests with datastore system tests. #2738

Merged
merged 1 commit into from
Dec 2, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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'

This comment was marked as spam.

This comment was marked as spam.


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')

This comment was marked as spam.

This comment was marked as spam.


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__(),)

This comment was marked as spam.

This comment was marked as spam.

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)

This comment was marked as spam.

This comment was marked as spam.


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)

This comment was marked as spam.

This comment was marked as spam.

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

This comment was marked as spam.


docs_dir = self._make_temp_docs()

This comment was marked as spam.

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.4
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