docwrap 0.1.0__py3-none-any.whl

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 (58) hide show
  1. docwrap/__init__.py +59 -0
  2. docwrap/__main__.py +8 -0
  3. docwrap/_canonical.py +66 -0
  4. docwrap/_classify.py +56 -0
  5. docwrap/_cli.py +1284 -0
  6. docwrap/_color.py +135 -0
  7. docwrap/_config.py +615 -0
  8. docwrap/_convert.py +1324 -0
  9. docwrap/_core/__init__.py +27 -0
  10. docwrap/_core/_codeblock.py +214 -0
  11. docwrap/_core/_discover.py +466 -0
  12. docwrap/_core/_escape.py +204 -0
  13. docwrap/_core/_incremental.py +402 -0
  14. docwrap/_core/_normalize.py +306 -0
  15. docwrap/_core/_parse.py +594 -0
  16. docwrap/_core/_process.py +826 -0
  17. docwrap/_core/_wrap.py +1714 -0
  18. docwrap/_detect.py +98 -0
  19. docwrap/_detector.py +166 -0
  20. docwrap/_display/__init__.py +17 -0
  21. docwrap/_display/_diff.py +62 -0
  22. docwrap/_display/_json.py +168 -0
  23. docwrap/_display/_print.py +93 -0
  24. docwrap/_display/_recommend.py +165 -0
  25. docwrap/_display/_skips.py +17 -0
  26. docwrap/_display/_stats.py +1075 -0
  27. docwrap/_display/_summary.py +213 -0
  28. docwrap/_display/_text.py +17 -0
  29. docwrap/_downstream.py +181 -0
  30. docwrap/_exceptions.py +52 -0
  31. docwrap/_files.py +304 -0
  32. docwrap/_git.py +764 -0
  33. docwrap/_git_utils.py +76 -0
  34. docwrap/_grammar.py +800 -0
  35. docwrap/_hook.py +1001 -0
  36. docwrap/_hosts/__init__.py +50 -0
  37. docwrap/_shell.py +73 -0
  38. docwrap/_shellparse.py +643 -0
  39. docwrap/_stats.py +529 -0
  40. docwrap/_styles/__init__.py +335 -0
  41. docwrap/_styles/_google.py +423 -0
  42. docwrap/_styles/_numpy.py +292 -0
  43. docwrap/_styles/_sphinx.py +324 -0
  44. docwrap/_types.py +423 -0
  45. docwrap/_validate.py +62 -0
  46. docwrap/hooks/__init__.py +245 -0
  47. docwrap/py.typed +0 -0
  48. docwrap-0.1.0.dist-info/METADATA +126 -0
  49. docwrap-0.1.0.dist-info/RECORD +58 -0
  50. docwrap-0.1.0.dist-info/WHEEL +4 -0
  51. docwrap-0.1.0.dist-info/entry_points.txt +7 -0
  52. docwrap-0.1.0.dist-info/licenses/LICENSE +21 -0
  53. plugins/agy/_docwrap/__init__.py +1 -0
  54. plugins/agy/_docwrap/_adapter.py +122 -0
  55. plugins/claude/_docwrap/__init__.py +1 -0
  56. plugins/claude/_docwrap/_adapter.py +106 -0
  57. plugins/codex/_docwrap/__init__.py +1 -0
  58. plugins/codex/_docwrap/_adapter.py +117 -0
