format-docstring 0.1.6__tar.gz → 0.1.7__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (97) hide show
  1. {format_docstring-0.1.6 → format_docstring-0.1.7}/CHANGELOG.md +8 -0
  2. {format_docstring-0.1.6 → format_docstring-0.1.7}/PKG-INFO +1 -1
  3. {format_docstring-0.1.6 → format_docstring-0.1.7}/format_docstring/line_wrap_numpy.py +83 -19
  4. {format_docstring-0.1.6 → format_docstring-0.1.7}/format_docstring.egg-info/PKG-INFO +1 -1
  5. {format_docstring-0.1.6 → format_docstring-0.1.7}/pyproject.toml +1 -1
  6. {format_docstring-0.1.6 → format_docstring-0.1.7}/tests/test_data/end_to_end/numpy/fix_rst_backticks.txt +10 -0
  7. {format_docstring-0.1.6 → format_docstring-0.1.7}/tests/test_data/line_wrap/numpy/fix_rst_backticks.txt +16 -0
  8. {format_docstring-0.1.6 → format_docstring-0.1.7}/tests/test_line_wrap_numpy.py +58 -2
  9. {format_docstring-0.1.6 → format_docstring-0.1.7}/.github/workflows/python-package.yml +0 -0
  10. {format_docstring-0.1.6 → format_docstring-0.1.7}/.github/workflows/python-publish.yml +0 -0
  11. {format_docstring-0.1.6 → format_docstring-0.1.7}/.gitignore +0 -0
  12. {format_docstring-0.1.6 → format_docstring-0.1.7}/.pre-commit-config.yaml +0 -0
  13. {format_docstring-0.1.6 → format_docstring-0.1.7}/.pre-commit-hooks.yaml +0 -0
  14. {format_docstring-0.1.6 → format_docstring-0.1.7}/CLAUDE.md +0 -0
  15. {format_docstring-0.1.6 → format_docstring-0.1.7}/LICENSE +0 -0
  16. {format_docstring-0.1.6 → format_docstring-0.1.7}/README.md +0 -0
  17. {format_docstring-0.1.6 → format_docstring-0.1.7}/format_docstring/__init__.py +0 -0
  18. {format_docstring-0.1.6 → format_docstring-0.1.7}/format_docstring/base_fixer.py +0 -0
  19. {format_docstring-0.1.6 → format_docstring-0.1.7}/format_docstring/config.py +0 -0
  20. {format_docstring-0.1.6 → format_docstring-0.1.7}/format_docstring/docstring_rewriter.py +0 -0
  21. {format_docstring-0.1.6 → format_docstring-0.1.7}/format_docstring/line_wrap_google.py +0 -0
  22. {format_docstring-0.1.6 → format_docstring-0.1.7}/format_docstring/line_wrap_utils.py +0 -0
  23. {format_docstring-0.1.6 → format_docstring-0.1.7}/format_docstring/main_jupyter.py +0 -0
  24. {format_docstring-0.1.6 → format_docstring-0.1.7}/format_docstring/main_py.py +0 -0
  25. {format_docstring-0.1.6 → format_docstring-0.1.7}/format_docstring.egg-info/SOURCES.txt +0 -0
  26. {format_docstring-0.1.6 → format_docstring-0.1.7}/format_docstring.egg-info/dependency_links.txt +0 -0
  27. {format_docstring-0.1.6 → format_docstring-0.1.7}/format_docstring.egg-info/entry_points.txt +0 -0
  28. {format_docstring-0.1.6 → format_docstring-0.1.7}/format_docstring.egg-info/requires.txt +0 -0
  29. {format_docstring-0.1.6 → format_docstring-0.1.7}/format_docstring.egg-info/top_level.txt +0 -0
  30. {format_docstring-0.1.6 → format_docstring-0.1.7}/muff.toml +0 -0
  31. {format_docstring-0.1.6 → format_docstring-0.1.7}/requirements.dev +0 -0
  32. {format_docstring-0.1.6 → format_docstring-0.1.7}/setup.cfg +0 -0
  33. {format_docstring-0.1.6 → format_docstring-0.1.7}/tests/__init__.py +0 -0
  34. {format_docstring-0.1.6 → format_docstring-0.1.7}/tests/helpers.py +0 -0
  35. {format_docstring-0.1.6 → format_docstring-0.1.7}/tests/test_config.py +0 -0
  36. {format_docstring-0.1.6 → format_docstring-0.1.7}/tests/test_data/end_to_end/numpy/README.md +0 -0
  37. {format_docstring-0.1.6 → format_docstring-0.1.7}/tests/test_data/end_to_end/numpy/colon_spacing_fix.txt +0 -0
  38. {format_docstring-0.1.6 → format_docstring-0.1.7}/tests/test_data/end_to_end/numpy/contents_that_are_not_wrapped.txt +0 -0
  39. {format_docstring-0.1.6 → format_docstring-0.1.7}/tests/test_data/end_to_end/numpy/default_value_standardization.txt +0 -0
  40. {format_docstring-0.1.6 → format_docstring-0.1.7}/tests/test_data/end_to_end/numpy/empty_lines_are_respected.txt +0 -0
  41. {format_docstring-0.1.6 → format_docstring-0.1.7}/tests/test_data/end_to_end/numpy/examples_section.txt +0 -0
  42. {format_docstring-0.1.6 → format_docstring-0.1.7}/tests/test_data/end_to_end/numpy/existing_linebreaks_should_not_be_respected.txt +0 -0
  43. {format_docstring-0.1.6 → format_docstring-0.1.7}/tests/test_data/end_to_end/numpy/four_level_nested_classes.txt +0 -0
  44. {format_docstring-0.1.6 → format_docstring-0.1.7}/tests/test_data/end_to_end/numpy/indent_four_levels_16_spaces_width_10.txt +0 -0
  45. {format_docstring-0.1.6 → format_docstring-0.1.7}/tests/test_data/end_to_end/numpy/indent_misaligned_all.txt +0 -0
  46. {format_docstring-0.1.6 → format_docstring-0.1.7}/tests/test_data/end_to_end/numpy/indent_two_levels_8_spaces.txt +0 -0
  47. {format_docstring-0.1.6 → format_docstring-0.1.7}/tests/test_data/end_to_end/numpy/line_length_2.txt +0 -0
  48. {format_docstring-0.1.6 → format_docstring-0.1.7}/tests/test_data/end_to_end/numpy/mismatched_underlines.txt +0 -0
  49. {format_docstring-0.1.6 → format_docstring-0.1.7}/tests/test_data/end_to_end/numpy/mismatched_underlines_one_dash.txt +0 -0
  50. {format_docstring-0.1.6 → format_docstring-0.1.7}/tests/test_data/end_to_end/numpy/mismatched_underlines_two_dashes.txt +0 -0
  51. {format_docstring-0.1.6 → format_docstring-0.1.7}/tests/test_data/end_to_end/numpy/module_level_docstring.txt +0 -0
  52. {format_docstring-0.1.6 → format_docstring-0.1.7}/tests/test_data/end_to_end/numpy/new_lines_before_and_after.txt +0 -0
  53. {format_docstring-0.1.6 → format_docstring-0.1.7}/tests/test_data/end_to_end/numpy/param_signature_without_type.txt +0 -0
  54. {format_docstring-0.1.6 → format_docstring-0.1.7}/tests/test_data/end_to_end/numpy/parameters_returns_raises_wrapping.txt +0 -0
  55. {format_docstring-0.1.6 → format_docstring-0.1.7}/tests/test_data/end_to_end/numpy/returns_signature_and_description.txt +0 -0
  56. {format_docstring-0.1.6 → format_docstring-0.1.7}/tests/test_data/end_to_end/numpy/section_title_fixed.txt +0 -0
  57. {format_docstring-0.1.6 → format_docstring-0.1.7}/tests/test_data/end_to_end/numpy/sections_notes_examples.txt +0 -0
  58. {format_docstring-0.1.6 → format_docstring-0.1.7}/tests/test_data/end_to_end/numpy/signature_line_is_not_wrapped.txt +0 -0
  59. {format_docstring-0.1.6 → format_docstring-0.1.7}/tests/test_data/end_to_end/numpy/single_line_docstring.txt +0 -0
  60. {format_docstring-0.1.6 → format_docstring-0.1.7}/tests/test_data/end_to_end/numpy/texts_are_rewrapped.txt +0 -0
  61. {format_docstring-0.1.6 → format_docstring-0.1.7}/tests/test_data/end_to_end/numpy/very_long_unbreakable_word.txt +0 -0
  62. {format_docstring-0.1.6 → format_docstring-0.1.7}/tests/test_data/integration_test/numpy/after.ipynb +0 -0
  63. {format_docstring-0.1.6 → format_docstring-0.1.7}/tests/test_data/integration_test/numpy/after.py +0 -0
  64. {format_docstring-0.1.6 → format_docstring-0.1.7}/tests/test_data/integration_test/numpy/after_50.ipynb +0 -0
  65. {format_docstring-0.1.6 → format_docstring-0.1.7}/tests/test_data/integration_test/numpy/after_50.py +0 -0
  66. {format_docstring-0.1.6 → format_docstring-0.1.7}/tests/test_data/integration_test/numpy/before.ipynb +0 -0
  67. {format_docstring-0.1.6 → format_docstring-0.1.7}/tests/test_data/integration_test/numpy/before.py +0 -0
  68. {format_docstring-0.1.6 → format_docstring-0.1.7}/tests/test_data/line_wrap/numpy/README.md +0 -0
  69. {format_docstring-0.1.6 → format_docstring-0.1.7}/tests/test_data/line_wrap/numpy/colon_spacing_fix.txt +0 -0
  70. {format_docstring-0.1.6 → format_docstring-0.1.7}/tests/test_data/line_wrap/numpy/contents_that_are_not_wrapped.txt +0 -0
  71. {format_docstring-0.1.6 → format_docstring-0.1.7}/tests/test_data/line_wrap/numpy/default_value_standardization.txt +0 -0
  72. {format_docstring-0.1.6 → format_docstring-0.1.7}/tests/test_data/line_wrap/numpy/empty_lines_are_respected.txt +0 -0
  73. {format_docstring-0.1.6 → format_docstring-0.1.7}/tests/test_data/line_wrap/numpy/examples_section.txt +0 -0
  74. {format_docstring-0.1.6 → format_docstring-0.1.7}/tests/test_data/line_wrap/numpy/existing_linebreaks_should_not_be_respected.txt +0 -0
  75. {format_docstring-0.1.6 → format_docstring-0.1.7}/tests/test_data/line_wrap/numpy/indent_four_levels_16_spaces_width_10.txt +0 -0
  76. {format_docstring-0.1.6 → format_docstring-0.1.7}/tests/test_data/line_wrap/numpy/indent_two_levels_8_spaces.txt +0 -0
  77. {format_docstring-0.1.6 → format_docstring-0.1.7}/tests/test_data/line_wrap/numpy/line_length_2.txt +0 -0
  78. {format_docstring-0.1.6 → format_docstring-0.1.7}/tests/test_data/line_wrap/numpy/mismatched_underlines.txt +0 -0
  79. {format_docstring-0.1.6 → format_docstring-0.1.7}/tests/test_data/line_wrap/numpy/mismatched_underlines_one_dash.txt +0 -0
  80. {format_docstring-0.1.6 → format_docstring-0.1.7}/tests/test_data/line_wrap/numpy/mismatched_underlines_two_dashes.txt +0 -0
  81. {format_docstring-0.1.6 → format_docstring-0.1.7}/tests/test_data/line_wrap/numpy/module_level_docstring.txt +0 -0
  82. {format_docstring-0.1.6 → format_docstring-0.1.7}/tests/test_data/line_wrap/numpy/param_signature_without_type.txt +0 -0
  83. {format_docstring-0.1.6 → format_docstring-0.1.7}/tests/test_data/line_wrap/numpy/parameters_returns_raises_wrapping.txt +0 -0
  84. {format_docstring-0.1.6 → format_docstring-0.1.7}/tests/test_data/line_wrap/numpy/returns_signature_and_description.txt +0 -0
  85. {format_docstring-0.1.6 → format_docstring-0.1.7}/tests/test_data/line_wrap/numpy/section_title_fixed.txt +0 -0
  86. {format_docstring-0.1.6 → format_docstring-0.1.7}/tests/test_data/line_wrap/numpy/sections_notes_examples.txt +0 -0
  87. {format_docstring-0.1.6 → format_docstring-0.1.7}/tests/test_data/line_wrap/numpy/signature_line_is_not_wrapped.txt +0 -0
  88. {format_docstring-0.1.6 → format_docstring-0.1.7}/tests/test_data/line_wrap/numpy/texts_are_rewrapped.txt +0 -0
  89. {format_docstring-0.1.6 → format_docstring-0.1.7}/tests/test_data/line_wrap/numpy/very_long_unbreakable_word.txt +0 -0
  90. {format_docstring-0.1.6 → format_docstring-0.1.7}/tests/test_data/playground.py +0 -0
  91. {format_docstring-0.1.6 → format_docstring-0.1.7}/tests/test_docstring_rewriter.py +0 -0
  92. {format_docstring-0.1.6 → format_docstring-0.1.7}/tests/test_line_wrap_google.py +0 -0
  93. {format_docstring-0.1.6 → format_docstring-0.1.7}/tests/test_line_wrap_utils.py +0 -0
  94. {format_docstring-0.1.6 → format_docstring-0.1.7}/tests/test_main_jupyter.py +0 -0
  95. {format_docstring-0.1.6 → format_docstring-0.1.7}/tests/test_main_py.py +0 -0
  96. {format_docstring-0.1.6 → format_docstring-0.1.7}/tests/test_playground.py +0 -0
  97. {format_docstring-0.1.6 → format_docstring-0.1.7}/tox.ini +0 -0
