Skip to content

Commit 32f1b56

Browse files
[Enh] Activating numpydoc validation during Sphinx build (#694)
* Added patch to avoid error if properties have docstrings, when using numpydoc docstring validation * Enabled numpydoc validation for basic docstring structure * Fixes for GL02 and GL03, concerning extra line breaks within or at the end of the docstring * Fixes for GL06, concerning wrong naming and typos in the main docstring sections * Fixes for GL07, concerning the wrong order of the docstring sections * Fixes for SS03, concerning missing period at the end of the summary (first) sentence. * Fixes for SA02, concerning missing periods at the end of the entries in See Also section. * Fixes for PR02, concerning missing parameters in the docstring (also catches missing space between parameter name and separator :). * Fixes for PR05, concerning periods at the end of the parameter type * Fixes for PR06, concerning wrong parameter types * Fixes related to GL01, concerning missing line-break from the triple quote token * Added GL05, concerning tabs instead of spaces in indentations * Added SS02 and SS04, concerning summary starting with capital letter and no leading spaces * Fixes for PR03, concerning matching the order of parameters in the docstring to the order in the function signature * Fixes for PR08, concerning parameter description not starting with a capital letter. * Comment on PR09, that cannot be used due to the information on defaults * Added PR10, concerning missing space between the colon separator in the parameter type specification * Fixes for SA03, concerning See Also descriptions not starting with capital letter. * Added PR07, for checking undocumented parameters. * Fixes for RT04, concerning that the description of returns start with a capital letter. * Fixes for RT05, concerning that the description of returns ends with a period. * Fixed warnings due to indentations in the window parameter description * Fixed warnings due to indentations in the description of instantaneous_rate returns * Added GL01, with remarks for expected warnings. * Fixed issues related to RT05, concerning the lack of a period at the end of the description of returns. * Fixed typo in doc/conf.py Co-authored-by: Harris Jos <104043391+CozySocksAlways@users.noreply.github.com> --------- Co-authored-by: Harris Jos <104043391+CozySocksAlways@users.noreply.github.com>
1 parent 787f4d2 commit 32f1b56

32 files changed

Lines changed: 336 additions & 427 deletions

doc/conf.py

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,26 @@
2121
# documentation root, use os.path.abspath to make it absolute, like shown here.
2222
sys.path.insert(0, '..')
2323

24+
# -- numpydoc validation compatibility patch -----------------------------
25+
# Property descriptors do not always expose __module__. numpydoc's
26+
# `mangle_docstrings` function that is run during the builtin validation
27+
# accesses `obj.__module__` unconditionally, which raises AttributeError for
28+
# such objects. This patch must be applied here (before Sphinx loads the
29+
# extensions) so that when numpydoc.setup() registers its handler, the patched
30+
# version is used.
31+
import numpydoc.numpydoc as _numpydoc_mod
32+
33+
_orig_mangle_docstrings = _numpydoc_mod.mangle_docstrings
34+
35+
36+
def _safe_mangle_docstrings(app, what, name, obj, options, lines):
37+
if not hasattr(obj, '__module__'):
38+
return
39+
return _orig_mangle_docstrings(app, what, name, obj, options, lines)
40+
41+
42+
_numpydoc_mod.mangle_docstrings = _safe_mangle_docstrings
43+
2444
# -- General configuration -----------------------------------------------
2545
# If your documentation needs a minimal Sphinx version, state it here.
2646
# needs_sphinx = '1.0'
@@ -210,10 +230,34 @@
210230
# Output file base name for HTML help builder.
211231
htmlhelp_basename = 'elephantdoc'
212232

233+
# --- Options for numpydoc ---------------------------------------------
234+
235+
# Validation checks not included:
236+
# - PR09: warnings triggered by the use of "Default: x" in the last line of
237+
# parameter descriptions, which is a common and recommended way to specify
238+
# the default and is more readable without a trailing period.
239+
240+
# Notes:
241+
# - GL01: warnings are triggered for GPFA methods and statistics.cv due to
242+
# non-conforming docstrings in sklearn and SciPy that are inherited.
243+
# - RT05: added in-line exceptions to suppress warnings triggered for functions
244+
# in `phase_analysis` where a trailing period is not used in the last line
245+
# stating the range of the returned values.
246+
247+
numpydoc_validation_checks = {
248+
"GL01", "GL02", "GL03", "GL05", "GL06", "GL07",
249+
"SS02", "SS03", "SS04",
250+
"SA02", "SA03",
251+
"PR02", "PR03", "PR05", "PR06", "PR07", "PR08", "PR10",
252+
"RT04", "RT05",
253+
}
254+
213255
# Suppresses wrong numpy doc warnings
214256
# see here https://github.com/phn/pytpm/issues/3#issuecomment-12133978
215257
numpydoc_show_class_members = False
216258

259+
# --- Options for bibtex -----------------------------------------------
260+
217261
# path to bibtex-bibfiles.
218262
bibtex_bibfiles = ['bib/elephant.bib']
219263

elephant/asset/asset.py

Lines changed: 35 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -420,7 +420,6 @@ def _stretched_metric_2d(x, y, stretch, ref_angle, working_memory=None,
420420
MemoryError
421421
If there is not enough memory to allocate the matrix to store the
422422
pairwise distances when using chunked computations.
423-
424423
"""
425424
alpha = np.deg2rad(ref_angle) # reference angle in radians
426425

@@ -1482,8 +1481,7 @@ def synchronous_events_intersection(sse1, sse2, intersection='linkwise'):
14821481
14831482
See Also
14841483
--------
1485-
ASSET.extract_synchronous_events : extract SSEs from given spike trains
1486-
1484+
ASSET.extract_synchronous_events : Extract SSEs from given spike trains.
14871485
"""
14881486
sse_new = sse1.copy()
14891487
for pixel1 in sse1.keys():
@@ -1550,8 +1548,7 @@ def synchronous_events_difference(sse1, sse2, difference='linkwise'):
15501548
15511549
See Also
15521550
--------
1553-
ASSET.extract_synchronous_events : extract SSEs from given spike trains
1554-
1551+
ASSET.extract_synchronous_events : Extract SSEs from given spike trains.
15551552
"""
15561553
sse_new = sse1.copy()
15571554
for pixel1 in sse1.keys():
@@ -1592,7 +1589,6 @@ def _remove_empty_events(sse):
15921589
-------
15931590
sse_new : dict
15941591
A copy of `sse` where all empty events have been removed.
1595-
15961592
"""
15971593
sse_new = sse.copy()
15981594
for pixel, link in sse.items():
@@ -1633,8 +1629,7 @@ def synchronous_events_identical(sse1, sse2):
16331629
16341630
See Also
16351631
--------
1636-
ASSET.extract_synchronous_events : extract SSEs from given spike trains
1637-
1632+
ASSET.extract_synchronous_events : Extract SSEs from given spike trains.
16381633
"""
16391634
# Remove empty links from sse11 and sse22, if any
16401635
sse11 = _remove_empty_events(sse1)
@@ -1672,8 +1667,7 @@ def synchronous_events_no_overlap(sse1, sse2):
16721667
16731668
See Also
16741669
--------
1675-
ASSET.extract_synchronous_events : extract SSEs from given spike trains
1676-
1670+
ASSET.extract_synchronous_events : Extract SSEs from given spike trains.
16771671
"""
16781672
# Remove empty links from sse11 and sse22, if any
16791673
sse11 = _remove_empty_events(sse1)
@@ -1722,8 +1716,7 @@ def synchronous_events_contained_in(sse1, sse2):
17221716
17231717
See Also
17241718
--------
1725-
ASSET.extract_synchronous_events : extract SSEs from given spike trains
1726-
1719+
ASSET.extract_synchronous_events : Extract SSEs from given spike trains.
17271720
"""
17281721
# Remove empty links from sse11 and sse22, if any
17291722
sse11 = _remove_empty_events(sse1)
@@ -1774,15 +1767,14 @@ def synchronous_events_contains_all(sse1, sse2):
17741767
bool
17751768
True if `sse1` strictly contains `sse2`.
17761769
1770+
See Also
1771+
--------
1772+
ASSET.extract_synchronous_events : Extract SSEs from given spike trains.
1773+
17771774
Notes
17781775
-----
17791776
`synchronous_events_contains_all(sse1, sse2)` is identical to
17801777
`synchronous_events_is_subsequence(sse2, sse1)`.
1781-
1782-
See Also
1783-
--------
1784-
ASSET.extract_synchronous_events : extract SSEs from given spike trains
1785-
17861778
"""
17871779
return synchronous_events_contained_in(sse2, sse1)
17881780

@@ -1815,8 +1807,7 @@ def synchronous_events_overlap(sse1, sse2):
18151807
18161808
See Also
18171809
--------
1818-
ASSET.extract_synchronous_events : extract SSEs from given spike trains
1819-
1810+
ASSET.extract_synchronous_events : Extract SSEs from given spike trains.
18201811
"""
18211812
contained_in = synchronous_events_contained_in(sse1, sse2)
18221813
contains_all = synchronous_events_contains_all(sse1, sse2)
@@ -1844,6 +1835,10 @@ def get_neurons_in_sse(sse):
18441835
list
18451836
All neuron IDs present in the SSE, sorted in ascending order.
18461837
1838+
See Also
1839+
--------
1840+
ASSET.extract_synchronous_events : Extract SSEs from given spike trains.
1841+
18471842
Examples
18481843
--------
18491844
>>> sse = {(268, 51): {22, 27},
@@ -1857,10 +1852,6 @@ def get_neurons_in_sse(sse):
18571852
>>> neurons = get_neurons_in_sse(sse)
18581853
>>> print(neurons)
18591854
[9, 22, 26, 27, 77, 92]
1860-
1861-
See Also
1862-
--------
1863-
ASSET.extract_synchronous_events
18641855
"""
18651856
all_neurons = []
18661857
for neurons in sse.values():
@@ -1897,6 +1888,10 @@ def get_sse_start_and_end_time_bins(sse):
18971888
the second element corresponds to the second sequence (elements `j`
18981889
in the SSE pixel).
18991890
1891+
See Also
1892+
--------
1893+
ASSET.extract_synchronous_events : Extract SSEs from given spike trains.
1894+
19001895
Examples
19011896
--------
19021897
>>> sse = {(268, 51): {22, 27},
@@ -1912,10 +1907,6 @@ def get_sse_start_and_end_time_bins(sse):
19121907
[268, 51]
19131908
>>> print(end)
19141909
[277, 61]
1915-
1916-
See Also
1917-
--------
1918-
ASSET.extract_synchronous_events
19191910
"""
19201911
pixels = list(sse.keys())
19211912
start = list(pixels[0])
@@ -2024,7 +2015,6 @@ class ASSET(object):
20242015
this value.
20252016
Default: 'default'
20262017
2027-
20282018
Raises
20292019
------
20302020
ValueError
@@ -2033,6 +2023,10 @@ class ASSET(object):
20332023
20342024
fully disjoint.
20352025
2026+
See Also
2027+
--------
2028+
:class:`elephant.conversion.BinnedSpikeTrain`
2029+
20362030
Notes
20372031
-----
20382032
To control the verbosity of log messages throughout the ASSET analysis,
@@ -2045,11 +2039,6 @@ class ASSET(object):
20452039
>>> import logging
20462040
>>> from elephant.asset.asset import logger as asset_logger
20472041
>>> asset_logger.setLevel(logging.WARNING)
2048-
2049-
See Also
2050-
--------
2051-
:class:`elephant.conversion.BinnedSpikeTrain`
2052-
20532042
"""
20542043

20552044
def __init__(self, spiketrains_i, spiketrains_j=None, bin_size=3 * pq.ms,
@@ -2131,8 +2120,8 @@ def is_symmetric(self):
21312120
21322121
See Also
21332122
--------
2134-
ASSET.intersection_matrix
2135-
2123+
ASSET.intersection_matrix : Generates the intersection matrix from a
2124+
list of spike trains.
21362125
"""
21372126
return _quantities_almost_equal(self.x_edges[0], self.y_edges[0])
21382127

@@ -2173,7 +2162,6 @@ def intersection_matrix(self, normalization=None):
21732162
The floating point intersection matrix of a list of spike trains.
21742163
It has the shape `(n, n)`, where `n` is the number of bins that
21752164
time was discretized in.
2176-
21772165
"""
21782166
imat = _intersection_matrix(self.spiketrains_i, self.spiketrains_j,
21792167
self.bin_size,
@@ -2244,16 +2232,15 @@ def probability_matrix_montecarlo(self, n_surrogates, imat=None,
22442232
STRICTLY LOWER than the observed overlap, under the null hypothesis
22452233
of independence of the input spike trains.
22462234
2235+
See Also
2236+
--------
2237+
ASSET.probability_matrix_analytical : Analytical derivation of the
2238+
matrix.
2239+
22472240
Notes
22482241
-----
22492242
We recommend playing with `surrogate_dt` parameter to see how it
22502243
influences the result matrix. For this, refer to the ASSET tutorial.
2251-
2252-
See Also
2253-
--------
2254-
ASSET.probability_matrix_analytical : analytical derivation of the
2255-
matrix
2256-
22572244
"""
22582245
if imat is None:
22592246
# Compute the intersection matrix of the original data
@@ -2559,7 +2546,6 @@ def joint_probability_matrix(self, pmat, filter_shape, n_largest,
25592546
caution -using your built-in Intel graphics card to perform
25602547
computations may make the system unresponsive until the compute
25612548
program terminates.
2562-
25632549
"""
25642550
l, w = filter_shape
25652551

@@ -2649,10 +2635,12 @@ def mask_matrices(matrices, thresholds):
26492635
26502636
See Also
26512637
--------
2652-
ASSET.probability_matrix_montecarlo : for `pmat` generation
2653-
ASSET.probability_matrix_analytical : for `pmat` generation
2654-
ASSET.joint_probability_matrix : for `jmat` generation
2655-
2638+
ASSET.probability_matrix_montecarlo : For `pmat` generation using a
2639+
Monte Carlo approach using
2640+
surrogate data.
2641+
ASSET.probability_matrix_analytical : For `pmat` generation using the
2642+
analytical derivation.
2643+
ASSET.joint_probability_matrix : For `jmat` generation.
26562644
"""
26572645
if len(matrices) == 0:
26582646
raise ValueError("Empty list of matrices")
@@ -2766,7 +2754,6 @@ def cluster_matrix_entries(mask_matrix, max_distance, min_neighbors,
27662754
See Also
27672755
--------
27682756
sklearn.cluster.DBSCAN
2769-
27702757
"""
27712758

27722759
# Don't do anything if mat is identically zero

elephant/causality/granger.py

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -189,7 +189,6 @@ def _lag_covariances(signals, dimension, max_lag):
189189
\tau: lag
190190
191191
C(\tau) = \sum_{i=0}^{N-\tau} x[i]*x^T[\tau+i]
192-
193192
"""
194193
length = np.size(signals[0])
195194

@@ -243,7 +242,6 @@ def _yule_walker_matrix(data, dimension, order):
243242
where 1 \leq i \leq j \leq p. The other entries are determined by
244243
symmetry.
245244
lag_covariances : np.ndarray
246-
247245
"""
248246

249247
lag_covariances = _lag_covariances(data, dimension, order)
@@ -299,7 +297,6 @@ def _vector_arm(signals, dimension, order):
299297
ry
300298
covar_mat : np.ndarray
301299
covariance matrix of
302-
303300
"""
304301

305302
yule_walker_matrix, lag_covariances = \
@@ -473,7 +470,6 @@ def _spectral_factorization(cross_spectrum, num_iterations, term_crit=1e-12):
473470
factorization
474471
Default: 1e-12
475472
476-
477473
Returns
478474
------
479475
cov_matrix : np.ndarray
@@ -545,7 +541,7 @@ def _spectral_factorization(cross_spectrum, num_iterations, term_crit=1e-12):
545541

546542
def pairwise_granger(signals, max_order, information_criterion='aic'):
547543
r"""
548-
Determine Granger Causality of two time series
544+
Determine Granger Causality of two time series.
549545
550546
Parameters
551547
----------
@@ -644,7 +640,6 @@ def pairwise_granger(signals, max_order, information_criterion='aic'):
644640
>>> signals = np.array([x[1:], y]).T # N x 2 matrix
645641
>>> pairwise_granger(signals, max_order=1) # noqa
646642
Causality(directional_causality_x_y=2.64, directional_causality_y_x=-0.0, instantaneous_causality=0.0, total_interdependence=2.64)
647-
648643
"""
649644
if isinstance(signals, AnalogSignal):
650645
signals = signals.magnitude
@@ -789,7 +784,8 @@ def pairwise_spectral_granger(signal_i, signal_j, fs=1, nw=4, num_tapers=None,
789784
len_segment=None, frequency_resolution=None,
790785
overlap=0.5, num_iterations=300,
791786
term_crit=1e-12):
792-
r"""Determine spectral Granger Causality of two signals.
787+
r"""
788+
Determine spectral Granger Causality of two signals.
793789
794790
The spectral Granger Causality is obtained through the following steps:
795791

elephant/cell_assembly_detection.py

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -191,7 +191,6 @@ def cell_assembly_detection(binned_spiketrain, max_lag, reference_lag=2,
191191
Notes
192192
-----
193193
Alias: cad
194-
195194
"""
196195
initial_time = time.time()
197196

@@ -599,7 +598,6 @@ def _test_pair(ensemble, spiketrain2, n2, max_lag, size_chunks, reference_lag,
599598
item_candidate : list of list with two components
600599
in the first component there are the neurons involved in the assembly,
601600
in the second there are the correspondent lags.
602-
603601
"""
604602

605603
# list with the binned spike trains of the two neurons
@@ -1062,7 +1060,6 @@ def _subgroup_pruning_step(pre_pruning_assembly):
10621060
--------
10631061
final_assembly : list
10641062
contains the assemblies filtered by inclusion
1065-
10661063
"""
10671064

10681065
# reversing the semifinal_assembly makes the computation quicker
@@ -1140,7 +1137,6 @@ def _raise_errors(binned_spiketrain, max_lag, alpha, min_occurrences,
11401137
if the maximal assembly order is not between 2
11411138
and the number of neurons
11421139
if the time series is too short (less than 100 bins)
1143-
11441140
"""
11451141

11461142
if not isinstance(binned_spiketrain, conv.BinnedSpikeTrain):

0 commit comments

Comments
 (0)