Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package python-docstring-to-markdown for openSUSE:Factory checked in at 2024-04-07 22:11:42 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/python-docstring-to-markdown (Old) and /work/SRC/openSUSE:Factory/.python-docstring-to-markdown.new.1905 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-docstring-to-markdown" Sun Apr 7 22:11:42 2024 rev:6 rq:1165868 version:0.15 Changes: -------- --- /work/SRC/openSUSE:Factory/python-docstring-to-markdown/python-docstring-to-markdown.changes 2023-11-26 19:37:24.542395753 +0100 +++ /work/SRC/openSUSE:Factory/.python-docstring-to-markdown.new.1905/python-docstring-to-markdown.changes 2024-04-07 22:13:58.308107118 +0200 @@ -1,0 +2,8 @@ +Sat Apr 6 19:10:13 UTC 2024 - Dirk Müller <dmuel...@suse.com> + +- update to 0.15: + * Fix multi-line links and incorrect dunder escapes in code +- update to 0.14: + * Add plain text and cPython docstring support + +------------------------------------------------------------------- Old: ---- docstring-to-markdown-0.13-gh.tar.gz New: ---- docstring-to-markdown-0.15-gh.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python-docstring-to-markdown.spec ++++++ --- /var/tmp/diff_new_pack.iuZ50x/_old 2024-04-07 22:13:58.728122522 +0200 +++ /var/tmp/diff_new_pack.iuZ50x/_new 2024-04-07 22:13:58.728122522 +0200 @@ -1,7 +1,7 @@ # # spec file for package python-docstring-to-markdown # -# Copyright (c) 2023 SUSE LLC +# Copyright (c) 2024 SUSE LLC # # All modifications and additions to the file contributed by third parties # remain the property of their copyright owners, unless otherwise agreed @@ -19,7 +19,7 @@ %{?sle15_python_module_pythons} Name: python-docstring-to-markdown -Version: 0.13 +Version: 0.15 Release: 0 Summary: On the fly conversion of Python docstrings to markdown License: LGPL-2.1-only ++++++ docstring-to-markdown-0.13-gh.tar.gz -> docstring-to-markdown-0.15-gh.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/docstring-to-markdown-0.13/.github/workflows/tests.yml new/docstring-to-markdown-0.15/.github/workflows/tests.yml --- old/docstring-to-markdown-0.13/.github/workflows/tests.yml 2023-10-11 21:43:03.000000000 +0200 +++ new/docstring-to-markdown-0.15/.github/workflows/tests.yml 2024-02-21 14:50:11.000000000 +0100 @@ -12,9 +12,6 @@ matrix: os: [ubuntu-latest] python-version: [3.7, 3.8, 3.9, '3.10', '3.11'] - include: - - os: ubuntu-20.04 - python-version: 3.6 runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@v2 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/docstring-to-markdown-0.13/README.md new/docstring-to-markdown-0.15/README.md --- old/docstring-to-markdown-0.13/README.md 2023-10-11 21:43:03.000000000 +0200 +++ new/docstring-to-markdown-0.15/README.md 2024-02-21 14:50:11.000000000 +0100 @@ -6,7 +6,7 @@ On the fly conversion of Python docstrings to markdown -- Python 3.6+ +- Python 3.6+ (tested on 3.7 up to 3.11) - can recognise reStructuredText and convert multiple of its features to Markdown - since v0.13 includes initial support for Google-formatted docstrings diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/docstring-to-markdown-0.13/docstring_to_markdown/__init__.py new/docstring-to-markdown-0.15/docstring_to_markdown/__init__.py --- old/docstring-to-markdown-0.13/docstring_to_markdown/__init__.py 2023-10-11 21:43:03.000000000 +0200 +++ new/docstring-to-markdown-0.15/docstring_to_markdown/__init__.py 2024-02-21 14:50:11.000000000 +0100 @@ -1,7 +1,9 @@ +from .cpython import cpython_to_markdown from .google import google_to_markdown, looks_like_google +from .plain import looks_like_plain_text, plain_text_to_markdown from .rst import looks_like_rst, rst_to_markdown -__version__ = "0.13" +__version__ = "0.15" class UnknownFormatError(Exception): @@ -15,4 +17,11 @@ if looks_like_google(docstring): return google_to_markdown(docstring) + if looks_like_plain_text(docstring): + return plain_text_to_markdown(docstring) + + cpython = cpython_to_markdown(docstring) + if cpython: + return cpython + raise UnknownFormatError() diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/docstring-to-markdown-0.13/docstring_to_markdown/_utils.py new/docstring-to-markdown-0.15/docstring_to_markdown/_utils.py --- old/docstring-to-markdown-0.13/docstring_to_markdown/_utils.py 1970-01-01 01:00:00.000000000 +0100 +++ new/docstring-to-markdown-0.15/docstring_to_markdown/_utils.py 2024-02-21 14:50:11.000000000 +0100 @@ -0,0 +1,5 @@ +from re import sub + + +def escape_markdown(text: str) -> str: + return sub(r'([\\#*_[\]])', r'\\\1', text) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/docstring-to-markdown-0.13/docstring_to_markdown/cpython.py new/docstring-to-markdown-0.15/docstring_to_markdown/cpython.py --- old/docstring-to-markdown-0.13/docstring_to_markdown/cpython.py 1970-01-01 01:00:00.000000000 +0100 +++ new/docstring-to-markdown-0.15/docstring_to_markdown/cpython.py 2024-02-21 14:50:11.000000000 +0100 @@ -0,0 +1,37 @@ +from typing import Union, List +from re import fullmatch + +from ._utils import escape_markdown + +def _is_cpython_signature_line(line: str) -> bool: + """CPython uses signature lines in the following format: + + str(bytes_or_buffer[, encoding[, errors]]) -> str + """ + return fullmatch(r'\w+\(\S*(, \S+)*(\[, \S+\])*\)\s--?>\s.+', line) is not None + + +def cpython_to_markdown(text: str) -> Union[str, None]: + signature_lines: List[str] = [] + other_lines: List[str] = [] + for line in text.splitlines(): + if not other_lines and _is_cpython_signature_line(line): + signature_lines.append(line) + elif not signature_lines: + return None + elif line.startswith(' '): + signature_lines.append(line) + else: + other_lines.append(line) + return '\n'.join([ + '```', + '\n'.join(signature_lines), + '```', + escape_markdown('\n'.join(other_lines)) + ]) + +def looks_like_cpython(text: str) -> bool: + return cpython_to_markdown(text) is not None + + +__all__ = ['looks_like_cpython', 'cpython_to_markdown'] diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/docstring-to-markdown-0.13/docstring_to_markdown/plain.py new/docstring-to-markdown-0.15/docstring_to_markdown/plain.py --- old/docstring-to-markdown-0.13/docstring_to_markdown/plain.py 1970-01-01 01:00:00.000000000 +0100 +++ new/docstring-to-markdown-0.15/docstring_to_markdown/plain.py 2024-02-21 14:50:11.000000000 +0100 @@ -0,0 +1,27 @@ +from re import fullmatch +from ._utils import escape_markdown + + +def looks_like_plain_text(value: str) -> bool: + """Check if given string has plain text following English syntax without need for escaping. + + Accepts: + - words without numbers + - full stop, bangs and question marks at the end of a word if followed by a space or end of string + - commas, colons and semicolons if after a word and followed by a space + - dashes between words (like in `e-mail`) + - double and single quotes if proceeded with a space and followed by a word, or if proceeded by a word and followed by a space (or end of string); single quotes are also allowed in between two words + - parentheses if opening preceded by space and closing followed by space or end + + Does not accept: + - square brackets (used in markdown a lot) + """ + if '_' in value: + return False + return fullmatch(r"((\w[\.!\?\)'\"](\s|$))|(\w[,:;]\s)|(\w[-']\w)|(\w\s['\"\(])|\w|\s)+", value) is not None + + +def plain_text_to_markdown(text: str) -> str: + return escape_markdown(text) + +__all__ = ['looks_like_plain_text', 'plain_text_to_markdown'] diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/docstring-to-markdown-0.13/docstring_to_markdown/rst.py new/docstring-to-markdown-0.15/docstring_to_markdown/rst.py --- old/docstring-to-markdown-0.13/docstring_to_markdown/rst.py 2023-10-11 21:43:03.000000000 +0200 +++ new/docstring-to-markdown-0.15/docstring_to_markdown/rst.py 2024-02-21 14:50:11.000000000 +0100 @@ -1,13 +1,13 @@ from abc import ABC, abstractmethod from enum import IntEnum, auto from types import SimpleNamespace -from typing import Union, List, Dict +from typing import Callable, Match, Union, List, Dict import re class Directive: def __init__( - self, pattern: str, replacement: str, + self, pattern: str, replacement: Union[str, Callable[[Match], str]], name: Union[str, None] = None, flags: int = 0 ): @@ -249,7 +249,7 @@ ), Directive( pattern=r'`(?P<label>[^<`]+?)(\n?)<(?P<url>[^>`]+)>`_+', - replacement=r'[\g<label>](\g<url>)' + replacement=lambda m: '[' + m.group('label') + '](' + re.sub(r"\s+", "", m.group('url')) + ')' ), Directive( pattern=r':mod:`(?P<label>[^`]+)`', @@ -316,7 +316,7 @@ ESCAPING_RULES: List[Directive] = [ Directive( - pattern=r'__(?P<text>\S+)__', + pattern=r'(?<!`)__(?P<text>\S+)__(?!`)', replacement=r'\_\_\g<text>\_\_' ) ] diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/docstring-to-markdown-0.13/setup.cfg new/docstring-to-markdown-0.15/setup.cfg --- old/docstring-to-markdown-0.13/setup.cfg 2023-10-11 21:43:03.000000000 +0200 +++ new/docstring-to-markdown-0.15/setup.cfg 2024-02-21 14:50:11.000000000 +0100 @@ -37,7 +37,7 @@ addopts = --pyargs tests --cov docstring_to_markdown - --cov-fail-under=98 + --cov-fail-under=99 --cov-report term-missing:skip-covered -p no:warnings --flake8 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/docstring-to-markdown-0.13/tests/test_convert.py new/docstring-to-markdown-0.15/tests/test_convert.py --- old/docstring-to-markdown-0.13/tests/test_convert.py 1970-01-01 01:00:00.000000000 +0100 +++ new/docstring-to-markdown-0.15/tests/test_convert.py 2024-02-21 14:50:11.000000000 +0100 @@ -0,0 +1,57 @@ +from docstring_to_markdown import convert, UnknownFormatError +import pytest + +CPYTHON = """\ +bool(x) -> bool + +Returns True when the argument x is true, False otherwise.\ +""" + + +CPYTHON_MD = """\ +``` +bool(x) -> bool +``` + +Returns True when the argument x is true, False otherwise.\ +""" + +GOOGLE = """Do **something**. + +Args: + a: some arg + b: some arg +""" + +GOOGLE_MD = """Do **something**. + +#### Args + +- `a`: some arg +- `b`: some arg +""" + + +RST = "Please see `this link<https://example.com>`__." +RST_MD = "Please see [this link](https://example.com)." + + +def test_convert_cpython(): + assert convert(CPYTHON) == CPYTHON_MD + + +def test_convert_plain_text(): + assert convert('This is a sentence.') == 'This is a sentence.' + + +def test_convert_google(): + assert convert(GOOGLE) == GOOGLE_MD + + +def test_convert_rst(): + assert convert(RST) == RST_MD + + +def test_unknown_format(): + with pytest.raises(UnknownFormatError): + convert('ARGS [arg1, arg2] RETURNS: str OR None') diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/docstring-to-markdown-0.13/tests/test_cpython.py new/docstring-to-markdown-0.15/tests/test_cpython.py --- old/docstring-to-markdown-0.13/tests/test_cpython.py 1970-01-01 01:00:00.000000000 +0100 +++ new/docstring-to-markdown-0.15/tests/test_cpython.py 2024-02-21 14:50:11.000000000 +0100 @@ -0,0 +1,103 @@ +import pytest +from docstring_to_markdown.cpython import looks_like_cpython, cpython_to_markdown + +BOOL = """\ +bool(x) -> bool + +Returns True when the argument x is true, False otherwise.\ +""" + +BOOL_MD = """\ +``` +bool(x) -> bool +``` + +Returns True when the argument x is true, False otherwise.\ +""" + +BYTES = """\ +bytes(iterable_of_ints) -> bytes +bytes(string, encoding[, errors]) -> bytes +bytes(bytes_or_buffer) -> immutable copy of bytes_or_buffer +bytes(int) -> bytes object of size given by the parameter initialized with null bytes +bytes() -> empty bytes object + +Construct an immutable array of bytes from: + - an iterable yielding integers in range(256) + - a text string encoded using the specified encoding + - any object implementing the buffer API. + - an integer\ +""" + +COLLECTIONS_DEQUEUE = """\ +deque([iterable[, maxlen]]) --> deque object + +A list-like sequence optimized for data accesses near its endpoints.\ +""" + +DICT = """\ +dict() -> new empty dictionary +dict(mapping) -> new dictionary initialized from a mapping object's + (key, value) pairs +dict(iterable) -> new dictionary initialized as if via: + d = {} + for k, v in iterable: + d[k] = v +dict(**kwargs) -> new dictionary initialized with the name=value pairs + in the keyword argument list. For example: dict(one=1, two=2)\ +""" + +STR = """\ +str(object='') -> str +str(bytes_or_buffer[, encoding[, errors]]) -> str + +Create a new string object from the given object. If encoding or +errors is specified, then the object must expose a data buffer +that will be decoded using the given encoding and error handler. +Otherwise, returns the result of object.__str__() (if defined) +or repr(object).\ +""" + +STR_MD = """\ +``` +str(object='') -> str +str(bytes_or_buffer[, encoding[, errors]]) -> str +``` + +Create a new string object from the given object. If encoding or +errors is specified, then the object must expose a data buffer +that will be decoded using the given encoding and error handler. +Otherwise, returns the result of object.\\_\\_str\\_\\_() (if defined) +or repr(object).\ +""" + + +@pytest.mark.parametrize("text", [BYTES, STR, DICT, BOOL, COLLECTIONS_DEQUEUE]) +def test_accepts_cpython_docstrings(text): + assert looks_like_cpython(text) is True + + +@pytest.mark.parametrize("text", [ + "[link label](https://link)", + "![image label](https://source)", + "Some **bold** text", + "More __bold__ text", + "Some *italic* text", + "More _italic_ text", + "This is a sentence.", + "Exclamation!", + "Can I ask a question?", + "Let's send an e-mail", + "Parentheses (are) fine (really)", + "Double \"quotes\" and single 'quotes'" +]) +def test_rejects_markdown_and_plain_text(text): + assert looks_like_cpython(text) is False + + +def test_conversion_bool(): + assert cpython_to_markdown(BOOL) == BOOL_MD + + +def test_conversion_str(): + assert cpython_to_markdown(STR) == STR_MD diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/docstring-to-markdown-0.13/tests/test_plain.py new/docstring-to-markdown-0.15/tests/test_plain.py --- old/docstring-to-markdown-0.13/tests/test_plain.py 1970-01-01 01:00:00.000000000 +0100 +++ new/docstring-to-markdown-0.15/tests/test_plain.py 2024-02-21 14:50:11.000000000 +0100 @@ -0,0 +1,42 @@ +import pytest +from docstring_to_markdown.plain import looks_like_plain_text, plain_text_to_markdown + + +@pytest.mark.parametrize("text", [ + "This is a sentence.", + "Exclamation!", + "Can I ask a question?", + "Let's send an e-mail", + "Parentheses (are) fine (really)", + "Double \"quotes\" and single 'quotes'" +]) +def test_accepts_english(text): + assert looks_like_plain_text(text) is True + + +@pytest.mark.parametrize("text", [ + "[link label](https://link)", + "![image label](https://source)", + "Some **bold** text", + "More __bold__ text", + "Some *italic* text", + "More _italic_ text" +]) +def test_rejects_markdown(text): + assert looks_like_plain_text(text) is False + + +@pytest.mark.parametrize("text", [ + "def test():", + "print(123)", + "func(arg)", + "2 + 2", + "var['test']", + "x = 'test'" +]) +def test_rejects_code(text): + assert looks_like_plain_text(text) is False + + +def test_conversion(): + assert plain_text_to_markdown("test") == "test" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/docstring-to-markdown-0.13/tests/test_rst.py new/docstring-to-markdown-0.15/tests/test_rst.py --- old/docstring-to-markdown-0.13/tests/test_rst.py 2023-10-11 21:43:03.000000000 +0200 +++ new/docstring-to-markdown-0.15/tests/test_rst.py 2024-02-21 14:50:11.000000000 +0100 @@ -78,6 +78,17 @@ "[this link](https://pandas.pydata.org/pandas-docs/stable/user_guide/timeseries.html#offset-aliases)." ) +RST_LINK_MULTILINE_EXAMPLE = """ +See +`strftime documentation +<https://docs.python.org/3/library/datetime.html +#strftime-and-strptime-behavior>`_ for more. +""" +RST_LINK_MULTILINE_MARKDOWN = """ +See +[strftime documentation](https://docs.python.org/3/library/datetime.html#strftime-and-strptime-behavior) for more. +""" + RST_REF_EXAMPLE = """See :ref:`here <timeseries.offset_aliases>` for a list of frequency aliases.""" RST_REF_MARKDOWN = """See here: `timeseries.offset_aliases` for a list of frequency aliases.""" @@ -686,6 +697,10 @@ 'rst': RST_LINK_EXAMPLE, 'md': RST_LINK_EXAMPLE_MARKDOWN }, + 'converts multi-line links': { + 'rst': RST_LINK_MULTILINE_EXAMPLE, + 'md': RST_LINK_MULTILINE_MARKDOWN + }, 'changes highlight': { 'rst': RST_HIGHLIGHTED_BLOCK, 'md': RST_HIGHLIGHTED_BLOCK_MARKDOWN @@ -764,6 +779,10 @@ 'rst': '__init__', 'md': r'\_\_init\_\_' }, + 'does not escape dunders in code': { + 'rst': '`__init__`', + 'md': '`__init__`' + }, 'converts bibliographic references': { 'rst': REFERENCES, 'md': REFERENCES_MARKDOWN