|
| 1 | +from __future__ import annotations |
| 2 | + |
| 3 | +import re |
1 | 4 | import textwrap
|
2 | 5 |
|
3 | 6 | from xarray.core.dataset import Dataset
|
4 |
| - |
5 | 7 | from xarray.core.datatree_mapping import map_over_subtree
|
6 | 8 |
|
7 | 9 | """
|
|
12 | 14 | """
|
13 | 15 |
|
14 | 16 |
|
15 |
| -_MAPPED_DOCSTRING_ADDENDUM = textwrap.fill( |
| 17 | +_MAPPED_DOCSTRING_ADDENDUM = ( |
16 | 18 | "This method was copied from xarray.Dataset, but has been altered to "
|
17 | 19 | "call the method on the Datasets stored in every node of the subtree. "
|
18 |
| - "See the `map_over_subtree` function for more details.", |
19 |
| - width=117, |
| 20 | + "See the `map_over_subtree` function for more details." |
20 | 21 | )
|
21 | 22 |
|
22 | 23 | # TODO equals, broadcast_equals etc.
|
@@ -173,7 +174,7 @@ def _wrap_then_attach_to_cls(
|
173 | 174 | target_cls_dict, source_cls, methods_to_set, wrap_func=None
|
174 | 175 | ):
|
175 | 176 | """
|
176 |
| - Attach given methods on a class, and optionally wrap each method first. (i.e. with map_over_subtree) |
| 177 | + Attach given methods on a class, and optionally wrap each method first. (i.e. with map_over_subtree). |
177 | 178 |
|
178 | 179 | Result is like having written this in the classes' definition:
|
179 | 180 | ```
|
@@ -208,16 +209,62 @@ def method_name(self, *args, **kwargs):
|
208 | 209 | if wrap_func is map_over_subtree:
|
209 | 210 | # Add a paragraph to the method's docstring explaining how it's been mapped
|
210 | 211 | orig_method_docstring = orig_method.__doc__
|
211 |
| - # if orig_method_docstring is not None: |
212 |
| - # if "\n" in orig_method_docstring: |
213 |
| - # new_method_docstring = orig_method_docstring.replace( |
214 |
| - # "\n", _MAPPED_DOCSTRING_ADDENDUM, 1 |
215 |
| - # ) |
216 |
| - # else: |
217 |
| - # new_method_docstring = ( |
218 |
| - # orig_method_docstring + f"\n\n{_MAPPED_DOCSTRING_ADDENDUM}" |
219 |
| - # ) |
220 |
| - setattr(target_cls_dict[method_name], "__doc__", orig_method_docstring) |
| 212 | + |
| 213 | + if orig_method_docstring is not None: |
| 214 | + new_method_docstring = insert_doc_addendum( |
| 215 | + orig_method_docstring, _MAPPED_DOCSTRING_ADDENDUM |
| 216 | + ) |
| 217 | + setattr(target_cls_dict[method_name], "__doc__", new_method_docstring) |
| 218 | + |
| 219 | + |
| 220 | +def insert_doc_addendum(docstring: str | None, addendum: str) -> str | None: |
| 221 | + """Insert addendum after first paragraph or at the end of the docstring. |
| 222 | +
|
| 223 | + There are a number of Dataset's functions that are wrapped. These come from |
| 224 | + Dataset directly as well as the mixins: DataWithCoords, DatasetAggregations, and DatasetOpsMixin. |
| 225 | +
|
| 226 | + The majority of the docstrings fall into a parseable pattern. Those that |
| 227 | + don't, just have the addendum appeneded after. None values are returned. |
| 228 | +
|
| 229 | + """ |
| 230 | + if docstring is None: |
| 231 | + return None |
| 232 | + |
| 233 | + pattern = re.compile( |
| 234 | + r"^(?P<start>(\S+)?(.*?))(?P<paragraph_break>\n\s*\n)(?P<whitespace>[ ]*)(?P<rest>.*)", |
| 235 | + re.DOTALL, |
| 236 | + ) |
| 237 | + capture = re.match(pattern, docstring) |
| 238 | + if capture is None: |
| 239 | + ### single line docstring. |
| 240 | + return ( |
| 241 | + docstring |
| 242 | + + "\n\n" |
| 243 | + + textwrap.fill( |
| 244 | + addendum, |
| 245 | + subsequent_indent=" ", |
| 246 | + width=79, |
| 247 | + ) |
| 248 | + ) |
| 249 | + |
| 250 | + if len(capture.groups()) == 6: |
| 251 | + return ( |
| 252 | + capture["start"] |
| 253 | + + capture["paragraph_break"] |
| 254 | + + capture["whitespace"] |
| 255 | + + ".. note::\n" |
| 256 | + + textwrap.fill( |
| 257 | + addendum, |
| 258 | + initial_indent=capture["whitespace"] + " ", |
| 259 | + subsequent_indent=capture["whitespace"] + " ", |
| 260 | + width=79, |
| 261 | + ) |
| 262 | + + capture["paragraph_break"] |
| 263 | + + capture["whitespace"] |
| 264 | + + capture["rest"] |
| 265 | + ) |
| 266 | + else: |
| 267 | + return docstring |
221 | 268 |
|
222 | 269 |
|
223 | 270 | class MappedDatasetMethodsMixin:
|
|
0 commit comments