Skip to content

Commit 147cbee

Browse files
authored
Fixes all docstrings and adds lint for docstrings (#134)
* ran ruff pydocstyle ruleset * attributes -> parameters * fixed all docstrings * set convention and fix some issues * review fixes
1 parent abded50 commit 147cbee

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

47 files changed

+452
-164
lines changed

RATapi/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
"""RATapi is a Python package for modelling, fitting and optimising reflectivity problems."""
2+
13
import RATapi.examples as examples
24
from RATapi import events, models
35
from RATapi.classlist import ClassList

RATapi/classlist.py

Lines changed: 45 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
1-
"""The classlist module. Contains the ClassList class, which defines a list containing instances of a particular
2-
class.
3-
"""
1+
"""The ClassList class, which defines a list containing instances of a particular class."""
42

53
import collections
64
import contextlib
@@ -24,12 +22,12 @@ class ClassList(collections.UserList, Generic[T]):
2422
attribute given in the ClassList's "name_field" attribute (the default is "name"), the ClassList will ensure that
2523
all objects within the ClassList have unique values for that attribute. It is then possible to use this attribute
2624
of an object in the .remove(), .count(), and .index() routines in place of the full object. Due to the requirement
27-
of unique values of the name_field attribute, the multiplication operators __mul__, __rmul__, and __imul__ have
25+
of unique values of the ``name_field`` attribute, the multiplication operators __mul__, __rmul__, and __imul__ have
2826
been disabled, since they cannot allow for unique attribute values by definition.
2927
3028
We extend the UserList class to enable objects to be added and modified using just the keyword arguments, enable
31-
the object name_field attribute to be used in place of the full object, and ensure all elements are of the
32-
specified type, with unique name_field attributes defined.
29+
the object ``name_field`` attribute to be used in place of the full object, and ensure all elements are of the
30+
specified type, with unique ``name_field`` attributes defined.
3331
3432
Parameters
3533
----------
@@ -171,8 +169,9 @@ def __imul__(self, n: int) -> None:
171169
raise TypeError(f"unsupported operand type(s) for *=: '{self.__class__.__name__}' and '{n.__class__.__name__}'")
172170

173171
def append(self, obj: T = None, **kwargs) -> None:
174-
"""Append a new object to the ClassList using either the object itself, or keyword arguments to set attribute
175-
values.
172+
"""Append a new object to the ClassList.
173+
174+
This method can use the object itself, or can provide attribute values as keyword arguments for a new object.
176175
177176
Parameters
178177
----------
@@ -184,7 +183,7 @@ def append(self, obj: T = None, **kwargs) -> None:
184183
Raises
185184
------
186185
ValueError
187-
Raised if the input arguments contain a name_field value already defined in the ClassList.
186+
Raised if the input arguments contain a ``name_field`` value already defined in the ClassList.
188187
189188
Warnings
190189
--------
@@ -216,8 +215,9 @@ def append(self, obj: T = None, **kwargs) -> None:
216215
self.data.append(self._class_handle(**kwargs))
217216

218217
def insert(self, index: int, obj: T = None, **kwargs) -> None:
219-
"""Insert a new object into the ClassList at a given index using either the object itself, or keyword arguments
220-
to set attribute values.
218+
"""Insert a new object at a given index.
219+
220+
This method can use the object itself, or can provide attribute values as keyword arguments for a new object.
221221
222222
Parameters
223223
----------
@@ -231,7 +231,7 @@ def insert(self, index: int, obj: T = None, **kwargs) -> None:
231231
Raises
232232
------
233233
ValueError
234-
Raised if the input arguments contain a name_field value already defined in the ClassList.
234+
Raised if the input arguments contain a ``name_field`` value already defined in the ClassList.
235235
236236
Warnings
237237
--------
@@ -263,20 +263,25 @@ def insert(self, index: int, obj: T = None, **kwargs) -> None:
263263
self.data.insert(index, self._class_handle(**kwargs))
264264

265265
def remove(self, item: Union[T, str]) -> None:
266-
"""Remove an object from the ClassList using either the object itself or its name_field value."""
266+
"""Remove an object from the ClassList using either the object itself or its ``name_field`` value."""
267267
item = self._get_item_from_name_field(item)
268268
self.data.remove(item)
269269

270270
def count(self, item: Union[T, str]) -> int:
271-
"""Return the number of times an object appears in the ClassList using either the object itself or its
272-
name_field value.
271+
"""Return the number of times an object appears in the ClassList.
272+
273+
This method can use either the object itself or its ``name_field`` value.
274+
273275
"""
274276
item = self._get_item_from_name_field(item)
275277
return self.data.count(item)
276278

277279
def index(self, item: Union[T, str], offset: bool = False, *args) -> int:
278-
"""Return the index of a particular object in the ClassList using either the object itself or its
279-
name_field value. If offset is specified, add one to the index. This is used to account for one-based indexing.
280+
"""Return the index of a particular object in the ClassList.
281+
282+
This method can use either the object itself or its ``name_field`` value.
283+
If offset is specified, add one to the index. This is used to account for one-based indexing.
284+
280285
"""
281286
item = self._get_item_from_name_field(item)
282287
return self.data.index(item, *args) + int(offset)
@@ -357,12 +362,12 @@ def __exit__(self, exctype, excinst, exctb):
357362
self._class_handle.model_validate(self.data[index])
358363

359364
def get_names(self) -> list[str]:
360-
"""Return a list of the values of the name_field attribute of each class object in the list.
365+
"""Return a list of the values of the ``name_field`` attribute of each class object in the list.
361366
362367
Returns
363368
-------
364369
names : list [str]
365-
The value of the name_field attribute of each object in the ClassList.
370+
The value of the ``name_field`` attribute of each object in the ClassList.
366371
367372
"""
368373
return [getattr(model, self.name_field) for model in self.data if hasattr(model, self.name_field)]
@@ -389,8 +394,7 @@ def get_all_matches(self, value: Any) -> list[tuple]:
389394
]
390395

391396
def _validate_name_field(self, input_args: dict[str, Any]) -> None:
392-
"""Raise a ValueError if the name_field attribute is passed as an object parameter, and its value is already
393-
used within the ClassList.
397+
"""Raise a ValueError if the user tries to add an object with a ``name_field`` already in the ClassList.
394398
395399
Parameters
396400
----------
@@ -400,7 +404,7 @@ def _validate_name_field(self, input_args: dict[str, Any]) -> None:
400404
Raises
401405
------
402406
ValueError
403-
Raised if the input arguments contain a name_field value already defined in the ClassList.
407+
Raised if the input arguments contain a ``name_field`` value already defined in the ClassList.
404408
405409
"""
406410
names = [name.lower() for name in self.get_names()]
@@ -413,8 +417,7 @@ def _validate_name_field(self, input_args: dict[str, Any]) -> None:
413417
)
414418

