readability-cli 0.10.0__tar.gz → 0.10.1__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 (37) hide show
  1. {readability_cli-0.10.0 → readability_cli-0.10.1}/PKG-INFO +4 -3
  2. {readability_cli-0.10.0 → readability_cli-0.10.1}/README.md +3 -2
  3. {readability_cli-0.10.0 → readability_cli-0.10.1}/pyproject.toml +7 -1
  4. {readability_cli-0.10.0 → readability_cli-0.10.1}/readability/checking.py +8 -10
  5. {readability_cli-0.10.0 → readability_cli-0.10.1}/readability/cli.py +8 -9
  6. {readability_cli-0.10.0 → readability_cli-0.10.1}/readability/configs/ruff.toml +8 -0
  7. {readability_cli-0.10.0 → readability_cli-0.10.1}/readability/guide.py +5 -7
  8. {readability_cli-0.10.0 → readability_cli-0.10.1}/readability/outline.py +19 -43
  9. {readability_cli-0.10.0 → readability_cli-0.10.1}/test_checking.py +19 -10
  10. {readability_cli-0.10.0 → readability_cli-0.10.1}/test_guide.py +9 -11
  11. {readability_cli-0.10.0 → readability_cli-0.10.1}/test_outline.py +16 -26
  12. {readability_cli-0.10.0 → readability_cli-0.10.1}/test_package.py +4 -2
  13. {readability_cli-0.10.0 → readability_cli-0.10.1}/uv.lock +1 -1
  14. {readability_cli-0.10.0 → readability_cli-0.10.1}/.github/workflows/ci.yml +0 -0
  15. {readability_cli-0.10.0 → readability_cli-0.10.1}/.github/workflows/publish.yml +0 -0
  16. {readability_cli-0.10.0 → readability_cli-0.10.1}/.github/workflows/update-guides.yml +0 -0
  17. {readability_cli-0.10.0 → readability_cli-0.10.1}/.gitignore +0 -0
  18. {readability_cli-0.10.0 → readability_cli-0.10.1}/.python-version +0 -0
  19. {readability_cli-0.10.0 → readability_cli-0.10.1}/LICENSE +0 -0
  20. {readability_cli-0.10.0 → readability_cli-0.10.1}/readability/__init__.py +0 -0
  21. {readability_cli-0.10.0 → readability_cli-0.10.1}/readability/configs/biome-default.json +0 -0
  22. {readability_cli-0.10.0 → readability_cli-0.10.1}/readability/configs/pyrefly.toml +0 -0
  23. {readability_cli-0.10.0 → readability_cli-0.10.1}/readability/guides/Rguide.md +0 -0
  24. {readability_cli-0.10.0 → readability_cli-0.10.1}/readability/guides/cppguide.md +0 -0
  25. {readability_cli-0.10.0 → readability_cli-0.10.1}/readability/guides/csharp-style.md +0 -0
  26. {readability_cli-0.10.0 → readability_cli-0.10.1}/readability/guides/docguide-style.md +0 -0
  27. {readability_cli-0.10.0 → readability_cli-0.10.1}/readability/guides/go-guide.md +0 -0
  28. {readability_cli-0.10.0 → readability_cli-0.10.1}/readability/guides/htmlcssguide.md +0 -0
  29. {readability_cli-0.10.0 → readability_cli-0.10.1}/readability/guides/javaguide.md +0 -0
  30. {readability_cli-0.10.0 → readability_cli-0.10.1}/readability/guides/jsguide.md +0 -0
  31. {readability_cli-0.10.0 → readability_cli-0.10.1}/readability/guides/jsoncstyleguide.md +0 -0
  32. {readability_cli-0.10.0 → readability_cli-0.10.1}/readability/guides/objcguide.md +0 -0
  33. {readability_cli-0.10.0 → readability_cli-0.10.1}/readability/guides/pyguide.md +0 -0
  34. {readability_cli-0.10.0 → readability_cli-0.10.1}/readability/guides/shellguide.md +0 -0
  35. {readability_cli-0.10.0 → readability_cli-0.10.1}/readability/guides/tsguide.md +0 -0
  36. {readability_cli-0.10.0 → readability_cli-0.10.1}/readability/guides/vimscriptguide.md +0 -0
  37. {readability_cli-0.10.0 → readability_cli-0.10.1}/readability/tools.py +4 -4
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: readability-cli
3
- Version: 0.10.0
3
+ Version: 0.10.1
4
4
  Summary: A CLI to lint, format, and type-check code with Google-style defaults, and pull Google style guides in markdown format.