docwrap/__init__.py ADDED
@@ -0,0 +1,59 @@
1
+ """Public facade for docwrap's supported library API.
2
+
3
+ Example:
4
+ >>> import docwrap
5
+ >>> docwrap.wrap_source('def f(): pass')
6
+ 'def f(): pass'
7
+ """
8
+
9
+ from docwrap._config import clear_config_cache, resolve_config
10
+ from docwrap._core import check, wrap_file_report, wrap_source, wrap_source_report
11
+ from docwrap._exceptions import (
12
+ DocwrapConfigWarning,
13
+ DocwrapSkipWarning,
14
+ InvalidLineLengthError,
15
+ UnknownStyleError,
16
+ )
17
+ from docwrap._styles import get_styles
18
+ from docwrap._types import (
19
+ DEFAULT_LINE_LENGTH,
20
+ DetailLevel,
21
+ DocstringChange,
22
+ DocstringSkip,
23
+ DocwrapConfig,
24
+ FillStyle,
25
+ ReflowMode,
26
+ SkipCode,
27
+ StyleName,
28
+ SummaryStart,
29
+ WrapCheckResult,
30
+ WrapReport,
31
+ WrapStatus,
32
+ )
33
+
34
+ __all__ = [
35
+ 'DEFAULT_LINE_LENGTH',
36
+ 'DetailLevel',
37
+ 'DocstringChange',
38
+ 'DocstringSkip',
39
+ 'DocwrapConfig',
40
+ 'DocwrapConfigWarning',
41
+ 'DocwrapSkipWarning',
42
+ 'FillStyle',
43
+ 'InvalidLineLengthError',
44
+ 'ReflowMode',
45
+ 'SkipCode',
46
+ 'StyleName',
47
+ 'SummaryStart',
48
+ 'UnknownStyleError',
49
+ 'WrapCheckResult',
50
+ 'WrapReport',
51
+ 'WrapStatus',
52
+ 'check',
53
+ 'clear_config_cache',
54
+ 'get_styles',
55
+ 'resolve_config',
56
+ 'wrap_file_report',
57
+ 'wrap_source',
58
+ 'wrap_source_report',
59
+ ]
docwrap/__main__.py ADDED
@@ -0,0 +1,8 @@
1
+ """Module entry point for `python -m docwrap`."""
2
+
3
+ import sys
4
+
5
+ from docwrap._cli import main
6
+
7
+ if __name__ == '__main__':
8
+ sys.exit(main())
docwrap/_canonical.py ADDED
@@ -0,0 +1,66 @@
1
+ """Canonical section registry for docstring roles."""
2
+
3
+ from dataclasses import dataclass
4
+
5
+ from docwrap._types import CanonicalRole
6
+
7
+
8
+ @dataclass(frozen=True, slots=True)
9
+ class CanonicalSection:
10
+ """Registry entry whose tuple position determines canonical section order.
11
+
12
+ The entry's position in `CANONICAL_SECTIONS` is the ordering authority.
13
+ Sphinx field mappings and target support belong to the Sphinx style.
14
+
15
+ Attributes:
16
+ role: Canonical docstring role represented by this entry.
17
+ google_header: Google header label, or `None` when unavailable.
18
+ numpy_header: NumPy header label, or `None` when unavailable.
19
+ return_like: Whether the role uses return-like entry handling.
20
+ """
21
+
22
+ role: CanonicalRole
23
+ google_header: str | None = None
24
+ numpy_header: str | None = None
25
+ return_like: bool = False
26
+
27
+
28
+ CANONICAL_SECTIONS: tuple[CanonicalSection, ...] = (
29
+ CanonicalSection('param', google_header='Args', numpy_header='Parameters'),
30
+ CanonicalSection('keyword_param', google_header='Keyword Args'),
31
+ CanonicalSection('other_param', numpy_header='Other Parameters'),
32
+ CanonicalSection(
33
+ 'returns',
34
+ google_header='Returns',
35
+ numpy_header='Returns',
36
+ return_like=True,
37
+ ),
38
+ CanonicalSection(
39
+ 'yields',
40
+ google_header='Yields',
41
+ numpy_header='Yields',
42
+ return_like=True,
43
+ ),
44
+ CanonicalSection('raises', google_header='Raises', numpy_header='Raises'),
45
+ CanonicalSection('warns', google_header='Warns', numpy_header='Warns'),
46
+ CanonicalSection(
47
+ 'attributes',
48
+ google_header='Attributes',
49
+ numpy_header='Attributes',
50
+ ),
51
+ CanonicalSection('methods', google_header='Methods', numpy_header='Methods'),
52
+ CanonicalSection('see_also', google_header='See Also', numpy_header='See Also'),
53
+ CanonicalSection('notes', google_header='Notes', numpy_header='Notes'),
54
+ CanonicalSection('references', google_header='References', numpy_header='References'),
55
+ CanonicalSection('examples', google_header='Examples', numpy_header='Examples'),
56
+ CanonicalSection('todo', google_header='Todo', numpy_header='Todo'),
57
+ CanonicalSection('warnings', google_header='Warnings', numpy_header='Warnings'),
58
+ )
59
+
60
+ CANONICAL_ORDER: tuple[CanonicalRole, ...] = tuple(section.role for section in CANONICAL_SECTIONS)
61
+
62
+ CANONICAL_ORDER_SET: frozenset[CanonicalRole] = frozenset(CANONICAL_ORDER)
63
+
64
+ RETURN_LIKE_ROLES: frozenset[CanonicalRole] = frozenset(
65
+ s.role for s in CANONICAL_SECTIONS if s.return_like
66
+ )
docwrap/_classify.py ADDED
@@ -0,0 +1,56 @@
1
+ """Classify a pre-tool shell command into one of three outcomes."""
2
+
3
+ from dataclasses import dataclass
4
+ from typing import Literal
5
+
6
+ from docwrap._color import visible_controls
7
+ from docwrap._detector import detect_commit
8
+ from docwrap._grammar import CommitPlan, NoCommit, Rejection, classify_grammar
9
+ from docwrap._shellparse import parse_command
10
+
11
+ type _OUTCOME = Literal['unrelated', 'supported', 'unsupported']
12
+
13
+ _REASON_PREFIX = 'docwrap: unsupported commit command'
14
+
15
+
16
+ @dataclass(frozen=True, slots=True)
17
+ class Classification:
18
+ """Outcome of classifying one command.
19
+
20
+ Args:
21
+ outcome: `unrelated`, `supported`, or `unsupported`.
22
+ plan: Resolved commit plan, or `NoCommit`, for a supported command.
23
+ reason: Deny reason for an unsupported command.
24
+ """
25
+
26
+ outcome: _OUTCOME
27
+ plan: CommitPlan | NoCommit | None = None
28
+ reason: str | None = None
29
+
30
+
31
+ def _deny_reason(rejection: Rejection) -> str:
32
+ """Render a sanitized deny reason for a rejected command."""
33
+ return visible_controls(f'{_REASON_PREFIX}: {rejection.element}; {rejection.hint}')
34
+
35
+
36
+ def classify_command(text: str, command_cwd: str | None) -> Classification:
37
+ """Classify a shell command as unrelated, supported, or unsupported.
38
+
39
+ Args:
40
+ text: Shell command text from the hook payload.
41
+ command_cwd: Absolute directory the command executes in, or `None` when
42
+ unknown.
43
+
44
+ Returns:
45
+ The classification. The grammar decides first; a rejected command is
46
+ unsupported when the detector finds a commit and unrelated otherwise.
47
+ A committing command with an unknown directory and no absolute route is
48
+ unsupported.
49
+ """
50
+ command = parse_command(text)
51
+ result = classify_grammar(command, command_cwd)
52
+ if isinstance(result, Rejection):
53
+ if detect_commit(command):
54
+ return Classification('unsupported', reason=_deny_reason(result))
55
+ return Classification('unrelated')
56
+ return Classification('supported', plan=result)