415419
def _check_unique_name_fields(self, input_list: Sequence[T]) -> None:
416-
"""Raise a ValueError if any value of the name_field attribute is used more than once in a list of class
417-
objects.
420+
"""Raise a ValueError if any value of the ``name_field`` attribute is repeated in a list of class objects.
418421
419422
Parameters
420423
----------
@@ -470,17 +473,17 @@ def _check_unique_name_fields(self, input_list: Sequence[T]) -> None:
470473
)
471474

472475
def _check_classes(self, input_list: Sequence[T]) -> None:
473-
"""Raise a ValueError if any object in a list of objects is not of the type specified by self._class_handle.
476+
"""Raise a ValueError if any object in a list of objects is not of the type specified by ``self._class_handle``.
474477
475478
Parameters
476479
----------
477480
input_list : iterable
478-
A list of instances of the class given in self._class_handle.
481+
A list of instances of the class given in ``self._class_handle``.
479482
480483
Raises
481484
------
482485
ValueError
483-
Raised if the input list contains objects of any type other than that given in self._class_handle.
486+
If the input list contains objects of any type other than that given in ``self._class_handle``.
484487
485488
"""
486489
error_list = []
@@ -495,18 +498,18 @@ def _check_classes(self, input_list: Sequence[T]) -> None:
495498
)
496499

497500
def _get_item_from_name_field(self, value: Union[T, str]) -> Union[T, str]:
498-
"""Return the object with the given value of the name_field attribute in the ClassList.
501+
"""Return the object with the given value of the ``name_field`` attribute in the ClassList.
499502
500503
Parameters
501504
----------
502505
value : T or str
503-
Either an object in the ClassList, or the value of the name_field attribute of an object in the ClassList.
506+
Either an object in the ClassList, or the value of the ``name_field`` for an object in the ClassList.
504507
505508
Returns
506509
-------
507510
instance : T or str
508-
Either the object with the value of the name_field attribute given by value, or the input value if an
509-
object with that value of the name_field attribute cannot be found.
511+
Either the object with the value of the ``name_field`` attribute given by value, or the input value if an
512+
object with that value of the ``name_field`` attribute cannot be found.
510513
511514
"""
512515
try:
@@ -518,24 +521,27 @@ def _get_item_from_name_field(self, value: Union[T, str]) -> Union[T, str]:
518521