5
5
  Project-URL: Homepage, https://github.com/owahltinez/readability
6
6
  Project-URL: Repository, https://github.com/owahltinez/readability
@@ -180,8 +180,9 @@ caller happened to be standing in.
180
180
 
181
181
  Ruff and Pyrefly defaults follow the
182
182
  [Google Python style guide](https://google.github.io/styleguide/pyguide.html):
183
- 80-column lines, Google docstrings, import ordering, and full type checking. The
184
- Biome default applies the 80-column lines and two-space indentation of the
183
+ 80-column lines, Google docstrings, one import per line sorted as isort's
184
+ `google` profile does, and full type checking. The Biome default applies the
185
+ 80-column lines and two-space indentation of the
185
186
  [Google JavaScript style guide](https://google.github.io/styleguide/jsguide.html)
186
187
  and enables Biome's recommended lint rules. Project `biome.json` and
187
188
  `biome.jsonc` files replace those bundled defaults for Biome-owned formats.
@@ -166,8 +166,9 @@ caller happened to be standing in.
166
166
 
167
167
  Ruff and Pyrefly defaults follow the
168
168
  [Google Python style guide](https://google.github.io/styleguide/pyguide.html):
169
- 80-column lines, Google docstrings, import ordering, and full type checking. The
170
- Biome default applies the 80-column lines and two-space indentation of the
169
+ 80-column lines, Google docstrings, one import per line sorted as isort's
170
+ `google` profile does, and full type checking. The Biome default applies the
171
+ 80-column lines and two-space indentation of the
171
172
  [Google JavaScript style guide](https://google.github.io/styleguide/jsguide.html)
172
173
  and enables Biome's recommended lint rules. Project `biome.json` and
173
174
  `biome.jsonc` files replace those bundled defaults for Biome-owned formats.
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "readability-cli"
3
- version = "0.10.0"
3
+ version = "0.10.1"
4
4
  description = "A CLI to lint, format, and type-check code with Google-style defaults, and pull Google style guides in markdown format."
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.12"
@@ -47,6 +47,12 @@ ignore = ["PLR0911", "PLR0912", "PLR0913", "PLR0915", "PLR2004"]
47
47
  [tool.ruff.lint.pydocstyle]
48
48
  convention = "google"
49
49
 
50
+ [tool.ruff.lint.isort]
51
+ force-single-line = true
52
+ force-sort-within-sections = true
53
+ single-line-exclusions = ["typing"]
54
+ order-by-type = false
55
+
50
56
  [tool.ruff.lint.per-file-ignores]
51
57
  "test_*.py" = ["D"]
52
58
  "*_test.py" = ["D"]
@@ -1,21 +1,19 @@
1
1
  """Run readability checks and report their coverage."""
2
2
 
3
+ from collections.abc import Sequence
3
4
  import dataclasses
4
5
  import logging
5
- import subprocess
6
- from collections.abc import Sequence
7
6
  from pathlib import Path
7
+ import subprocess
8
8
 
9
9
  import click
10
10
 
11
- from readability.tools import (
12
- ToolPlan,
13
- _command_batches,
14
- _get_tool_definitions,
15
- _repository_root,
16
- _should_run_tool,
17
- _tool_is_installed,
18
- )
11
+ from readability.tools import _command_batches
12
+ from readability.tools import _get_tool_definitions
13
+ from readability.tools import _repository_root
14
+ from readability.tools import _should_run_tool
15
+ from readability.tools import _tool_is_installed
16
+ from readability.tools import ToolPlan
19
17
 
20
18
  logger = logging.getLogger("readability")
21
19
  DEFAULT_TIMEOUT = 60
@@ -1,21 +1,20 @@
1
1
  """Command-line interface for readability."""
2
2
 
3
+ from collections.abc import Sequence
3
4
  import logging
4
5
  import os
5
6
  import sys
6
- from collections.abc import Sequence
7
7
 
8
8
  import click
9
9
 
10
10
  from readability.checking import check_paths
11
- from readability.guide import (
12
- LANGUAGE_MAP,
13
- get_guide,
14
- get_guides_dir,
15
- get_local_path,
16
- refresh_guide,
17
- )
18
- from readability.outline import _echo_outline, _select_section
11
+ from readability.guide import get_guide
12
+ from readability.guide import get_guides_dir
13
+ from readability.guide import get_local_path
14
+ from readability.guide import LANGUAGE_MAP
15
+ from readability.guide import refresh_guide
16
+ from readability.outline import _echo_outline
17
+ from readability.outline import _select_section
19
18
 
20
19
  logger = logging.getLogger("readability")
21
20
 
@@ -14,6 +14,14 @@ ignore = ["PLR0911", "PLR0912", "PLR0913", "PLR0915", "PLR2004"]
14
14
  [lint.pydocstyle]
15
15
  convention = "google"
16
16
 
17
+ [lint.isort]
18
+ # Mirrors isort's google profile; its lexicographical and group-by-package
19
+ # options have no ruff equivalent
20
+ force-single-line = true
21
+ force-sort-within-sections = true
22
+ single-line-exclusions = ["typing"]
23
+ order-by-type = false
24
+
17
25
  [lint.per-file-ignores]
18
26
  # Docstring requirements are noise in test files
19
27
  "test_*.py" = ["D"]
@@ -1,14 +1,15 @@
1
1
  """Fetch and cache Google style guides."""
2
2
 
3
+ from importlib.resources import files
3
4
  import logging
4
5
  import os
5
6
  import warnings
6
- from importlib.resources import files
7
7
 
8
+ from bs4 import BeautifulSoup
9
+ from bs4 import XMLParsedAsHTMLWarning
8
10
  import click
9
- import requests
10
- from bs4 import BeautifulSoup, XMLParsedAsHTMLWarning
11
11
  from markdownify import markdownify as md
12
+ import requests
12
13
 
13
14
  warnings.filterwarnings("ignore", category=XMLParsedAsHTMLWarning)
14
15
 
@@ -55,10 +56,7 @@ LANGUAGE_MAP = {
55
56
 
56
57
  BASE_URL = "https://google.github.io/styleguide/"
57
58
 
58
- # Style guides are dense with snake_case and dunder identifiers, and escaping
59
- # their underscores leaves 'from \_\_future\_\_ import' in the text a caller
60
- # greps or reads. CommonMark would render a bare '__future__' as emphasis, but
61
- # these guides are consumed as plain text, where fidelity matters more.
59
+ # Escaping underscores would leave 'from \_\_future\_\_ import' in the text
62
60
  MARKDOWNIFY_OPTIONS = {"heading_style": "ATX", "escape_underscores": False}
63
61
 
64
62
 
@@ -1,31 +1,27 @@
1
1
  """Parse, search, and render style-guide outlines."""
2
2
 
3
+ from collections.abc import Iterator
4
+ from collections.abc import Sequence
5
+ from dataclasses import dataclass
3
6
  import re
4
7
  import sys
5
- from collections.abc import Iterator, Sequence
6
- from dataclasses import dataclass
7
8
  from typing import Any
8
9
 
9
10
  import click
10
11
 
11
- # A fence opens or closes a code block; anything inside is sample code, not
12
- # document structure. Guides for `#`-commented languages (shell, Python) would
13
- # otherwise report hundreds of code comments as headings.
12
+ # Inside a fence is sample code, where a '#' comment is not a heading
14
13
  FENCE_PATTERN = re.compile(r"^\s{0,3}(?:```|~~~)")
15
14
 
16
- # Closing hashes are optional in ATX headings and must be space-separated, so
17
- # a title such as 'C#' keeps its trailing character.
15
+ # Closing hashes are space-separated, so a title like 'C#' keeps its own
18
16
  HEADING_PATTERN = re.compile(r"^(#{1,6})\s+(.*?)(?:\s+#+)?\s*$")
19
17
 
20
- # A section number the document itself prints, e.g. '2.2' in '2.2 Imports'.
18
+ # A number the document prints itself, e.g. '2.2' in '2.2 Imports'
21
19
  DOCUMENT_NUMBER_PATTERN = re.compile(r"^(\d+(?:\.\d+)*)\.?\s+(.+)$")
22
20
 
23
- # Guides put a heading's link targets on the lines above it, which would
24
- # otherwise trail the end of the preceding section.
21
+ # Link targets sit above their heading, not at the end of the one before
25
22
  ANCHOR_PATTERN = re.compile(r'^<a id="[^"]*"></a>$')
26
23
 
27
- # The separator in a scoped reference such as 'Imports > Decision'. Spaces on
28
- # both sides are required so that a heading like '`Array<T>` Type' stays whole.
24
+ # Scoped reference separator; spaces required so '`Array<T>` Type' stays whole
29
25
  PATH_SEPARATOR_PATTERN = re.compile(r"\s+>\s+")
30
26
 
31
27
 
@@ -148,8 +144,7 @@ def parse_headings(content: str) -> list[Heading]:
148
144
  if not raw:
149
145
  return []
150
146
 
151
- # Only three of the shipped guides number their headings. A dotted number
152
- # ('2.2') is the reliable signal; a bare leading digit is not.
147
+ # A dotted number is the reliable signal; a bare leading digit is not
153
148
  document_numbers = [
154
149
  match.group(1)
155
150
  for _, _, text in raw
@@ -157,8 +152,7 @@ def parse_headings(content: str) -> list[Heading]:
157
152
  ]
158
153
  numbered = any("." in number for number in document_numbers)
159
154
 
160
- # A lone top-level heading is the document title: it roots the tree rather
161
- # than being the first section, so numbering starts with its children.
155
+ # A lone top-level heading is the title, so numbering starts below it
162
156
  top_level = min(level for _, level, _ in raw)
163
157
  top_level_lines = [line for line, level, _ in raw if level == top_level]
164
158
  title_line = top_level_lines[0] if len(top_level_lines) == 1 else None
@@ -169,12 +163,7 @@ def parse_headings(content: str) -> list[Heading]:
169
163
  index = "" if line == title_line else _next_index(open_headings, level)
170
164
  number, title = _split_document_number(text, numbered)
171
165
 
172
- # A guide that numbers its own sections is the authority on what they
173
- # are called, so its numbers address them. A positional index would
174
- # drift wherever the guide skips one — pyguide has no 2.15 at all,
175
- # and calling its 2.16 by that name would cite a section that does
176
- # not exist. The tree still advances above, so headings the guide
177
- # leaves unnumbered keep a positional index to be reachable by.
166
+ # A guide's own numbers address its sections; an index would drift
178
167
  if number:
179
168
  index = number
180
169
  headings.append(
@@ -203,10 +192,7 @@ def _slugify(text: str) -> str:
203
192
  return re.sub(r"[^a-z0-9]+", "-", text.lower()).strip("-")
204
193
 
205
194
 
206
- # Sections this long are worth warning about before one is fetched. Measured
207
- # over the shipped corpus, it marks the 4% that are expensive while leaving
208
- # the rest unannotated: a size on every line would read '0' on 59% of them,
209
- # which is noise in the one output whose job is to be scanned quickly.
195
+ # Marks the expensive 4% of the corpus; a size on every line would be noise
210
196
  LARGE_SECTION_WORDS = 1200
211
197
 
212
198
 
@@ -263,8 +249,7 @@ def format_outline(headings: Sequence[Heading], content: str = "") -> str:
263
249
  section = extract_section(content, headings, position)
264
250
  size = _format_size(len(section.split()))
265
251
 
266
- # The index already carries the guide's own number where it has one,
267
- # so printing the heading verbatim would show it twice.
252
+ # The index already carries the guide's number where it has one
268
253
  lines.append(f"{indent}{prefix}{heading.title}{size}")
269
254
 
270
255
  return "\n".join(lines)
@@ -281,8 +266,7 @@ def _matches_component(heading: Heading, component: str, exact: bool) -> bool:
281
266
  Returns:
282
267
  True if the component identifies the heading.
283
268
  """
284
- # Numbers are only ever compared in full; a substring of a number would
285
- # match unrelated sections.
269
+ # Numbers compare in full; a substring would match unrelated sections
286
270
  wanted = component.strip().rstrip(".")
287
271
  if wanted and wanted in {heading.index, heading.number}:
288
272
  return True
@@ -369,8 +353,7 @@ def find_headings(headings: Sequence[Heading], reference: str) -> list[int]:
369
353
  if not components:
370
354
  return []
371
355
 
372
- # Prefer whole matches; fall back to substrings only when nothing matches
373
- # in full, so 'Imports' does not also select 'Imports and Exports'.
356
+ # Whole matches first, so 'Imports' does not select 'Imports and Exports'
374
357
  for exact in (True, False):
375
358
  matches = [
376
359
  position
@@ -512,9 +495,7 @@ def find_mentions(
512
495
 
513
496
  lines = content.splitlines()
514
497
 
515
- # Only an indexed heading can be offered. The document title has no index
516
- # because it is the whole guide rather than a section within it, so
517
- # crediting the preamble to it would suggest reading everything.
498
+ # The title has no index, so crediting it would suggest reading everything
518
499
  sections = [
519
500
  (position, _section_bounds(lines, headings, position))
520
501
  for position in range(len(headings))
@@ -526,10 +507,7 @@ def find_mentions(
526
507
  if needle not in line.lower():
527
508
  continue
528
509
 
529
- # Bounds nest, so the last section still covering the line is the
530
- # innermost one that prints it. A section sheds the anchors of the
531
- # heading below it, and those fall to an ancestor rather than to the
532
- # section they merely trail.
510
+ # Bounds nest, so the last one covering a line is what prints it
533
511
  holders = [
534
512
  position
535
513
  for position, (start, end) in sections
@@ -577,8 +555,7 @@ def _echo_outline(content: str, language: str) -> None:
577
555
  example = _example_reference(headings)
578
556
  if example:
579
557
  count = sum(1 for heading in headings if heading.index)
580
- # stdout is block-buffered when redirected, so without this the hint
581
- # lands above the outline it is meant to follow
558
+ # Redirected stdout is block-buffered, so the hint would land first
582
559
  sys.stdout.flush()
583
560
  click.echo(
584
561
  f"# {count} sections · print one: "
@@ -656,8 +633,7 @@ def _select_section(content: str, reference: str, language: str) -> str:
656
633
  if not matches:
657
634
  _report_no_heading(content, headings, reference, language)
658
635
 
659
- # Reporting every candidate beats returning the first one silently, since
660
- # guides repeat headings ('Decision' appears under every Python rule).
636
+ # Guides repeat headings, so name every candidate rather than guess
661
637
  if len(matches) > 1:
662
638
  click.echo(
663
639
  f"Error: '{reference}' matches {len(matches)} headings in the "
@@ -1,20 +1,21 @@
1
1
  import json
2
+ from pathlib import Path
2
3
  import subprocess
3
4
  import tomllib
4
- from pathlib import Path
5
- from unittest.mock import MagicMock, call, patch
5
+ from unittest.mock import call
6
+ from unittest.mock import MagicMock
7
+ from unittest.mock import patch
6
8
 
7
- import pytest
8
9
  from click.testing import CliRunner
10
+ import pytest
9
11
 
10
- from readability.checking import CheckReport, check_paths
12
+ from readability.checking import check_paths
13
+ from readability.checking import CheckReport
11
14
  from readability.cli import cli
12
- from readability.tools import (
13
- TOOL_RUNNERS,
14
- _bundled_config,
15
- _get_tool_definitions,
16
- _has_project_config,
17
- )
15
+ from readability.tools import _bundled_config
16
+ from readability.tools import _get_tool_definitions
17
+ from readability.tools import _has_project_config
18
+ from readability.tools import TOOL_RUNNERS
18
19
 
19
20
 
20
21
  def _source_file(directory: Path, name: str) -> Path:
@@ -1035,6 +1036,14 @@ def test_bundled_default_configs_are_valid() -> None:
1035
1036
  assert ruff_config["line-length"] == 80
1036
1037
  assert ruff_config["lint"]["pydocstyle"]["convention"] == "google"
1037
1038
 
1039
+ # Import sorting mirrors isort's google profile
1040
+ assert ruff_config["lint"]["isort"] == {
1041
+ "force-single-line": True,
1042
+ "force-sort-within-sections": True,
1043
+ "single-line-exclusions": ["typing"],
1044
+ "order-by-type": False,
1045
+ }
1046
+
1038
1047
 
1039
1048
  @patch("readability.checking._check_path")
1040
1049
  def test_check_paths_aggregates_str_and_path_inputs(
@@ -1,20 +1,19 @@
1
1
  import os
2
2
  from pathlib import Path
3
- from unittest.mock import MagicMock, patch
3
+ from unittest.mock import MagicMock
4
+ from unittest.mock import patch
4
5
 
5
6
  import click
7
+ from click.testing import CliRunner
6
8
  import pytest
7
9
  import requests
8
- from click.testing import CliRunner
9
10
 
10
11
  from readability.cli import cli
11
- from readability.guide import (
12
- convert_to_markdown,
13
- get_guide,
14
- get_guide_content,
15
- get_guides_dir,
16
- get_local_path,
17
- )
12
+ from readability.guide import convert_to_markdown
13
+ from readability.guide import get_guide
14
+ from readability.guide import get_guide_content
15
+ from readability.guide import get_guides_dir
16
+ from readability.guide import get_local_path
18
17
 
19
18
 
20
19
  def test_get_guide_unsupported() -> None:
@@ -159,8 +158,7 @@ def test_sync_command(
159
158
  result = runner.invoke(cli, ["sync"])
160
159
 
161
160
  assert result.exit_code == 0
162
- # Progress is an outcome the caller asked for, so it is reported
163
- # regardless of log level rather than logged as narration.
161
+ # An asked-for outcome, so reported regardless of log level
164
162
  assert "Sync complete" in result.stderr
165
163
  # Check if at least one guide was "synced" (written to tmp_path)
166
164
  assert len(os.listdir(tmp_path)) > 0
@@ -1,23 +1,21 @@
1
1
  import logging
2
2
  import os
3
3
  from pathlib import Path
4
- from unittest.mock import MagicMock, patch
4
+ from unittest.mock import MagicMock
5
+ from unittest.mock import patch
5
6
 
6
7
  from click.testing import CliRunner
7
8
 
8
- from readability.cli import cli, main
9
- from readability.guide import (
10
- LANGUAGE_MAP,
11
- get_local_path,
12
- )
13
- from readability.outline import (
14
- _iter_heading_lines,
15
- _unique_reference,
16
- extract_section,
17
- find_headings,
18
- find_mentions,
19
- parse_headings,
20
- )
9
+ from readability.cli import cli
10
+ from readability.cli import main
11
+ from readability.guide import get_local_path
12
+ from readability.guide import LANGUAGE_MAP
13
+ from readability.outline import _iter_heading_lines
14
+ from readability.outline import _unique_reference
15
+ from readability.outline import extract_section
16
+ from readability.outline import find_headings
17
+ from readability.outline import find_mentions
18
+ from readability.outline import parse_headings
21
19
 
22
20
  NUMBERED_GUIDE = """# Sample Style Guide
23
21
 
@@ -456,10 +454,7 @@ def test_cli_section_heading_containing_an_angle_bracket(
456
454
  assert "Array body." in result.stdout
457
455
 
458
456
 
459
- # The heading scanner is deliberately not a Markdown parser (see the note on
460
- # _iter_heading_lines). These tests are the evidence for that decision: the
461
- # scope it covers, the constructs it rejects, and its behaviour over every
462
- # guide actually shipped. A failure here means the scope has been outgrown.
457
+ # Evidence the scanner need not be a Markdown parser; a failure means it is
463
458
 
464
459
 
465
460
  def test_heading_scanner_rejects_non_headings() -> None:
@@ -551,8 +546,7 @@ def test_every_shipped_guide_parses_into_unique_sections() -> None:
551
546
  f"{language}: duplicate positional indices"
552
547
  )
553
548
 
554
- # A heading taken from inside a fence would carry a comment marker
555
- # or a shebang, neither of which appears in a real guide heading.
549
+ # A fenced line would carry a comment marker or a shebang
556
550
  for heading in headings:
557
551
  assert not heading.title.startswith("!"), (
558
552
  f"{language}: shebang parsed as heading: {heading.title!r}"
@@ -575,9 +569,7 @@ def test_every_shipped_guide_heading_is_addressable() -> None:
575
569
  )
576
570
  assert titles[0] is headings[0], f"{language}: title is not first"
577
571
 
578
- # An index alone is not always enough: where a guide prints its own
579
- # numbers those drift from the tree, so one string can name two
580
- # headings. What must always hold is that some reference resolves.
572
+ # A guide's own numbers drift, so only 'some reference resolves' holds
581
573
  for position, heading in enumerate(headings):
582
574
  reference = _unique_reference(headings, position).strip('"')
583
575
  matches = find_headings(headings, reference)
@@ -587,9 +579,7 @@ def test_every_shipped_guide_heading_is_addressable() -> None:
587
579
  )
588
580
 
589
581
 
590
- # Words the corpus uses often enough to exercise many sections at once.
591
- # 'truefalse' appears only inside pyguide's anchors, which is the shape that
592
- # used to be credited to whichever section happened to precede them.
582
+ # Common words, plus 'truefalse' which appears only inside pyguide's anchors
593
583
  MENTION_PROBES = (
594
584
  "truefalse",
595
585
  "indent",
@@ -1,8 +1,10 @@
1
1
  from importlib.resources import files
2
2
 
3
3
  import readability
4
- from readability.checking import CheckReport, check_paths
5
- from readability.cli import cli, main
4
+ from readability.checking import check_paths
5
+ from readability.checking import CheckReport
6
+ from readability.cli import cli
7
+ from readability.cli import main
6
8
 
7
9
 
8
10
  def test_public_modules_are_importable() -> None:
@@ -194,7 +194,7 @@ wheels = [
194
194
 
195
195
  [[package]]
196
196
  name = "readability-cli"
197
- version = "0.9.0"
197
+ version = "0.10.1"
198
198
  source = { editable = "." }
199
199
  dependencies = [
200
200
  { name = "beautifulsoup4" },
@@ -1,13 +1,13 @@
1
1
  """Build executable plans for readability's canonical tools."""
2
2
 
3
- import logging
4
- import os
5
- import shutil
6
- import tomllib
7
3
  from collections.abc import Sequence
8
4
  from dataclasses import dataclass
9
5
  from importlib.resources import files
6
+ import logging
7
+ import os
10
8
  from pathlib import Path
9
+ import shutil
10
+ import tomllib
11
11
 
12
12
  logger = logging.getLogger("readability")
13
13