diff --git a/Changelog b/Changelog index 06cbf74fd..cd3c2b005 100644 --- a/Changelog +++ b/Changelog @@ -36,7 +36,7 @@ tested up to Python 3.12 and NumPy 1.26. New features ------------ * Add generic :class:`~nibabel.pointset.Pointset` and regularly spaced - :class:`~nibabel.pointset.NDGrid` data structures in preparation for coordinate + :class:`~nibabel.pointset.Grid` data structures in preparation for coordinate transformation and resampling (pr/1251) (CM, reviewed by Oscar Esteban) Enhancements @@ -44,7 +44,7 @@ Enhancements * Add :meth:`~nibabel.arrayproxy.ArrayProxy.copy` method to :class:`~nibabel.arrayproxy.ArrayProxy` (pr/1255) (CM, reviewed by Paul McCarthy) * Permit :meth:`~nibabel.xmlutils.XmlSerializable.to_xml` to pass keyword - arguments to :meth:`~xml.etree.ElementTree.ElementTree.tostring` (pr/1258) + arguments to :meth:`~xml.etree.ElementTree.tostring` (pr/1258) (CM) * Allow user expansion (e.g., ``~/...``) in strings passed to functions that accept paths (pr/1260) (Reinder Vos de Wael, reviewed by CM) @@ -54,7 +54,7 @@ Enhancements ``affine=None`` argument (pr/1253) (Blake Dewey, reviewed by CM) * Warn on invalid MINC2 spacing declarations, treat as missing (pr/1237) (Peter Suter, reviewed by CM) -* Refactor :func:`~nibabel.nicom.utils.find_private_element` for improved +* Refactor :func:`~nibabel.nicom.utils.find_private_section` for improved readability and maintainability (pr/1228) (MB, reviewed by CM) Bug fixes diff --git a/tools/markdown_release_notes.py b/tools/markdown_release_notes.py new file mode 100644 index 000000000..66e787603 --- /dev/null +++ b/tools/markdown_release_notes.py @@ -0,0 +1,94 @@ +#!/usr/bin/env python +import re +import sys +from pathlib import Path + +CHANGELOG = Path(__file__).parent.parent / 'Changelog' + +# Match release lines like "5.2.0 (Monday 11 December 2023)" +RELEASE_REGEX = re.compile(r"""((?:\d+)\.(?:\d+)\.(?:\d+)) \(\w+ \d{1,2} \w+ \d{4}\)$""") + + +def main(): + version = sys.argv[1] + output = sys.argv[2] + if output == '-': + output = sys.stdout + else: + output = open(output, 'w') + + release_notes = [] + in_release_notes = False + + with open(CHANGELOG) as f: + for line in f: + match = RELEASE_REGEX.match(line) + if match: + if in_release_notes: + break + in_release_notes = match.group(1) == version + next(f) # Skip the underline + continue + + if in_release_notes: + release_notes.append(line) + + # Drop empty lines at start and end + while release_notes and not release_notes[0].strip(): + release_notes.pop(0) + while release_notes and not release_notes[-1].strip(): + release_notes.pop() + + # Join lines + release_notes = ''.join(release_notes) + + # Remove line breaks when they are followed by a space + release_notes = re.sub(r'\n +', ' ', release_notes) + + # Replace pr/ with # for GitHub + release_notes = re.sub(r'\(pr/(\d+)\)', r'(#\1)', release_notes) + + # Replace :mod:`package.X` with [package.X](...) + release_notes = re.sub( + r':mod:`nibabel\.(.*)`', + r'[nibabel.\1](https://nipy.org/nibabel/reference/nibabel.\1.html)', + release_notes, + ) + # Replace :class/func/attr:`package.module.X` with [package.module.X](...) + release_notes = re.sub( + r':(?:class|func|attr):`(nibabel\.\w*)(\.[\w.]*)?\.(\w+)`', + r'[\1\2.\3](https://nipy.org/nibabel/reference/\1.html#\1\2.\3)', + release_notes, + ) + release_notes = re.sub( + r':(?:class|func|attr):`~(nibabel\.\w*)(\.[\w.]*)?\.(\w+)`', + r'[\3](https://nipy.org/nibabel/reference/\1.html#\1\2.\3)', + release_notes, + ) + # Replace :meth:`package.module.class.X` with [package.module.class.X](...) + release_notes = re.sub( + r':meth:`(nibabel\.[\w.]*)\.(\w+)\.(\w+)`', + r'[\1.\2.\3](https://nipy.org/nibabel/reference/\1.html#\1.\2.\3)', + release_notes, + ) + release_notes = re.sub( + r':meth:`~(nibabel\.[\w.]*)\.(\w+)\.(\w+)`', + r'[\3](https://nipy.org/nibabel/reference/\1.html#\1.\2.\3)', + release_notes, + ) + + def python_doc(match): + module = match.group(1) + name = match.group(2) + return f'[{name}](https://docs.python.org/3/library/{module.lower()}.html#{module}.{name})' + + release_notes = re.sub(r':meth:`~([\w.]+)\.(\w+)`', python_doc, release_notes) + + output.write('## Release notes\n\n') + output.write(release_notes) + + output.close() + + +if __name__ == '__main__': + main() diff --git a/tox.ini b/tox.ini index d91c136fc..cc2b263cb 100644 --- a/tox.ini +++ b/tox.ini @@ -141,7 +141,8 @@ labels = check deps = flake8 blue - isort[colors] + # Broken extras, remove when fix is released + isort[colors]!=5.13.1 skip_install = true commands = blue --check --diff --color nibabel @@ -153,7 +154,7 @@ description = Auto-apply style guide to the extent possible labels = pre-release deps = blue - isort[colors] + isort skip_install = true commands = blue nibabel