Skip to content
This repository was archived by the owner on Nov 3, 2023. It is now read-only.

Commit 4aa5d96

Browse files
justinludwigNurdok
authored andcommitted
Test cases for canonical examples of conventions (#429)
* Test cases for canonical examples of conventions This change adds test cases for the examples from the official docs of each of the three default conventions: * google: the "3.8.2 Modules", "3.8.3 Functions and Methods", and "3.8.4 Classes" examples from the [Google Python Style Guide](https://google.github.io/styleguide/pyguide.html) * numpy: the content of the "example.py" file from the "Example" page of the [numpydoc manual](https://numpydoc.readthedocs.io/) * pep257: the "One-line Docstrings" and "Multi-line Docstrings" examples from the [PEP 257 -- Docstring Conventions](https://www.python.org/dev/peps/pep-0257/) specification These test cases help validate which existing errors should be excluded from each of the default conventions, and will help identify new errors or changes to existing errors in the future that should be excluded from the default conventions. * Use normcase to fix test failures on windows
1 parent dbbf578 commit 4aa5d96

File tree

4 files changed

+313
-0
lines changed

4 files changed

+313
-0
lines changed
Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
"""A one line summary of the module or program, terminated by a period.
2+
3+
Leave one blank line. The rest of this docstring should contain an
4+
overall description of the module or program. Optionally, it may also
5+
contain a brief description of exported classes and functions and/or usage
6+
examples.
7+
8+
Typical usage example:
9+
10+
foo = ClassFoo()
11+
bar = foo.FunctionBar()
12+
"""
13+
# above: "2.8.2 Modules" section example
14+
# https://google.github.io/styleguide/pyguide.html#382-modules
15+
16+
# Examples from the official "Google Python Style Guide" documentation:
17+
# * As HTML: https://google.github.io/styleguide/pyguide.html
18+
# * Source Markdown:
19+
# https://github.com/google/styleguide/blob/gh-pages/pyguide.md
20+
21+
import os
22+
from .expected import Expectation
23+
24+
expectation = Expectation()
25+
expect = expectation.expect
26+
27+
# module docstring expected violations:
28+
expectation.expected.add((
29+
os.path.normcase(__file__),
30+
"D213: Multi-line docstring summary should start at the second line"))
31+
32+
33+
# "3.8.3 Functions and Methods" section example
34+
# https://google.github.io/styleguide/pyguide.html#383-functions-and-methods
35+
@expect("D213: Multi-line docstring summary should start at the second line",
36+
arg_count=3)
37+
@expect("D401: First line should be in imperative mood "
38+
"(perhaps 'Fetch', not 'Fetches')", arg_count=3)
39+
@expect("D406: Section name should end with a newline "
40+
"('Raises', not 'Raises:')", arg_count=3)
41+
@expect("D406: Section name should end with a newline "
42+
"('Returns', not 'Returns:')", arg_count=3)
43+
@expect("D407: Missing dashed underline after section ('Raises')", arg_count=3)
44+
@expect("D407: Missing dashed underline after section ('Returns')",
45+
arg_count=3)
46+
@expect("D413: Missing blank line after last section ('Raises')", arg_count=3)
47+
def fetch_bigtable_rows(big_table, keys, other_silly_variable=None):
48+
"""Fetches rows from a Bigtable.
49+
50+
Retrieves rows pertaining to the given keys from the Table instance
51+
represented by big_table. Silly things may happen if
52+
other_silly_variable is not None.
53+
54+
Args:
55+
big_table: An open Bigtable Table instance.
56+
keys: A sequence of strings representing the key of each table row
57+
to fetch.
58+
other_silly_variable: Another optional variable, that has a much
59+
longer name than the other args, and which does nothing.
60+
61+
Returns:
62+
A dict mapping keys to the corresponding table row data
63+
fetched. Each row is represented as a tuple of strings. For
64+
example:
65+
66+
{'Serak': ('Rigel VII', 'Preparer'),
67+
'Zim': ('Irk', 'Invader'),
68+
'Lrrr': ('Omicron Persei 8', 'Emperor')}
69+
70+
If a key from the keys argument is missing from the dictionary,
71+
then that row was not found in the table.
72+
73+
Raises:
74+
IOError: An error occurred accessing the bigtable.Table object.
75+
"""
76+
77+
78+
# "3.8.4 Classes" section example
79+
# https://google.github.io/styleguide/pyguide.html#384-classes
80+
@expect("D203: 1 blank line required before class docstring (found 0)")
81+
@expect("D213: Multi-line docstring summary should start at the second line")
82+
@expect("D406: Section name should end with a newline "
83+
"('Attributes', not 'Attributes:')")
84+
@expect("D407: Missing dashed underline after section ('Attributes')")
85+
@expect("D413: Missing blank line after last section ('Attributes')")
86+
class SampleClass(object):
87+
"""Summary of class here.
88+
89+
Longer class information....
90+
Longer class information....
91+
92+
Attributes:
93+
likes_spam: A boolean indicating if we like SPAM or not.
94+
eggs: An integer count of the eggs we have laid.
95+
"""
96+
97+
@expect("D401: First line should be in imperative mood "
98+
"(perhaps 'Init', not 'Inits')", arg_count=2)
99+
def __init__(self, likes_spam=False):
100+
"""Inits SampleClass with blah."""
101+
if self: # added to avoid NameError when run via @expect decorator
102+
self.likes_spam = likes_spam
103+
self.eggs = 0
104+
105+
@expect("D401: First line should be in imperative mood "
106+
"(perhaps 'Perform', not 'Performs')", arg_count=1)
107+
def public_method(self):
108+
"""Performs operation blah."""
Lines changed: 163 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,163 @@
1+
"""This is the docstring for the example.py module. Modules names should
2+
have short, all-lowercase names. The module name may have underscores if
3+
this improves readability.
4+
5+
Every module should have a docstring at the very top of the file. The
6+
module's docstring may extend over multiple lines. If your docstring does
7+
extend over multiple lines, the closing three quotation marks must be on
8+
a line by itself, preferably preceded by a blank line.
9+
10+
"""
11+
12+
# Example source file from the official "numpydoc docstring guide"
13+
# documentation (with the modification of commenting out all the original
14+
# ``import`` lines, plus adding this note and ``Expectation`` code):
15+
# * As HTML: https://numpydoc.readthedocs.io/en/latest/example.html
16+
# * Source Python:
17+
# https://github.com/numpy/numpydoc/blob/master/doc/example.py
18+
19+
# from __future__ import division, absolute_import, print_function
20+
#
21+
# import os # standard library imports first
22+
#
23+
# Do NOT import using *, e.g. from numpy import *
24+
#
25+
# Import the module using
26+
#
27+
# import numpy
28+
#
29+
# instead or import individual functions as needed, e.g
30+
#
31+
# from numpy import array, zeros
32+
#
33+
# If you prefer the use of abbreviated module names, we suggest the
34+
# convention used by NumPy itself::
35+
#
36+
# import numpy as np
37+
# import matplotlib as mpl
38+
# import matplotlib.pyplot as plt
39+
#
40+
# These abbreviated names are not to be used in docstrings; users must
41+
# be able to paste and execute docstrings after importing only the
42+
# numpy module itself, unabbreviated.
43+
44+
import os
45+
from .expected import Expectation
46+
47+
expectation = Expectation()
48+
expect = expectation.expect
49+
50+
# module docstring expected violations:
51+
expectation.expected.add((
52+
os.path.normcase(__file__),
53+
"D205: 1 blank line required between summary line and description "
54+
"(found 0)"))
55+
expectation.expected.add((
56+
os.path.normcase(__file__),
57+
"D213: Multi-line docstring summary should start at the second line"))
58+
expectation.expected.add((
59+
os.path.normcase(__file__),
60+
"D400: First line should end with a period (not 'd')"))
61+
expectation.expected.add((
62+
os.path.normcase(__file__),
63+
"D404: First word of the docstring should not be `This`"))
64+
expectation.expected.add((
65+
os.path.normcase(__file__),
66+
"D415: First line should end with a period, question mark, or exclamation "
67+
"point (not 'd')"))
68+
69+
70+
@expect("D213: Multi-line docstring summary should start at the second line",
71+
arg_count=3)
72+
@expect("D401: First line should be in imperative mood; try rephrasing "
73+
"(found 'A')", arg_count=3)
74+
@expect("D413: Missing blank line after last section ('Examples')",
75+
arg_count=3)
76+
def foo(var1, var2, long_var_name='hi'):
77+
r"""A one-line summary that does not use variable names.
78+
79+
Several sentences providing an extended description. Refer to
80+
variables using back-ticks, e.g. `var`.
81+
82+
Parameters
83+
----------
84+
var1 : array_like
85+
Array_like means all those objects -- lists, nested lists, etc. --
86+
that can be converted to an array. We can also refer to
87+
variables like `var1`.
88+
var2 : int
89+
The type above can either refer to an actual Python type
90+
(e.g. ``int``), or describe the type of the variable in more
91+
detail, e.g. ``(N,) ndarray`` or ``array_like``.
92+
long_var_name : {'hi', 'ho'}, optional
93+
Choices in brackets, default first when optional.
94+
95+
Returns
96+
-------
97+
type
98+
Explanation of anonymous return value of type ``type``.
99+
describe : type
100+
Explanation of return value named `describe`.
101+
out : type
102+
Explanation of `out`.
103+
type_without_description
104+
105+
Other Parameters
106+
----------------
107+
only_seldom_used_keywords : type
108+
Explanation
109+
common_parameters_listed_above : type
110+
Explanation
111+
112+
Raises
113+
------
114+
BadException
115+
Because you shouldn't have done that.
116+
117+
See Also
118+
--------
119+
numpy.array : Relationship (optional).
120+
numpy.ndarray : Relationship (optional), which could be fairly long, in
121+
which case the line wraps here.
122+
numpy.dot, numpy.linalg.norm, numpy.eye
123+
124+
Notes
125+
-----
126+
Notes about the implementation algorithm (if needed).
127+
128+
This can have multiple paragraphs.
129+
130+
You may include some math:
131+
132+
.. math:: X(e^{j\omega } ) = x(n)e^{ - j\omega n}
133+
134+
And even use a Greek symbol like :math:`\omega` inline.
135+
136+
References
137+
----------
138+
Cite the relevant literature, e.g. [1]_. You may also cite these
139+
references in the notes section above.
140+
141+
.. [1] O. McNoleg, "The integration of GIS, remote sensing,
142+
expert systems and adaptive co-kriging for environmental habitat
143+
modelling of the Highland Haggis using object-oriented, fuzzy-logic
144+
and neural-network techniques," Computers & Geosciences, vol. 22,
145+
pp. 585-588, 1996.
146+
147+
Examples
148+
--------
149+
These are written in doctest format, and should illustrate how to
150+
use the function.
151+
152+
>>> a = [1, 2, 3]
153+
>>> print([x + 3 for x in a])
154+
[4, 5, 6]
155+
>>> print("a\nb")
156+
a
157+
b
158+
"""
159+
# After closing class docstring, there should be one blank line to
160+
# separate following codes (according to PEP257).
161+
# But for function, method and module, there should be no blank lines
162+
# after closing the docstring.
163+
pass
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
"""Examples from the pep257 specification."""
2+
3+
# Examples from the official "Python PEP 257 -- Docstring Conventions"
4+
# documentation:
5+
# * As HTML: https://www.python.org/dev/peps/pep-0257
6+
# * Source reST: https://github.com/python/peps/blob/master/pep-0257.txt
7+
8+
from .expected import Expectation
9+
10+
expectation = Expectation()
11+
expect = expectation.expect
12+
13+
14+
# "One-line Docstrings" section example
15+
# https://www.python.org/dev/peps/pep-0257/#id16
16+
def kos_root():
17+
"""Return the pathname of the KOS root directory."""
18+
global _kos_root
19+
if _kos_root:
20+
return _kos_root
21+
22+
23+
# "Multiline-line Docstrings" section example
24+
# https://www.python.org/dev/peps/pep-0257/#id17
25+
@expect("D213: Multi-line docstring summary should start at the second line")
26+
@expect("D405: Section name should be properly capitalized "
27+
"('Keyword Arguments', not 'Keyword arguments')")
28+
@expect("D407: Missing dashed underline after section ('Keyword Arguments')")
29+
@expect("D413: Missing blank line after last section ('Keyword Arguments')")
30+
def complex(real=0.0, imag=0.0):
31+
"""Form a complex number.
32+
33+
Keyword arguments:
34+
real -- the real part (default 0.0)
35+
imag -- the imaginary part (default 0.0)
36+
"""
37+
if imag == 0.0 and real == 0.0:
38+
complex_zero = 0 # added to avoid NameError with @expect decorator
39+
return complex_zero

src/tests/test_definitions.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,9 @@
1919
'superfluous_quotes',
2020
'noqa',
2121
'sections',
22+
'canonical_google_examples',
23+
'canonical_numpy_examples',
24+
'canonical_pep257_examples',
2225
])
2326
def test_complex_file(test_case):
2427
"""Run domain-specific tests from test.py file."""

0 commit comments

Comments
 (0)