@@ -6,6 +6,14 @@ The format is based on
6
6
  [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project
7
7
  adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
8
8
 
9
+ ## [0.1.7] - 2025-10-14
10
+
11
+ - Fixed
12
+ - Backtick fixing logic to properly distinguish between inline literals and
13
+ external links (e.g., `` `Python <https://example.org>`_ ``)
14
+ - Refactored `_fix_rst_backticks()` to use pre-compiled regex pattern for
15
+ better performance
16
+
9
17
  ## [0.1.6] - 2025-10-13
10
18
 
11
19
  - Added
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: format-docstring
3
- Version: 0.1.6
3
+ Version: 0.1.7
4
4
  Summary: A Python formatter to wrap/adjust docstring lines
5
5
  Author-email: jsh9 <25124332+jsh9@users.noreply.github.com>
6
6
  Maintainer-email: jsh9 <25124332+jsh9@users.noreply.github.com>
@@ -415,15 +415,47 @@ def handle_single_line_docstring(
415
415
  return whole_docstring_literal
416
416
 
417
417
 
418
+ # Precompiled regex for fixing RST backticks.
419
+ # Pattern matches inline literals while avoiding roles, cross-references, and
420
+ # links. See the documentation of _fix_rst_backticks() for more details.
421
+ # The pattern allows backticks after: start of line, whitespace, parentheses,
422
+ # or certain punctuation (like > and . for `>>> ` and `... ` literals)
423
+ # Note: We match [^`]+ (anything except backticks) and then check in the
424
+ # replacement function whether it's an external link (contains < followed by >)
425
+ _RST_BACKTICK_PATTERN = re.compile(
426
+ r'(?:^|(?<=\s)|(?<=\()|(?<=[>.]))(?::[\w-]+:)?`([^`]+)`(?!`)(?!__)(?!_)'
427
+ )
428
+
429
+
418
430
  def _fix_rst_backticks(docstring: str) -> str:
419
431
  """
420
- Fix single backticks to double backticks per rST syntax.
421
-
422
- This function converts pairs of single backticks (`) to pairs of double
423
- backticks (``). It handles various edge cases:
424
- - Preserves existing double backticks
425
- - Handles nested backticks
426
- - Preserves code blocks and literal blocks
432
+ Fix inline-literal single backticks to double backticks per rST syntax.
433
+
434
+ This function converts pairs of single backticks (`` `...` ``) that
435
+ represent inline *literals* into pairs of double backticks (`` ``...`` ``).
436
+ It deliberately **does not** modify other rST constructs that require
437
+ single backticks.
438
+
439
+ What stays untouched
440
+ --------------------
441
+ - Existing double-backtick literals: ````code````.
442
+ - Roles: ``:role:`text``` (e.g., ``:emphasis:`word```).
443
+ - Cross-references: `` `text`_ `` and anonymous refs `` `text`__ ``.
444
+ - Inline external links: `` `text <https://example.com>`_ ``.
445
+ - Explicit hyperlink targets: ``.. _`Label`: https://example.com``.
446
+
447
+ How it works (regex guards)
448
+ ---------------------------
449
+ The pattern only upgrades a match when **all** these are true:
450
+ - Opening backtick is not part of an existing ````...```` (``(?<!`)``).
451
+ - Opening backtick is not immediately preceded by ``:`` (to avoid roles).
452
+ - Opening backtick is not immediately preceded by ``_`` (to avoid
453
+ explicit targets like ``.. _`Label`: …``).
454
+ - The enclosed text contains **no** backticks and **no** ``<`` (to avoid
455
+ inline-link forms like `` `text <url>`_ ``).
456
+ - Closing backtick is not part of ````...```` (``(?!`)``).
457
+ - Closing backtick is not followed by ``__`` or ``_`` (to avoid
458
+ anonymous/named references).
427
459
 
428
460
  Parameters
429
461
  ----------
@@ -433,23 +465,55 @@ def _fix_rst_backticks(docstring: str) -> str:
433
465
  Returns
434
466
  -------
435
467
  str
436
- The docstring with single backticks converted to double backticks.
468
+ The docstring with only inline-literal backticks fixed.
437
469
 
438
470
  Examples
439
471
  --------
440
472
  >>> _fix_rst_backticks('Use `foo` to do something')
441
473
  'Use ``foo`` to do something'
474
+
475
+ >>> _fix_rst_backticks('Edge punctuation: `x`.')
476
+ 'Edge punctuation: ``x``.'
477
+
478
+ >>> _fix_rst_backticks(':emphasis:`word`')
479
+ ':emphasis:`word`'
480
+
481
+ >>> _fix_rst_backticks('See `Link`_ for details')
482
+ 'See `Link`_ for details'
483
+
484
+ >>> _fix_rst_backticks('`Python <https://www.python.org>`_')
485
+ '`Python <https://www.python.org>`_'
486
+
487
+ >>> _fix_rst_backticks('.. _`Special Target`: https://example.com/special')
488
+ '.. _`Special Target`: https://example.com/special'
489
+
442
490
  >>> _fix_rst_backticks('Already has ``foo`` double backticks')
443
491
  'Already has ``foo`` double backticks'
444
492
  """
445
- # Pattern to match single backticks that are not already part of double
446
- # backticks. We look for:
447
- # - A backtick not preceded by a backtick: (?<!`)
448
- # - Followed by one or more non-backtick characters: ([^`]+)
449
- # - Followed by a backtick not followed by another backtick: `(?!`)
450
- #
451
- # This pattern avoids matching backticks that are already part of ``...``
452
- pattern = r'(?<!`)`([^`]+)`(?!`)'
453
-
454
- # Replace single backtick pairs with double backtick pairs
455
- return re.sub(pattern, r'``\1``', docstring)
493
+
494
+ def replace_func(match: re.Match[str]) -> str:
495
+ # match.group(0) is the full match
496
+ # match.group(1) is the content between backticks
497
+ full_match: str = match.group(0)
498
+ content: str = match.group(1)
499
+
500
+ # If the match includes a role prefix (like :emphasis:), don't replace
501
+ if ':' in full_match and full_match.index('`') > 0:
502
+ # Check if there's a role prefix before the backtick
503
+ before_backtick = full_match[: full_match.index('`')]
504
+ if ':' in before_backtick:
505
+ return full_match # Keep original (it's a role)
506
+
507
+ # Check if this is an external link (contains <...> pattern)
508
+ # External links look like: `text <url>`_
509
+ if '<' in content and '>' in content:
510
+ # Check if < comes before > (basic validation)
511
+ if content.index('<') < content.rindex('>'):
512
+ return full_match # Keep original (it's an external link)
513
+
514
+ # Otherwise, replace single backticks with double
515
+ # Keep any leading whitespace/parenthesis/punctuation
516
+ prefix = match.group(0)[: match.group(0).index('`')]
517
+ return f'{prefix}``{content}``'
518
+
519
+ return _RST_BACKTICK_PATTERN.sub(replace_func, docstring)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: format-docstring
3
- Version: 0.1.6
3
+ Version: 0.1.7
4
4
  Summary: A Python formatter to wrap/adjust docstring lines
5
5
  Author-email: jsh9 <25124332+jsh9@users.noreply.github.com>
6
6
  Maintainer-email: jsh9 <25124332+jsh9@users.noreply.github.com>
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "format-docstring"
7
- version = "0.1.6"
7
+ version = "0.1.7"
8
8
  description = "A Python formatter to wrap/adjust docstring lines"
9
9
  readme = "README.md"
10
10
  license = {text = "MIT"}
@@ -41,6 +41,11 @@ def process_data(data, config=None):
41
41
  When `mode` is set to `'advanced'`, additional processing steps are
42
42
  applied. The `threshold` parameter controls filtering behavior.
43
43
 
44
+ For rST roles like :emphasis:`important` and :sup:`2`, the single backticks
45
+ should remain. Cross-references like `Section`_ and anonymous refs like
46
+ `Link`__ should not be modified. External links such as `Python
47
+ <https://www.python.org>`_ must stay as-is.
48
+
44
49
  Examples
45
50
  --------
46
51
  >>> data = [{'id': 1, 'value': 10}]
@@ -123,6 +128,11 @@ def process_data(data, config=None):
123
128
  When ``mode`` is set to ``'advanced'``, additional processing steps are
124
129
  applied. The ``threshold`` parameter controls filtering behavior.
125
130
 
131
+ For rST roles like :emphasis:`important` and :sup:`2`, the single backticks
132
+ should remain. Cross-references like `Section`_ and anonymous refs like
133
+ `Link`__ should not be modified. External links such as `Python
134
+ <https://www.python.org>`_ must stay as-is.
135
+
126
136
  Examples
127
137
  --------
128
138
  >>> data = [{'id': 1, 'value': 10}]
@@ -29,6 +29,14 @@ Notes
29
29
  When using `special_value`, ensure that `config` is set properly. The
30
30
  `default_value` is `None` by default.
31
31
 
32
+ This section also contains rST roles like :emphasis:`word` and :strong:`bold`
33
+ that should remain unchanged. Cross-references like `Section`_ should not be
34
+ modified, nor should anonymous refs like `Docs`__. External links like `Python
35
+ <https://www.python.org>`_ must also stay as-is.
36
+
37
+ Explicit targets like shown in the directive ``.. _`Special Target`:
38
+ https://example.com/special`` should not be touched.
39
+
32
40
  Examples
33
41
  --------
34
42
  >>> data = [{'id': 1, 'value': 10}]
@@ -67,6 +75,14 @@ Notes
67
75
  When using ``special_value``, ensure that ``config`` is set properly. The
68
76
  ``default_value`` is ``None`` by default.
69
77
 
78
+ This section also contains rST roles like :emphasis:`word` and :strong:`bold`
79
+ that should remain unchanged. Cross-references like `Section`_ should not be
80
+ modified, nor should anonymous refs like `Docs`__. External links like `Python
81
+ <https://www.python.org>`_ must also stay as-is.
82
+
83
+ Explicit targets like shown in the directive ``.. _`Special Target`:
84
+ https://example.com/special`` should not be touched.
85
+
70
86
  Examples
71
87
  --------
72
88
  >>> data = [{'id': 1, 'value': 10}]
@@ -5,6 +5,7 @@ import pytest
5
5
  from format_docstring.docstring_rewriter import wrap_docstring
6
6
  from format_docstring.line_wrap_numpy import (
7
7
  _fix_colon_spacing,
8
+ _fix_rst_backticks,
8
9
  _get_section_heading_title,
9
10
  _is_hyphen_underline,
10
11
  _is_param_signature,
@@ -243,6 +244,61 @@ def test_standardize_default_value(line: str, expected: str) -> None:
243
244
  assert _standardize_default_value(line) == expected
244
245
 
245
246
 
247
+ @pytest.mark.parametrize(
248
+ 'src, expected',
249
+ [
250
+ # --- should fix (inline literals) ---
251
+ ('Use `foo` to do something', 'Use ``foo`` to do something'),
252
+ ('Edge punctuation: `x`.', 'Edge punctuation: ``x``.'),
253
+ (
254
+ 'Multiple inline literals: `a` and `b`.',
255
+ 'Multiple inline literals: ``a`` and ``b``.',
256
+ ),
257
+ (
258
+ 'Underscores inside literal are fine: `foo_bar`.',
259
+ 'Underscores inside literal are fine: ``foo_bar``.',
260
+ ),
261
+ (
262
+ 'Adjacent to parentheses: (`call_me`) and `ok`',
263
+ 'Adjacent to parentheses: (``call_me``) and ``ok``',
264
+ ),
265
+ # Edge cases: literals that contain special characters -> should fix
266
+ ('`>>> `', '``>>> ``'),
267
+ ('`... `', '``... ``'),
268
+ # --- should not fix (roles) ---
269
+ (':emphasis:`word`', ':emphasis:`word`'),
270
+ (':strong:`bold`', ':strong:`bold`'),
271
+ (':sup:`2`', ':sup:`2`'),
272
+ (
273
+ ':title-reference:`The Great Book`',
274
+ ':title-reference:`The Great Book`',
275
+ ),
276
+ # --- should not fix (cross-references & links) ---
277
+ ('See `Section`_ for details', 'See `Section`_ for details'),
278
+ (
279
+ 'See `Docs`__ for the anonymous reference',
280
+ 'See `Docs`__ for the anonymous reference',
281
+ ),
282
+ (
283
+ '`Python <https://www.python.org>`_',
284
+ '`Python <https://www.python.org>`_',
285
+ ),
286
+ # --- should not fix (already correct literals) ---
287
+ (
288
+ 'Already has ``double`` backticks',
289
+ 'Already has ``double`` backticks',
290
+ ),
291
+ # --- should not fix (explicit hyperlink target) ---
292
+ (
293
+ '.. _`Special Target`: https://example.com/special',
294
+ '.. _`Special Target`: https://example.com/special',
295
+ ),
296
+ ],
297
+ )
298
+ def test_fix_rst_backticks_cases(src: str, expected: str) -> None:
299
+ assert _fix_rst_backticks(src) == expected
300
+
301
+
246
302
  @pytest.mark.parametrize(
247
303
  'fix_rst_backticks, input_docstring, expected_docstring',
248
304
  [
@@ -258,10 +314,10 @@ def test_standardize_default_value(line: str, expected: str) -> None:
258
314
  ),
259
315
  ],
260
316
  )
261
- def test_fix_rst_backticks(
317
+ def test_fix_rst_backticks_option_on_and_off(
262
318
  fix_rst_backticks: bool, input_docstring: str, expected_docstring: str
263
319
  ) -> None:
264
- """Test that backticks are fixed or preserved based on fix_rst_backticks"""
320
+ """Verify the `fix_rst_backticks` option can be correctly turned on/off"""
265
321
  result = wrap_docstring(
266
322
  input_docstring,
267
323
  line_length=79,