519522
@staticmethod
520523
def _determine_class_handle(input_list: Sequence[T]):
521-
"""When inputting a sequence of object to a ClassList, the _class_handle should be set as the type of the
522-
element which satisfies "issubclass" for all the other elements.
524+
"""Determine the class handle from a sequence of objects.
525+
526+
The ``_class_handle`` of the sequence is the type of the first element in the sequence
527+
which is a subclass of all elements in the sequence. If no such element exists, the handle
528+
is set to be the type of the first element in the list.
523529
524530
Parameters
525531
----------
526-
input_list : Sequence [object]
532+
input_list : Sequence[T]
527533
A list of instances to populate the ClassList.
528534
529535
Returns
530536
-------
531537
class_handle : type
532-
The type object of the element fulfilling the condition of satisfying "issubclass" for all of the other
533-
elements.
538+
The type object of the first element which is a subclass of all of the other
539+
elements, or the first element if no such element exists.
534540
535541
"""
536-
for this_element in input_list:
537-
if all([issubclass(type(instance), type(this_element)) for instance in input_list]):
538-
class_handle = type(this_element)
542+
for element in input_list:
543+
if all(issubclass(type(instance), type(element)) for instance in input_list):
544+
class_handle = type(element)
539545
break
540546
else:
541547
class_handle = type(input_list[0])

RATapi/controls.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
"""The Controls class for providing RAT algorithm settings."""
2+
13
import contextlib
24
import os
35
import tempfile
@@ -196,19 +198,20 @@ def __str__(self) -> str:
196198
return table.get_string()
197199

198200
def initialise_IPC(self):
199-
"""Setup the inter-process communication file."""
201+
"""Set up the inter-process communication file."""
200202
IPC_obj, self._IPCFilePath = tempfile.mkstemp()
201203
os.write(IPC_obj, b"0")
202204
os.close(IPC_obj)
203205
return None
204206

205207
def sendStopEvent(self):
206-
"""Sends the stop event via the inter-process communication file.
208+
"""Send the stop event via the inter-process communication file.
207209
208210
Warnings
209211
--------
210212
UserWarning
211213
Raised if we try to delete an IPC file that was not initialised.
214+
212215
"""
213216
if os.path.isfile(self._IPCFilePath):
214217
with open(self._IPCFilePath, "wb") as f:

RATapi/events.py

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
1+
"""Hooks for connecting to run callback events."""
2+
13
import os
24
from typing import Callable, Union
35

46
from RATapi.rat_core import EventBridge, EventTypes, PlotEventData, ProgressEventData
57

68

