format-docstring 0.2.6__tar.gz → 0.2.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 (114) hide show
  1. {format_docstring-0.2.6 → format_docstring-0.2.7}/CHANGELOG.md +7 -0
  2. {format_docstring-0.2.6 → format_docstring-0.2.7}/PKG-INFO +1 -1
  3. {format_docstring-0.2.6 → format_docstring-0.2.7}/format_docstring/docstring_rewriter.py +48 -4
  4. {format_docstring-0.2.6 → format_docstring-0.2.7}/format_docstring.egg-info/PKG-INFO +1 -1
  5. {format_docstring-0.2.6 → format_docstring-0.2.7}/format_docstring.egg-info/SOURCES.txt +2 -0
  6. {format_docstring-0.2.6 → format_docstring-0.2.7}/pyproject.toml +1 -1
  7. format_docstring-0.2.7/tests/test_data/end_to_end/numpy/non_ascii_docstrings.txt +89 -0
  8. format_docstring-0.2.7/tests/test_data/line_wrap/numpy/non_ascii_docstrings.txt +89 -0
  9. {format_docstring-0.2.6 → format_docstring-0.2.7}/tests/test_docstring_rewriter.py +9 -1
  10. {format_docstring-0.2.6 → format_docstring-0.2.7}/.github/workflows/python-package.yml +0 -0
  11. {format_docstring-0.2.6 → format_docstring-0.2.7}/.github/workflows/python-publish.yml +0 -0
  12. {format_docstring-0.2.6 → format_docstring-0.2.7}/.gitignore +0 -0
  13. {format_docstring-0.2.6 → format_docstring-0.2.7}/.pre-commit-config.yaml +0 -0
  14. {format_docstring-0.2.6 → format_docstring-0.2.7}/.pre-commit-hooks.yaml +0 -0
  15. {format_docstring-0.2.6 → format_docstring-0.2.7}/AGENTS.md +0 -0
  16. {format_docstring-0.2.6 → format_docstring-0.2.7}/LICENSE +0 -0
  17. {format_docstring-0.2.6 → format_docstring-0.2.7}/README.md +0 -0
  18. {format_docstring-0.2.6 → format_docstring-0.2.7}/format_docstring/__init__.py +0 -0
  19. {format_docstring-0.2.6 → format_docstring-0.2.7}/format_docstring/base_fixer.py +0 -0
  20. {format_docstring-0.2.6 → format_docstring-0.2.7}/format_docstring/config.py +0 -0
  21. {format_docstring-0.2.6 → format_docstring-0.2.7}/format_docstring/line_wrap_google.py +0 -0
  22. {format_docstring-0.2.6 → format_docstring-0.2.7}/format_docstring/line_wrap_numpy.py +0 -0
  23. {format_docstring-0.2.6 → format_docstring-0.2.7}/format_docstring/line_wrap_utils.py +0 -0
  24. {format_docstring-0.2.6 → format_docstring-0.2.7}/format_docstring/main_jupyter.py +0 -0
  25. {format_docstring-0.2.6 → format_docstring-0.2.7}/format_docstring/main_py.py +0 -0
  26. {format_docstring-0.2.6 → format_docstring-0.2.7}/format_docstring.egg-info/dependency_links.txt +0 -0
  27. {format_docstring-0.2.6 → format_docstring-0.2.7}/format_docstring.egg-info/entry_points.txt +0 -0
  28. {format_docstring-0.2.6 → format_docstring-0.2.7}/format_docstring.egg-info/requires.txt +0 -0
  29. {format_docstring-0.2.6 → format_docstring-0.2.7}/format_docstring.egg-info/top_level.txt +0 -0
  30. {format_docstring-0.2.6 → format_docstring-0.2.7}/muff.toml +0 -0
  31. {format_docstring-0.2.6 → format_docstring-0.2.7}/requirements.dev +0 -0
  32. {format_docstring-0.2.6 → format_docstring-0.2.7}/setup.cfg +0 -0
  33. {format_docstring-0.2.6 → format_docstring-0.2.7}/tests/__init__.py +0 -0
  34. {format_docstring-0.2.6 → format_docstring-0.2.7}/tests/helpers.py +0 -0
  35. {format_docstring-0.2.6 → format_docstring-0.2.7}/tests/test_base_fixer.py +0 -0
  36. {format_docstring-0.2.6 → format_docstring-0.2.7}/tests/test_config.py +0 -0
  37. {format_docstring-0.2.6 → format_docstring-0.2.7}/tests/test_data/end_to_end/numpy/README.md +0 -0
  38. {format_docstring-0.2.6 → format_docstring-0.2.7}/tests/test_data/end_to_end/numpy/arg_name_is_default.txt +0 -0
  39. {format_docstring-0.2.6 → format_docstring-0.2.7}/tests/test_data/end_to_end/numpy/colon_spacing_fix.txt +0 -0
  40. {format_docstring-0.2.6 → format_docstring-0.2.7}/tests/test_data/end_to_end/numpy/contents_that_are_not_wrapped.txt +0 -0
  41. {format_docstring-0.2.6 → format_docstring-0.2.7}/tests/test_data/end_to_end/numpy/default_value_standardization.txt +0 -0
  42. {format_docstring-0.2.6 → format_docstring-0.2.7}/tests/test_data/end_to_end/numpy/empty_lines_are_respected.txt +0 -0
  43. {format_docstring-0.2.6 → format_docstring-0.2.7}/tests/test_data/end_to_end/numpy/examples_section.txt +0 -0
  44. {format_docstring-0.2.6 → format_docstring-0.2.7}/tests/test_data/end_to_end/numpy/existing_linebreaks_should_not_be_respected.txt +0 -0
  45. {format_docstring-0.2.6 → format_docstring-0.2.7}/tests/test_data/end_to_end/numpy/fix_rst_backticks.txt +0 -0
  46. {format_docstring-0.2.6 → format_docstring-0.2.7}/tests/test_data/end_to_end/numpy/four_level_nested_classes.txt +0 -0
  47. {format_docstring-0.2.6 → format_docstring-0.2.7}/tests/test_data/end_to_end/numpy/indent_four_levels_16_spaces_width_10.txt +0 -0
  48. {format_docstring-0.2.6 → format_docstring-0.2.7}/tests/test_data/end_to_end/numpy/indent_misaligned_all.txt +0 -0
  49. {format_docstring-0.2.6 → format_docstring-0.2.7}/tests/test_data/end_to_end/numpy/indent_two_levels_8_spaces.txt +0 -0
  50. {format_docstring-0.2.6 → format_docstring-0.2.7}/tests/test_data/end_to_end/numpy/line_length_2.txt +0 -0
  51. {format_docstring-0.2.6 → format_docstring-0.2.7}/tests/test_data/end_to_end/numpy/mismatched_underlines.txt +0 -0
  52. {format_docstring-0.2.6 → format_docstring-0.2.7}/tests/test_data/end_to_end/numpy/mismatched_underlines_one_dash.txt +0 -0
  53. {format_docstring-0.2.6 → format_docstring-0.2.7}/tests/test_data/end_to_end/numpy/mismatched_underlines_two_dashes.txt +0 -0
  54. {format_docstring-0.2.6 → format_docstring-0.2.7}/tests/test_data/end_to_end/numpy/module_level_docstring.txt +0 -0
  55. {format_docstring-0.2.6 → format_docstring-0.2.7}/tests/test_data/end_to_end/numpy/new_lines_before_and_after.txt +0 -0
  56. {format_docstring-0.2.6 → format_docstring-0.2.7}/tests/test_data/end_to_end/numpy/no_format_docstring_comment.txt +0 -0
  57. {format_docstring-0.2.6 → format_docstring-0.2.7}/tests/test_data/end_to_end/numpy/param_signature_without_type.txt +0 -0
  58. {format_docstring-0.2.6 → format_docstring-0.2.7}/tests/test_data/end_to_end/numpy/parameters_returns_raises_wrapping.txt +0 -0
  59. {format_docstring-0.2.6 → format_docstring-0.2.7}/tests/test_data/end_to_end/numpy/rST_cross_reference.txt +0 -0
  60. {format_docstring-0.2.6 → format_docstring-0.2.7}/tests/test_data/end_to_end/numpy/returns_signature_and_description.txt +0 -0
  61. {format_docstring-0.2.6 → format_docstring-0.2.7}/tests/test_data/end_to_end/numpy/section_headings_with_colons.txt +0 -0
  62. {format_docstring-0.2.6 → format_docstring-0.2.7}/tests/test_data/end_to_end/numpy/section_title_fixed.txt +0 -0
  63. {format_docstring-0.2.6 → format_docstring-0.2.7}/tests/test_data/end_to_end/numpy/sections_notes_examples.txt +0 -0
  64. {format_docstring-0.2.6 → format_docstring-0.2.7}/tests/test_data/end_to_end/numpy/signature_dont_sync_raises.txt +0 -0
  65. {format_docstring-0.2.6 → format_docstring-0.2.7}/tests/test_data/end_to_end/numpy/signature_line_is_not_wrapped.txt +0 -0
  66. {format_docstring-0.2.6 → format_docstring-0.2.7}/tests/test_data/end_to_end/numpy/signature_sync_class_docstrings.txt +0 -0
  67. {format_docstring-0.2.6 → format_docstring-0.2.7}/tests/test_data/end_to_end/numpy/signature_sync_parameters.txt +0 -0
  68. {format_docstring-0.2.6 → format_docstring-0.2.7}/tests/test_data/end_to_end/numpy/signature_sync_returns.txt +0 -0
  69. {format_docstring-0.2.6 → format_docstring-0.2.7}/tests/test_data/end_to_end/numpy/signature_sync_yields.txt +0 -0
  70. {format_docstring-0.2.6 → format_docstring-0.2.7}/tests/test_data/end_to_end/numpy/single_line_docstring.txt +0 -0
  71. {format_docstring-0.2.6 → format_docstring-0.2.7}/tests/test_data/end_to_end/numpy/texts_are_rewrapped.txt +0 -0
  72. {format_docstring-0.2.6 → format_docstring-0.2.7}/tests/test_data/end_to_end/numpy/variadic_signature_without_colon.txt +0 -0
  73. {format_docstring-0.2.6 → format_docstring-0.2.7}/tests/test_data/end_to_end/numpy/very_long_unbreakable_word.txt +0 -0
  74. {format_docstring-0.2.6 → format_docstring-0.2.7}/tests/test_data/integration_test/numpy/after.ipynb +0 -0
  75. {format_docstring-0.2.6 → format_docstring-0.2.7}/tests/test_data/integration_test/numpy/after.py +0 -0
  76. {format_docstring-0.2.6 → format_docstring-0.2.7}/tests/test_data/integration_test/numpy/after_50.ipynb +0 -0
  77. {format_docstring-0.2.6 → format_docstring-0.2.7}/tests/test_data/integration_test/numpy/after_50.py +0 -0
  78. {format_docstring-0.2.6 → format_docstring-0.2.7}/tests/test_data/integration_test/numpy/before.ipynb +0 -0
  79. {format_docstring-0.2.6 → format_docstring-0.2.7}/tests/test_data/integration_test/numpy/before.py +0 -0
  80. {format_docstring-0.2.6 → format_docstring-0.2.7}/tests/test_data/jupyter/before.ipynb +0 -0
  81. {format_docstring-0.2.6 → format_docstring-0.2.7}/tests/test_data/jupyter/verbose_before.ipynb +0 -0
  82. {format_docstring-0.2.6 → format_docstring-0.2.7}/tests/test_data/line_wrap/numpy/README.md +0 -0
  83. {format_docstring-0.2.6 → format_docstring-0.2.7}/tests/test_data/line_wrap/numpy/colon_spacing_fix.txt +0 -0
  84. {format_docstring-0.2.6 → format_docstring-0.2.7}/tests/test_data/line_wrap/numpy/contents_that_are_not_wrapped.txt +0 -0
  85. {format_docstring-0.2.6 → format_docstring-0.2.7}/tests/test_data/line_wrap/numpy/default_value_standardization.txt +0 -0
  86. {format_docstring-0.2.6 → format_docstring-0.2.7}/tests/test_data/line_wrap/numpy/empty_lines_are_respected.txt +0 -0
  87. {format_docstring-0.2.6 → format_docstring-0.2.7}/tests/test_data/line_wrap/numpy/examples_section.txt +0 -0
  88. {format_docstring-0.2.6 → format_docstring-0.2.7}/tests/test_data/line_wrap/numpy/existing_linebreaks_should_not_be_respected.txt +0 -0
  89. {format_docstring-0.2.6 → format_docstring-0.2.7}/tests/test_data/line_wrap/numpy/fix_rst_backticks.txt +0 -0
  90. {format_docstring-0.2.6 → format_docstring-0.2.7}/tests/test_data/line_wrap/numpy/indent_four_levels_16_spaces_width_10.txt +0 -0
  91. {format_docstring-0.2.6 → format_docstring-0.2.7}/tests/test_data/line_wrap/numpy/indent_two_levels_8_spaces.txt +0 -0
  92. {format_docstring-0.2.6 → format_docstring-0.2.7}/tests/test_data/line_wrap/numpy/line_length_2.txt +0 -0
  93. {format_docstring-0.2.6 → format_docstring-0.2.7}/tests/test_data/line_wrap/numpy/mismatched_underlines.txt +0 -0
  94. {format_docstring-0.2.6 → format_docstring-0.2.7}/tests/test_data/line_wrap/numpy/mismatched_underlines_one_dash.txt +0 -0
  95. {format_docstring-0.2.6 → format_docstring-0.2.7}/tests/test_data/line_wrap/numpy/mismatched_underlines_two_dashes.txt +0 -0
  96. {format_docstring-0.2.6 → format_docstring-0.2.7}/tests/test_data/line_wrap/numpy/module_level_docstring.txt +0 -0
  97. {format_docstring-0.2.6 → format_docstring-0.2.7}/tests/test_data/line_wrap/numpy/param_signature_without_type.txt +0 -0
  98. {format_docstring-0.2.6 → format_docstring-0.2.7}/tests/test_data/line_wrap/numpy/parameters_returns_raises_wrapping.txt +0 -0
  99. {format_docstring-0.2.6 → format_docstring-0.2.7}/tests/test_data/line_wrap/numpy/returns_signature_and_description.txt +0 -0
  100. {format_docstring-0.2.6 → format_docstring-0.2.7}/tests/test_data/line_wrap/numpy/section_headings_with_colons.txt +0 -0
  101. {format_docstring-0.2.6 → format_docstring-0.2.7}/tests/test_data/line_wrap/numpy/section_title_fixed.txt +0 -0
  102. {format_docstring-0.2.6 → format_docstring-0.2.7}/tests/test_data/line_wrap/numpy/sections_notes_examples.txt +0 -0
  103. {format_docstring-0.2.6 → format_docstring-0.2.7}/tests/test_data/line_wrap/numpy/signature_line_is_not_wrapped.txt +0 -0
  104. {format_docstring-0.2.6 → format_docstring-0.2.7}/tests/test_data/line_wrap/numpy/texts_are_rewrapped.txt +0 -0
  105. {format_docstring-0.2.6 → format_docstring-0.2.7}/tests/test_data/line_wrap/numpy/variadic_signature_without_colon.txt +0 -0
  106. {format_docstring-0.2.6 → format_docstring-0.2.7}/tests/test_data/line_wrap/numpy/very_long_unbreakable_word.txt +0 -0
  107. {format_docstring-0.2.6 → format_docstring-0.2.7}/tests/test_data/playground.py +0 -0
  108. {format_docstring-0.2.6 → format_docstring-0.2.7}/tests/test_line_wrap_google.py +0 -0
  109. {format_docstring-0.2.6 → format_docstring-0.2.7}/tests/test_line_wrap_numpy.py +0 -0
  110. {format_docstring-0.2.6 → format_docstring-0.2.7}/tests/test_line_wrap_utils.py +0 -0
  111. {format_docstring-0.2.6 → format_docstring-0.2.7}/tests/test_main_jupyter.py +0 -0
  112. {format_docstring-0.2.6 → format_docstring-0.2.7}/tests/test_main_py.py +0 -0
  113. {format_docstring-0.2.6 → format_docstring-0.2.7}/tests/test_playground.py +0 -0
  114. {format_docstring-0.2.6 → format_docstring-0.2.7}/tox.ini +0 -0
