Skip to content

Commit ac09411

Browse files
docs: improve NumPy-style docstrings in internal modules (#462)
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
1 parent 5dab17e commit ac09411

4 files changed

Lines changed: 237 additions & 52 deletions

File tree

brainrender/_colors.py

Lines changed: 65 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,43 @@
1+
"""Color mapping and palette utilities for brainrender."""
2+
13
import random
24

35
import matplotlib as mpl
46
import numpy as np
7+
import numpy.typing as npt
58
from vedo.colors import colors as vcolors
69
from vedo.colors import get_color as getColor
710

811

9-
def map_color(value, name="jet", vmin=None, vmax=None):
10-
"""Map a real value in range [vmin, vmax] to a (r,g,b) color scale.
12+
def map_color(
13+
value: float,
14+
name: str = "jet",
15+
vmin: float | None = None,
16+
vmax: float | None = None,
17+
) -> tuple[float, float, float]:
18+
"""
19+
Map a scalar value in ``[vmin, vmax]`` to an RGB colour.
20+
21+
Parameters
22+
----------
23+
value
24+
Scalar value to transform into a colour.
25+
name
26+
Colormap name or matplotlib colormap. Default ``"jet"``.
27+
vmin
28+
Lower bound of the value range.
29+
vmax
30+
Upper bound of the value range.
1131
12-
:param value: scalar value to transform into a color
13-
:type value: float, list
14-
:param name: color map name (Default value = "jet")
15-
:type name: str, matplotlib.colors.LinearSegmentedColorMap
16-
:param vmin: (Default value = None)
17-
:param vmax: (Default value = None)
18-
:returns: return: (r,g,b) color, or a list of (r,g,b) colors.
32+
Returns
33+
-------
34+
tuple of float
35+
``(r, g, b)`` colour.
36+
37+
Raises
38+
------
39+
ValueError
40+
If ``vmax`` is smaller than ``vmin``.
1941
"""
2042
if vmax < vmin:
2143
raise ValueError("vmax should be larger than vmin")
@@ -31,13 +53,29 @@ def map_color(value, name="jet", vmin=None, vmax=None):
3153
return mp(value)[0:3]
3254

3355

34-
def make_palette(N, *colors):
35-
"""Generate N colors starting from `color1` to `color2`
36-
by linear interpolation HSV in or RGB spaces.
37-
Adapted from vedo make_palette function
56+
def make_palette(N: int, *colors: str) -> list[npt.NDArray]:
57+
"""
58+
Generate N colours interpolated across the given input colours.
59+
60+
Adapted from vedo's ``make_palette`` function. Interpolation is
61+
performed in RGB space.
62+
63+
Parameters
64+
----------
65+
N
66+
Number of output colours.
67+
*colors
68+
Input colours. Any number between 1 and N is accepted.
69+
70+
Returns
71+
-------
72+
list of numpy.ndarray
73+
List of ``(r, g, b)`` colour arrays.
3874
39-
:param int: N: number of output colors.
40-
:param colors: input colors, any number of colors with 0 < ncolors <= N is okay.
75+
Raises
76+
------
77+
ValueError
78+
If no colours are passed or more colours than N are passed.
4179
"""
4280
N = int(N)
4381

@@ -72,9 +110,19 @@ def make_palette(N, *colors):
72110
return output
73111

74112

75-
def get_random_colors(n_colors=1):
113+
def get_random_colors(n_colors: int = 1) -> str | list[str]:
76114
"""
77-
:param n_colors: (Default value = 1)
115+
Return one or more random colour names from vedo's colour palette.
116+
117+
Parameters
118+
----------
119+
n_colors
120+
Number of colours to return. Default 1.
121+
122+
Returns
123+
-------
124+
str or list of str
125+
A single colour name if ``n_colors == 1``, otherwise a list.
78126
"""
79127
col_names = list(vcolors.keys())
80128
if n_colors == 1:

brainrender/_io.py

Lines changed: 93 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,34 @@
1+
"""File I/O and network utilities for brainrender."""
2+
3+
from collections.abc import Callable
14
from pathlib import Path
5+
from typing import Any, ParamSpec, TypeVar
26

37
import requests
4-
from vedo import Mesh, load
8+
from vedo import Mesh, Volume, load
9+
10+
P = ParamSpec("P")
11+
R = TypeVar("R")
512

613

7-
def connected_to_internet(url="http://www.google.com/", timeout=5):
14+
def connected_to_internet(
15+
url: str = "http://www.google.com/",
16+
timeout: int = 5,
17+
) -> bool:
818
"""
9-
Check that there is an internet connection
19+
Check that there is an internet connection.
20+
21+
Parameters
22+
----------
23+
url
24+
URL to use for testing. Default ``"http://www.google.com/"``.
25+
timeout
26+
Timeout in seconds. Default 5.
1027
11-
:param url: url to use for testing (Default value = 'http://www.google.com/')
12-
:param timeout: timeout to wait for [in seconds] (Default value = 5)
28+
Returns
29+
-------
30+
bool
31+
``True`` if an internet connection is available, otherwise ``False``.
1332
"""
1433

1534
try:
@@ -20,27 +39,54 @@ def connected_to_internet(url="http://www.google.com/", timeout=5):
2039
return False
2140

2241

23-
def fail_on_no_connection(func):
42+
def fail_on_no_connection(func: Callable[P, R]) -> Callable[P, R]:
2443
"""
25-
Decorator that throws an error if no internet connection is available
44+
Decorator that raises an error if no internet connection is available.
45+
46+
Parameters
47+
----------
48+
func
49+
Function to wrap.
50+
51+
Returns
52+
-------
53+
collections.abc.Callable
54+
55+
Raises
56+
------
57+
ConnectionError
58+
If no internet connection is found.
2659
"""
2760
if not connected_to_internet(): # pragma: no cover
2861
raise ConnectionError(
2962
"No internet connection found."
3063
) # pragma: no cover
3164

32-
def inner(*args, **kwargs):
65+
def inner(*args: Any, **kwargs: Any) -> Any:
3366
return func(*args, **kwargs)
3467

3568
return inner
3669

3770

38-
def request(url):
71+
def request(url: str) -> requests.Response:
3972
"""
40-
Sends a request to a url
73+
Send a GET request to a URL.
4174
42-
:param url:
75+
Parameters
76+
----------
77+
url
78+
URL to request.
4379
80+
Returns
81+
-------
82+
requests.Response
83+
84+
Raises
85+
------
86+
ConnectionError
87+
If no internet connection is found.
88+
ValueError
89+
If the request fails.
4490
"""
4591
if not connected_to_internet(): # pragma: no cover
4692
raise ConnectionError(
@@ -57,13 +103,29 @@ def request(url):
57103
raise ValueError(exception_string)
58104

59105

60-
def check_file_exists(func): # pragma: no cover
106+
def check_file_exists(
107+
func: Callable[P, R],
108+
) -> Callable[P, R]: # pragma: no cover
61109
"""
62-
Decorator that throws an error if a function;s first argument
110+
Decorator that raises an error if a function's first argument
63111
is not a path to an existing file.
112+
113+
Parameters
114+
----------
115+
func
116+
Function to wrap.
117+
118+
Returns
119+
-------
120+
collections.abc.Callable
121+
122+
Raises
123+
------
124+
FileNotFoundError
125+
If the file does not exist.
64126
"""
65127

66-
def inner(*args, **kwargs):
128+
def inner(*args: Any, **kwargs: Any) -> Any:
67129
if not Path(args[0]).exists():
68130
raise FileNotFoundError(
69131
f"File {args[0]} not found"
@@ -74,13 +136,26 @@ def inner(*args, **kwargs):
74136

75137

76138
@check_file_exists
77-
def load_mesh_from_file(filepath, color=None, alpha=None):
139+
def load_mesh_from_file(
140+
filepath: str | Path,
141+
color: str | None = None,
142+
alpha: float | None = None,
143+
) -> Mesh | Volume:
78144
"""
79-
Load a a mesh or volume from files like .obj, .stl, ...
145+
Load a mesh or volume from a file (e.g. .obj, .stl).
80146
81-
:param filepath: path to file
82-
:param **kwargs:
147+
Parameters
148+
----------
149+
filepath
150+
Path to the mesh file.
151+
color
152+
Colour to apply to the mesh.
153+
alpha
154+
Transparency to apply to the mesh.
83155
156+
Returns
157+
-------
158+
vedo.Mesh or vedo.Volume
84159
"""
85160
actor = load(str(filepath))
86161
actor.c(color).alpha(alpha)

brainrender/_utils.py

Lines changed: 48 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,55 @@
1+
"""General utility helpers for file system traversal and list manipulation."""
2+
13
from pathlib import Path
4+
from typing import TypeVar
5+
6+
T = TypeVar("T")
27

38

4-
def listdir(fld):
9+
def listdir(fld: str | Path) -> list[str]:
510
"""
611
List the files into a folder with the complete file path instead of the relative file path like os.listdir.
712
8-
:param fld: string, folder path
13+
Parameters
14+
----------
15+
fld
16+
Path to the folder.
917
18+
Returns
19+
-------
20+
list of str
1021
"""
1122
return [str(f) for f in Path(fld).glob("**/*") if f.is_file()]
1223

1324

14-
def get_subdirs(folderpath):
25+
def get_subdirs(folderpath: str | Path) -> list[str]:
1526
"""
16-
Returns the subfolders in a given folder
27+
Return all subdirectories in a given folder.
28+
29+
Parameters
30+
----------
31+
folderpath
32+
Path to the folder.
33+
34+
Returns
35+
-------
36+
list of str
1737
"""
1838
return [str(f) for f in Path(folderpath).glob("**/*") if f.is_dir()]
1939

2040

21-
def listify(obj):
41+
def listify(obj: T | list[T] | tuple[T, ...]) -> list[T]:
2242
"""
23-
Makes sure that the obj is a list
43+
Ensure the object is a list.
44+
45+
Parameters
46+
----------
47+
obj
48+
Object to listify.
49+
50+
Returns
51+
-------
52+
list
2453
"""
2554
if isinstance(obj, list):
2655
return obj
@@ -30,11 +59,20 @@ def listify(obj):
3059
return [obj]
3160

3261

33-
def return_list_smart(lst):
62+
def return_list_smart(lst: list[T]) -> list[T] | T | None:
3463
"""
35-
If the list has length > 1 returns the list
36-
if it has length == 1 it returns the element
37-
if it has length == 0 it returns None
64+
Return a list, single element, or None depending on list length.
65+
66+
Parameters
67+
----------
68+
lst
69+
Input list.
70+
71+
Returns
72+
-------
73+
list, Any, or None
74+
The list if length > 1, the single item if length == 1,
75+
or None if empty.
3876
"""
3977
if len(lst) > 1:
4078
return lst

0 commit comments

Comments
 (0)