79
def notify(event_type: EventTypes, data: Union[str, PlotEventData, ProgressEventData]) -> None:
8-
"""Calls registered callbacks with the data when event type has
9-
been triggered.
10+
"""Call registered callbacks with data when event type has been triggered.
1011
1112
Parameters
1213
----------
@@ -22,7 +23,7 @@ def notify(event_type: EventTypes, data: Union[str, PlotEventData, ProgressEvent
2223

2324

2425
def get_event_callback(event_type: EventTypes) -> list[Callable[[Union[str, PlotEventData, ProgressEventData]], None]]:
25-
"""Returns all callbacks registered for the given event type.
26+
"""Return all callbacks registered for the given event type.
2627
2728
Parameters
2829
----------
@@ -39,7 +40,7 @@ def get_event_callback(event_type: EventTypes) -> list[Callable[[Union[str, Plot
3940

4041

4142
def register(event_type: EventTypes, callback: Callable[[Union[str, PlotEventData, ProgressEventData]], None]) -> None:
42-
"""Registers a new callback for the event type.
43+
"""Register a new callback for the event type.
4344
4445
Parameters
4546
----------
@@ -58,12 +59,14 @@ def register(event_type: EventTypes, callback: Callable[[Union[str, PlotEventDat
5859

5960

6061
def clear(key=None, callback=None) -> None:
61-
"""Clears all event callbacks or specific callback.
62+
"""Clear all event callbacks or specific callback.
6263
6364
Parameters
6465
----------
65-
callback : Callable[[Union[str, PlotEventData, ProgressEventData]], None]
66-
The callback for when the event is triggered.
66+
key : EventTypes, optional
67+
The event type of the callback to clear if given.
68+
callback : Callable[[Union[str, PlotEventData, ProgressEventData]], None], optional
69+
A callback for an event which will be cleared if given.
6770
6871
"""
6972
if key is None and callback is None:

RATapi/examples/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
"""Usage examples for the Python RAT API."""
2+
13
from RATapi.examples.absorption.absorption import absorption
24
from RATapi.examples.convert_rascal_project.convert_rascal import convert_rascal
35
from RATapi.examples.domains.domains_custom_layers import domains_custom_layers
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
"""An example of using absorption in a RAT project."""

RATapi/examples/absorption/absorption.py

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
"""An example for using absorption in RAT."""
2+
13
import pathlib
24

35
import numpy as np
@@ -6,7 +8,17 @@
68

79

810
def absorption():
9-
"""Custom layers model including absorption"""
11+
"""Run a custom layers model including absorption.
12+
13+
RAT allows the use of an imaginary, as well as real part of the SLD.
14+
The effect of this is usually seen below the critical edge, and must sometimes be accounted for.
15+
16+
This is an example of a Custom Layers project using absorption. used here is Custom Layers.
17+
It analyses a bilayer sample on a permalloy / gold substrate,
18+
measured using polarised neutrons, against D2O and H2O, leading to 4 contrasts in total.
19+
Absorption (i.e. imaginary SLD) is defined for Gold and the Permalloy,
20+
to account for non-flat data below the critical edge.
21+
"""
1022
problem = RAT.Project(
1123
name="Absorption example",
1224
calculation="normal",

RATapi/examples/absorption/volume_thiol_bilayer.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
"""Custom layer model file for the absorption example."""
2+
3+
14
def volume_thiol_bilayer(params, bulk_in, bulk_out, contrast):
25
"""VolumeThiolBilayer RAT Custom Layer Model File.
36

RATapi/examples/bayes_benchmark/bayes_benchmark.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
"""
1+
"""An example script to compare different methods of Bayesian fitting.
2+
23
This example compares three Bayesian posteriors for a low-dimensional
34
example: a posterior generated by DREAM, one generated by NS, and
45
one calculated directly.
@@ -34,6 +35,7 @@
3435
# this is the RasCAL-1 default project
3536
# it is a bare D2O substrate
3637
def get_project() -> RAT.Project:
38+
"""Create the project used as our example."""
3739
return RAT.Project(
3840
name="Bare D2O Substrate",
3941
calculation="normal",
@@ -191,6 +193,7 @@ def calculate_posterior(roughness_index: int, background_index: int) -> float:
191193
-------
192194
float
193195
The value of exp(-chi^2 / 2) for the given roughness and background values.
196+
194197
"""
195198
problem.parameters[0].value = roughness[roughness_index]
196199
problem.background_parameters[0].value = background[background_index]
@@ -265,6 +268,7 @@ def calculate_posterior(roughness_index: int, background_index: int, scalefactor
265268
-------
266269
float
267270
The value of exp(-chi^2 / 2) for the given roughness and background values.
271+
268272
"""
269273
problem.parameters[0].value = roughness[roughness_index]
270274
problem.background_parameters[0].value = background[background_index]
@@ -300,6 +304,7 @@ def plot_posterior_comparison(
300304
The BayesResults object from a DREAM calculation.
301305
calc_results : CalculationResults
302306
The results from a direct calculation.
307+
303308
"""
304309
num_params = calc_results.distribution.ndim
305310
fig, axes = plt.subplots(3, num_params, figsize=(3 * num_params, 9))

RATapi/examples/convert_rascal_project/Model_IIb.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
1+
"""A custom model file for a monolayer volume model."""
2+
13
from math import cos, radians
24

35

46
def Model_IIb(params, bulk_in, bulk_out, contrast):
7+
"""Calculate layer parameters for a monolayer volume model at two deuterations."""
58
# converted from matlab file Model_IIb.m
69

710
Roughness, APM, thickHead, theta = params

0 commit comments

Comments
 (0)