@@ -6,6 +6,13 @@ 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.2.7] - 2025-12-04
10
+
11
+ - Fixed
12
+ - Bug where non-ASCII characters would mess up auto formatting
13
+ - Full diff
14
+ - https://github.com/jsh9/format-docstring/compare/0.2.6...0.2.7
15
+
9
16
  ## [0.2.6] - 2025-11-21
10
17
 
11
18
  - Fixed
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: format-docstring
3
- Version: 0.2.6
3
+ Version: 0.2.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>
@@ -427,8 +427,23 @@ def build_replacement_docstring(
427
427
  if not hasattr(val, 'lineno') or not hasattr(val, 'end_lineno'):
428
428
  return None
429
429
 
430
- start: int = calc_abs_pos(line_starts, val.lineno, val.col_offset)
431
- end: int = calc_abs_pos(line_starts, val.end_lineno, val.end_col_offset) # type: ignore[arg-type]
430
+ # ``end_lineno``/``end_col_offset`` are optional on older AST nodes or
431
+ # when running under tooling that strips positional info, so bail out if
432
+ # they are missing to avoid slicing with ``None`` later.
433
+ end_lineno: int | None = getattr(val, 'end_lineno', None)
434
+ end_col_offset: int | None = getattr(val, 'end_col_offset', None)
435
+ if end_lineno is None or end_col_offset is None:
436
+ return None
437
+
438
+ start: int = calc_abs_pos(
439
+ source_code, line_starts, val.lineno, val.col_offset
440
+ )
441
+ end: int = calc_abs_pos(
442
+ source_code,
443
+ line_starts,
444
+ end_lineno,
445
+ end_col_offset,
446
+ )
432
447
  original_literal = source_code[start:end]
433
448
 
434
449
  if _has_inline_no_format_comment(source_code, end):
@@ -524,12 +539,19 @@ def find_docstring(node: ModuleClassOrFunc) -> ast.Expr | None:
524
539
  return None
525
540
 
526
541
 
527
- def calc_abs_pos(line_starts: list[int], lineno: int, col: int) -> int:
542
+ def calc_abs_pos(
543
+ source_code: str, line_starts: list[int], lineno: int, col: int
544
+ ) -> int:
528
545
  """
529
546
  Convert a (lineno, col) pair to an absolute index.
530
547
 
531
548
  Parameters
532
549
  ----------
550
+ source_code : str
551
+ Full source text for computing character offsets. AST column offsets
552
+ are byte-based, so we need the actual text to translate them back to
553
+ character indices when multi-byte Unicode code points (e.g., 😄, é, 文)
554
+ are present.
533
555
  line_starts : list[int]
534
556
  Precomputed start offsets for each line, from :func:`_line_starts`.
535
557
  lineno : int
@@ -542,7 +564,29 @@ def calc_abs_pos(line_starts: list[int], lineno: int, col: int) -> int:
542
564
  int
543
565
  The absolute character index into the source string.
544
566
  """
545
- return line_starts[lineno - 1] + col
567
+ line_idx = lineno - 1
568
+ line_start = line_starts[line_idx]
569
+ next_line_start = (
570
+ line_starts[line_idx + 1]
571
+ if line_idx + 1 < len(line_starts)
572
+ else len(source_code)
573
+ )
574
+ line_segment = source_code[line_start:next_line_start]
575
+
576
+ # Column offsets from the AST are measured in bytes, so convert them back
577
+ # to character offsets when slicing the original ``str`` source. Iterate
578
+ # through the current line until reaching the requested byte position.
579
+ byte_count = 0
580
+ char_offset = 0
581
+ for char in line_segment:
582
+ if byte_count >= col:
583
+ break
584
+
585
+ byte_count += len(char.encode('utf-8'))
586
+ char_offset += 1
587
+
588
+ # Clamp to the line length in case the reported byte offset overshoots.
589
+ return line_start + min(char_offset, len(line_segment))
546
590
 
547
591
 
548
592
  def rebuild_literal(original_literal: str, content: str) -> str | None:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: format-docstring
3
- Version: 0.2.6
3
+ Version: 0.2.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>
@@ -58,6 +58,7 @@ tests/test_data/end_to_end/numpy/mismatched_underlines_two_dashes.txt
58
58
  tests/test_data/end_to_end/numpy/module_level_docstring.txt
59
59
  tests/test_data/end_to_end/numpy/new_lines_before_and_after.txt
60
60
  tests/test_data/end_to_end/numpy/no_format_docstring_comment.txt
61
+ tests/test_data/end_to_end/numpy/non_ascii_docstrings.txt
61
62
  tests/test_data/end_to_end/numpy/param_signature_without_type.txt
62
63
  tests/test_data/end_to_end/numpy/parameters_returns_raises_wrapping.txt
63
64
  tests/test_data/end_to_end/numpy/rST_cross_reference.txt
@@ -98,6 +99,7 @@ tests/test_data/line_wrap/numpy/mismatched_underlines.txt
98
99
  tests/test_data/line_wrap/numpy/mismatched_underlines_one_dash.txt
99
100
  tests/test_data/line_wrap/numpy/mismatched_underlines_two_dashes.txt
100
101
  tests/test_data/line_wrap/numpy/module_level_docstring.txt
102
+ tests/test_data/line_wrap/numpy/non_ascii_docstrings.txt
101
103
  tests/test_data/line_wrap/numpy/param_signature_without_type.txt
102
104
  tests/test_data/line_wrap/numpy/parameters_returns_raises_wrapping.txt
103
105
  tests/test_data/line_wrap/numpy/returns_signature_and_description.txt
@@ -4,7 +4,7 @@ requires = ["setuptools-scm[toml]>=6.2", "setuptools>=45"]
4
4
 
5
5
  [project]
6
6
  name = "format-docstring"
7
- version = "0.2.6"
7
+ version = "0.2.7"
8
8
  dependencies = [
9
9
  "click>=8.0",
10
10
  "jupyter-notebook-parser>=0.1.4",
@@ -0,0 +1,89 @@
1
+ LINE_LENGTH: 79
2
+
3
+ **********
4
+
5
+ # Non-ASCII characters should not interfere with line length calculation.
6
+
7
+ def unicode_docstring_pythagoras() -> None:
8
+ """a² + b² = c²"""
9
+ return None
10
+
11
+ def unicode_docstring_quadratic() -> None:
12
+ """Δ = √(b² - 4ac)"""
13
+ return None
14
+
15
+ def unicode_docstring_emoji() -> None:
16
+ """emoji 😄🚀 with sparkle ✨"""
17
+ return None
18
+
19
+ def unicode_docstring_accents() -> None:
20
+ """accents naïve façade jalapeño año"""
21
+ return None
22
+
23
+ def unicode_docstring_greek() -> None:
24
+ """Greek letters αβγδεζηθ"""
25
+ return None
26
+
27
+ def unicode_docstring_cyrillic() -> None:
28
+ """Cyrillic Привет мир"""
29
+ return None
30
+
31
+ def unicode_docstring_cjk() -> None:
32
+ """CJK 面積は平方メートルです"""
33
+ return None
34
+
35
+ def unicode_docstring_pi_tau() -> None:
36
+ """Math π·r² + τ is about 6.283"""
37
+ return None
38
+
39
+ def unicode_docstring_currency() -> None:
40
+ """Currency mix € £ ¥ ₽"""
41
+ return None
42
+
43
+ def unicode_docstring_hebrew() -> None:
44
+ """Hebrew שלום עליכם"""
45
+ return None
46
+
47
+ **********
48
+
49
+ # Non-ASCII characters should not interfere with line length calculation.
50
+
51
+ def unicode_docstring_pythagoras() -> None:
52
+ """a² + b² = c²"""
53
+ return None
54
+
55
+ def unicode_docstring_quadratic() -> None:
56
+ """Δ = √(b² - 4ac)"""
57
+ return None
58
+
59
+ def unicode_docstring_emoji() -> None:
60
+ """emoji 😄🚀 with sparkle ✨"""
61
+ return None
62
+
63
+ def unicode_docstring_accents() -> None:
64
+ """accents naïve façade jalapeño año"""
65
+ return None
66
+
67
+ def unicode_docstring_greek() -> None:
68
+ """Greek letters αβγδεζηθ"""
69
+ return None
70
+
71
+ def unicode_docstring_cyrillic() -> None:
72
+ """Cyrillic Привет мир"""
73
+ return None
74
+
75
+ def unicode_docstring_cjk() -> None:
76
+ """CJK 面積は平方メートルです"""
77
+ return None
78
+
79
+ def unicode_docstring_pi_tau() -> None:
80
+ """Math π·r² + τ is about 6.283"""
81
+ return None
82
+
83
+ def unicode_docstring_currency() -> None:
84
+ """Currency mix € £ ¥ ₽"""
85
+ return None
86
+
87
+ def unicode_docstring_hebrew() -> None:
88
+ """Hebrew שלום עליכם"""
89
+ return None
@@ -0,0 +1,89 @@
1
+ LINE_LENGTH: 79
2
+
3
+ **********
4
+
5
+ Non-ASCII characters should not interfere with line length calculation.
6
+
7
+ Function f_square
8
+ -----------------
9
+ a² + b² = c²
10
+
11
+ Function f_delta
12
+ ----------------
13
+ Δ = √(b² - 4ac)
14
+
15
+ Function f_emoji
16
+ ----------------
17
+ emoji 😄🚀 with sparkle ✨
18
+
19
+ Function f_accents
20
+ ------------------
21
+ accents naïve façade jalapeño año
22
+
23
+ Function f_greek
24
+ ----------------
25
+ Greek letters αβγδεζηθ
26
+
27
+ Function f_cyrillic
28
+ -------------------
29
+ Cyrillic Привет мир
30
+
31
+ Function f_cjk
32
+ ---------------
33
+ CJK 面積は平方メートルです
34
+
35
+ Function f_pi_tau
36
+ -----------------
37
+ Math π·r² + τ is about 6.283
38
+
39
+ Function f_currency
40
+ -------------------
41
+ Currency mix € £ ¥ ₽
42
+
43
+ Function f_hebrew
44
+ -----------------
45
+ Hebrew שלום עליכם
46
+
47
+ **********
48
+
49
+ Non-ASCII characters should not interfere with line length calculation.
50
+
51
+ Function f_square
52
+ -----------------
53
+ a² + b² = c²
54
+
55
+ Function f_delta
56
+ ----------------
57
+ Δ = √(b² - 4ac)
58
+
59
+ Function f_emoji
60
+ ----------------
61
+ emoji 😄🚀 with sparkle ✨
62
+
63
+ Function f_accents
64
+ ------------------
65
+ accents naïve façade jalapeño año
66
+
67
+ Function f_greek
68
+ ----------------
69
+ Greek letters αβγδεζηθ
70
+
71
+ Function f_cyrillic
72
+ -------------------
73
+ Cyrillic Привет мир
74
+
75
+ Function f_cjk
76
+ ---------------
77
+ CJK 面積は平方メートルです
78
+
79
+ Function f_pi_tau
80
+ -----------------
81
+ Math π·r² + τ is about 6.283
82
+
83
+ Function f_currency
84
+ -------------------
85
+ Currency mix € £ ¥ ₽
86
+
87
+ Function f_hebrew
88
+ -----------------
89
+ Hebrew שלום עליכם
@@ -28,12 +28,20 @@ def test_calc_line_starts(src: str, expected: list[int]) -> None:
28
28
  ('a\n\nxyz\n', 2, 0, 2),
29
29
  ('a\n\nxyz\n', 3, 2, 5),
30
30
  ('one\ntwo\nthree', 2, 1, 5),
31
+ (
32
+ 'def f():\n """π"""\n pass\n',
33
+ 2,
34
+ len(' """π"""'.encode()),
35
+ len('def f():\n') + len(' """π"""'),
36
+ ),
31
37
  ],
32
38
  )
33
39
  def test_calc_abs_pos(src: str, lineno: int, col: int, expected: int) -> None:
34
40
  """Convert (lineno, col) to absolute indices using starts mapping."""
35
41
  starts = docstring_rewriter.calc_line_starts(src)
36
- assert docstring_rewriter.calc_abs_pos(starts, lineno, col) == expected
42
+ assert (
43
+ docstring_rewriter.calc_abs_pos(src, starts, lineno, col) == expected
44
+ )
37
45
 
38
46
 
39
47
  @pytest.mark.parametrize(