Skip to content

Commit 4e7d49f

Browse files
committed
Adding ability to run doctests with datastore system tests.
1 parent b92f0cf commit 4e7d49f

File tree

6 files changed

+105
-19
lines changed

6 files changed

+105
-19
lines changed

datastore/google/cloud/datastore/__init__.py

+18-6
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,26 @@
1616
1717
You'll typically use these to get started with the API:
1818
19-
.. code-block:: python
19+
.. testsetup:: constructors
2020
21-
from google.cloud import datastore
21+
import os
22+
os.environ['GOOGLE_CLOUD_PROJECT'] = u'my-project'
2223
23-
client = datastore.Client()
24-
key = client.key('EntityKind', 1234)
25-
entity = datastore.Entity(key)
26-
query = client.query(kind='EntityKind')
24+
.. doctest:: constructors
25+
26+
>>> from google.cloud import datastore
27+
>>>
28+
>>> client = datastore.Client()
29+
>>> print(client.project)
30+
my-project
31+
>>> key = client.key('EntityKind', 1234)
32+
>>> key
33+
<Key('EntityKind', 1234), project=my-project>
34+
>>> entity = datastore.Entity(key)
35+
>>> entity['answer'] = 42
36+
>>> entity
37+
<Entity('EntityKind', 1234) {'answer': 42}>
38+
>>> query = client.query(kind='EntityKind')
2739
2840
The main concepts with this API are:
2941

datastore/google/cloud/datastore/entity.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,7 @@ def exclude_from_indexes(self):
144144

145145
def __repr__(self):
146146
if self.key:
147-
return '<Entity%s %s>' % (self.key.path,
147+
return '<Entity%s %s>' % (self.key._flat_path,
148148
super(Entity, self).__repr__())
149149
else:
150-
return '<Entity %s>' % (super(Entity, self).__repr__())
150+
return '<Entity %s>' % (super(Entity, self).__repr__(),)

datastore/google/cloud/datastore/key.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -380,7 +380,7 @@ def parent(self):
380380
return self._parent
381381

382382
def __repr__(self):
383-
return '<Key%s, project=%s>' % (self.path, self.project)
383+
return '<Key%s, project=%s>' % (self._flat_path, self.project)
384384

385385

386386
def _validate_project(project, parent):

datastore/unit_tests/test_entity.py

+6-7
Original file line numberDiff line numberDiff line change
@@ -190,10 +190,13 @@ def test___repr___no_key_empty(self):
190190

191191
def test___repr___w_key_non_empty(self):
192192
key = _Key()
193-
key._path = '/bar/baz'
193+
flat_path = ('bar', 12, 'baz', 'himom')
194+
key._flat_path = flat_path
194195
entity = self._make_one(key=key)
195-
entity['foo'] = 'Foo'
196-
self.assertEqual(repr(entity), "<Entity/bar/baz {'foo': 'Foo'}>")
196+
entity_vals = {'foo': 'Foo'}
197+
entity.update(entity_vals)
198+
expected = '<Entity%s %s>' % (flat_path, entity_vals)
199+
self.assertEqual(repr(entity), expected)
197200

198201

199202
class _Key(object):
@@ -206,7 +209,3 @@ class _Key(object):
206209

207210
def __init__(self, project=_PROJECT):
208211
self.project = project
209-
210-
@property
211-
def path(self):
212-
return self._path

system_tests/datastore.py

+75
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@
1414

1515
import datetime
1616
import os
17+
import pkgutil
18+
import tempfile
1719
import unittest
1820

1921
import httplib2
@@ -31,6 +33,23 @@
3133
from system_test_utils import unique_resource_id
3234

3335

36+
SPHINX_CONF = """\
37+
extensions = [
38+
'sphinx.ext.autodoc',
39+
'sphinx.ext.doctest',
40+
]
41+
"""
42+
43+
SPHINX_SECTION_TEMPLATE = """\
44+
Section %02d
45+
===========
46+
47+
.. automodule:: google.cloud.%s
48+
:members:
49+
50+
"""
51+
52+
3453
class Config(object):
3554
"""Run-time configuration to be modified at set-up.
3655
@@ -495,3 +514,59 @@ def test_failure_with_contention(self):
495514
# transaction.
496515
entity_in_txn[contention_prop_name] = u'inside'
497516
txn.put(entity_in_txn)
517+
518+
519+
class TestDoctest(unittest.TestCase):
520+
521+
def _submodules(self):
522+
pkg_iter = pkgutil.iter_modules(datastore.__path__)
523+
result = []
524+
for _, mod_name, ispkg in pkg_iter:
525+
if mod_name == '_generated':
526+
self.assertTrue(ispkg)
527+
else:
528+
self.assertFalse(ispkg)
529+
result.append(mod_name)
530+
531+
self.assertNotIn('__init__', result)
532+
return result
533+
534+
@staticmethod
535+
def _add_section(index, mod_name, file_obj):
536+
mod_part = 'datastore'
537+
if mod_name != '__init__':
538+
mod_part += '.' + mod_name
539+
content = SPHINX_SECTION_TEMPLATE % (index, mod_part)
540+
file_obj.write(content)
541+
542+
def _make_temp_docs(self):
543+
docs_dir = tempfile.mkdtemp(prefix='datastore-')
544+
545+
conf_file = os.path.join(docs_dir, 'conf.py')
546+
547+
with open(conf_file, 'w') as file_obj:
548+
file_obj.write(SPHINX_CONF)
549+
550+
index_file = os.path.join(docs_dir, 'contents.rst')
551+
datastore_modules = self._submodules()
552+
with open(index_file, 'w') as file_obj:
553+
self._add_section(0, '__init__', file_obj)
554+
for index, datastore_module in enumerate(datastore_modules):
555+
self._add_section(index + 1, datastore_module, file_obj)
556+
557+
return docs_dir
558+
559+
def test_it(self):
560+
from sphinx import application
561+
562+
docs_dir = self._make_temp_docs()
563+
outdir = os.path.join(docs_dir, 'doctest', 'out')
564+
doctreedir = os.path.join(docs_dir, 'doctest', 'doctrees')
565+
566+
app = application.Sphinx(
567+
srcdir=docs_dir, confdir=docs_dir,
568+
outdir=outdir, doctreedir=doctreedir,
569+
buildername='doctest', warningiserror=True, parallel=1)
570+
571+
app.build()
572+
self.assertEqual(app.statuscode, 0)

tox.ini

+3-3
Original file line numberDiff line numberDiff line change
@@ -265,6 +265,7 @@ commands =
265265
python {toxinidir}/system_tests/attempt_system_tests.py {posargs}
266266
deps =
267267
{[testing]deps}
268+
Sphinx
268269
passenv =
269270
{[testing]passenv}
270271
encrypted_*
@@ -273,10 +274,9 @@ passenv =
273274
basepython =
274275
python3.4
275276
commands =
276-
{[testing]localdeps}
277-
python {toxinidir}/system_tests/attempt_system_tests.py {posargs}
277+
{[testenv:system-tests]commands}
278278
deps =
279-
{[testing]deps}
279+
{[testenv:system-tests]deps}
280280
passenv =
281281
{[testenv:system-tests]passenv}
282282

0 commit comments

Comments
 (0)