rstobj 1.2.1__tar.gz → 2.0.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 (98) hide show
  1. rstobj-2.0.1/AUTHORS.rst +15 -0
  2. {rstobj-1.2.1 → rstobj-2.0.1}/LICENSE.txt +2 -2
  3. {rstobj-1.2.1/rstobj.egg-info → rstobj-2.0.1}/PKG-INFO +72 -43
  4. {rstobj-1.2.1 → rstobj-2.0.1}/README.rst +31 -20
  5. rstobj-2.0.1/pyproject.toml +131 -0
  6. rstobj-2.0.1/rstobj/__init__.py +5 -0
  7. rstobj-2.0.1/rstobj/api.py +4 -0
  8. rstobj-2.0.1/rstobj/base.py +139 -0
  9. rstobj-2.0.1/rstobj/directives/__init__.py +5 -0
  10. rstobj-2.0.1/rstobj/directives/api.py +26 -0
  11. rstobj-2.0.1/rstobj/directives/base.py +22 -0
  12. {rstobj-1.2.1 → rstobj-2.0.1}/rstobj/directives/codeblock.py +31 -31
  13. {rstobj-1.2.1 → rstobj-2.0.1}/rstobj/directives/image.py +26 -31
  14. rstobj-2.0.1/rstobj/directives/miscellaneous.py +47 -0
  15. {rstobj-1.2.1 → rstobj-2.0.1}/rstobj/directives/table.py +17 -14
  16. {rstobj-1.2.1 → rstobj-2.0.1}/rstobj/directives/toc.py +22 -23
  17. rstobj-2.0.1/rstobj/markup/__init__.py +5 -0
  18. rstobj-2.0.1/rstobj/markup/api.py +16 -0
  19. {rstobj-1.2.1 → rstobj-2.0.1}/rstobj/markup/bullet_list.py +6 -3
  20. {rstobj-1.2.1 → rstobj-2.0.1}/rstobj/markup/enum_list.py +8 -4
  21. {rstobj-1.2.1 → rstobj-2.0.1}/rstobj/markup/header.py +58 -53
  22. {rstobj-1.2.1 → rstobj-2.0.1}/rstobj/markup/hyperlink.py +11 -7
  23. rstobj-2.0.1/rstobj/paths.py +60 -0
  24. rstobj-2.0.1/rstobj/templates/__init__.py +12 -0
  25. rstobj-2.0.1/rstobj/templates/rstobj.directives.base.Directive.rst +8 -0
  26. rstobj-2.0.1/rstobj/templates/rstobj.directives.codeblock.CodeBlockBase.rst +9 -0
  27. rstobj-2.0.1/rstobj/templates/rstobj.directives.image.Image.rst +18 -0
  28. {rstobj-1.2.1 → rstobj-2.0.1}/rstobj/templates/rstobj.directives.miscellaneous.Include.rst +10 -10
  29. rstobj-2.0.1/rstobj/templates/rstobj.directives.table.ListTable.rst +29 -0
  30. {rstobj-1.2.1 → rstobj-2.0.1}/rstobj/templates/rstobj.directives.toc.TableOfContent.rst +3 -3
  31. {rstobj-1.2.1 → rstobj-2.0.1}/rstobj/templates/rstobj.markup.bullet_list.BulletList.rst +1 -1
  32. rstobj-2.0.1/rstobj/templates/rstobj.markup.enum_list.EnumList.rst +4 -0
  33. rstobj-2.0.1/rstobj/templates/rstobj.markup.header.Header.rst +5 -0
  34. {rstobj-1.2.1/rstobj/docs → rstobj-2.0.1/rstobj/vendor}/__init__.py +0 -1
  35. rstobj-2.0.1/rstobj/vendor/pytest_cov_helper.py +148 -0
  36. {rstobj-1.2.1 → rstobj-2.0.1/rstobj.egg-info}/PKG-INFO +72 -43
  37. rstobj-2.0.1/rstobj.egg-info/SOURCES.txt +47 -0
  38. rstobj-2.0.1/rstobj.egg-info/requires.txt +25 -0
  39. rstobj-2.0.1/tests/test_api.py +19 -0
  40. rstobj-2.0.1/tests/test_base.py +85 -0
  41. rstobj-2.0.1/tests/test_option.py +52 -0
  42. rstobj-1.2.1/AUTHORS.rst +0 -14
  43. rstobj-1.2.1/MANIFEST.in +0 -10
  44. rstobj-1.2.1/release-history.rst +0 -97
  45. rstobj-1.2.1/requirements-dev.txt +0 -4
  46. rstobj-1.2.1/requirements-doc.txt +0 -15
  47. rstobj-1.2.1/requirements-test.txt +0 -3
  48. rstobj-1.2.1/requirements.txt +0 -4
  49. rstobj-1.2.1/rstobj/__init__.py +0 -22
  50. rstobj-1.2.1/rstobj/_version.py +0 -4
  51. rstobj-1.2.1/rstobj/base.py +0 -103
  52. rstobj-1.2.1/rstobj/demo.py +0 -107
  53. rstobj-1.2.1/rstobj/directives/__init__.py +0 -11
  54. rstobj-1.2.1/rstobj/directives/base.py +0 -16
  55. rstobj-1.2.1/rstobj/directives/miscellaneous.py +0 -43
  56. rstobj-1.2.1/rstobj/markup/__init__.py +0 -13
  57. rstobj-1.2.1/rstobj/templates/__init__.py +0 -6
  58. rstobj-1.2.1/rstobj/templates/rstobj.directives.base.Directive.rst +0 -8
  59. rstobj-1.2.1/rstobj/templates/rstobj.directives.codeblock.CodeBlockBase.rst +0 -3
  60. rstobj-1.2.1/rstobj/templates/rstobj.directives.image.Image.rst +0 -15
  61. rstobj-1.2.1/rstobj/templates/rstobj.directives.table.ListTable.rst +0 -28
  62. rstobj-1.2.1/rstobj/templates/rstobj.markup.enum_list.EnumList.rst +0 -3
  63. rstobj-1.2.1/rstobj/templates/rstobj.markup.header.Header.rst +0 -5
  64. rstobj-1.2.1/rstobj/tests/__init__.py +0 -23
  65. rstobj-1.2.1/rstobj/tests/rstobj.directives.codeblock.Code.render-indent.rst +0 -4
  66. rstobj-1.2.1/rstobj/tests/rstobj.directives.codeblock.CodeBlock.render.rst +0 -6
  67. rstobj-1.2.1/rstobj/tests/rstobj.directives.codeblock.CodeBlockEmpty.render-indent.rst +0 -6
  68. rstobj-1.2.1/rstobj/tests/rstobj.directives.codeblock.CodeBlockEmpty.render.rst +0 -6
  69. rstobj-1.2.1/rstobj/tests/rstobj.directives.codeblock.CodeBlockPython.render.rst +0 -6
  70. rstobj-1.2.1/rstobj/tests/rstobj.directives.image.Image.render-indent.rst +0 -1
  71. rstobj-1.2.1/rstobj/tests/rstobj.directives.image.Image.uri-only.rst +0 -1
  72. rstobj-1.2.1/rstobj/tests/rstobj.directives.image.Image.with-everything.rst +0 -5
  73. rstobj-1.2.1/rstobj/tests/rstobj.directives.miscellaneous.Include.render.rst +0 -1
  74. rstobj-1.2.1/rstobj/tests/rstobj.directives.table.ListTable.with-codeblock-indent.rst +0 -18
  75. rstobj-1.2.1/rstobj/tests/rstobj.directives.table.ListTable.with-codeblock.rst +0 -18
  76. rstobj-1.2.1/rstobj/tests/rstobj.directives.table.ListTable.with-header.rst +0 -10
  77. rstobj-1.2.1/rstobj/tests/rstobj.directives.table.ListTable.with-index.rst +0 -10
  78. rstobj-1.2.1/rstobj/tests/rstobj.directives.table.ListTable.with-widths.rst +0 -11
  79. rstobj-1.2.1/rstobj/tests/rstobj.directives.toc.TableOfContent.basic.rst +0 -1
  80. rstobj-1.2.1/rstobj/tests/rstobj.directives.toc.TableOfContent.rich-options.rst +0 -4
  81. rstobj-1.2.1/rstobj/tests/rstobj.markup.bullet_list.BulletList.render.rst +0 -3
  82. rstobj-1.2.1/rstobj/tests/rstobj.markup.enum_list.EnumList.render.rst +0 -3
  83. rstobj-1.2.1/rstobj/tests/rstobj.markup.header.Header.has-ref_key-auto-bar.rst +0 -4
  84. rstobj-1.2.1/rstobj/tests/rstobj.markup.header.Header.no-ref_key-auto-bar.rst +0 -2
  85. rstobj-1.2.1/rstobj/tests/rstobj.markup.header.Header.no-ref_key.rst +0 -2
  86. rstobj-1.2.1/rstobj/tests/rstobj.markup.header.Header2.auto-ref_key.rst +0 -4
  87. rstobj-1.2.1/rstobj/tests/rstobj.markup.header.Header2.has-ref_key-auto-bar.rst +0 -4
  88. rstobj-1.2.1/rstobj.egg-info/SOURCES.txt +0 -71
  89. rstobj-1.2.1/rstobj.egg-info/requires.txt +0 -17
  90. rstobj-1.2.1/setup.py +0 -245
  91. {rstobj-1.2.1 → rstobj-2.0.1}/rstobj/option.py +0 -0
  92. {rstobj-1.2.1 → rstobj-2.0.1}/rstobj/templates/rstobj.directives.codeblock.Code.rst +0 -0
  93. {rstobj-1.2.1 → rstobj-2.0.1}/rstobj/templates/rstobj.directives.codeblock.CodeBlockEmpty.rst +0 -0
  94. {rstobj-1.2.1 → rstobj-2.0.1}/rstobj/templates/rstobj.markup.hyperlink.Reference.rst +0 -0
  95. {rstobj-1.2.1 → rstobj-2.0.1}/rstobj/templates/rstobj.markup.hyperlink.URI.rst +0 -0
  96. {rstobj-1.2.1 → rstobj-2.0.1}/rstobj.egg-info/dependency_links.txt +0 -0
  97. {rstobj-1.2.1 → rstobj-2.0.1}/rstobj.egg-info/top_level.txt +0 -0
  98. {rstobj-1.2.1 → rstobj-2.0.1}/setup.cfg +0 -0
@@ -0,0 +1,15 @@
1
+ .. _about_author:
2
+
3
+ About the Author
4
+ ------------------------------------------------------------------------------
5
+ ::
6
+
7
+ (\ (\
8
+ ( -.-)o
9
+ o_(")(")
10
+
11
+ **Sanhe Hu** is a seasoned software engineer with a deep passion for Python development since 2010. As an author and maintainer of `150+ open-source Python projects <https://pypi.org/user/machugwu/>`_, with over `15 million monthly downloads <https://github.com/MacHu-GWU>`_, I bring a wealth of experience to the table. As a Senior Solution Architect and Subject Matter Expert in AI, Data, Amazon Web Services, Cloud Engineering, DevOps, I thrive on helping clients with platform design, enterprise architecture, and strategic roadmaps.
12
+
13
+ Talk is cheap, show me the code:
14
+
15
+ - My Github: https://github.com/MacHu-GWU
@@ -1,6 +1,6 @@
1
- The MIT License (MIT)
1
+ MIT License
2
2
 
3
- Copyright 2022 Sanhe Hu <https://github.com/MacHu-GWU/rstobj-project>
3
+ Copyright (c) 2026 Sanhe Hu <husanhe@email.com>
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
@@ -1,45 +1,63 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.4
2
2
  Name: rstobj
3
- Version: 1.2.1
4
- Summary: Construct RestructuredText markup and directives from Python Code.
5
- Home-page: https://github.com/MacHu-GWU/rstobj-project
6
- Download-URL: https://pypi.python.org/pypi/rstobj/1.2.1#downloads
7
- Author: Sanhe Hu
8
- Author-email: husanhe@gmail.com
9
- Maintainer: Sanhe Hu
10
- Maintainer-email: husanhe@gmail.com
11
- License: MIT
12
- Platform: Windows
13
- Platform: MacOS
14
- Platform: Unix
15
- Classifier: Development Status :: 5 - Production/Stable
3
+ Version: 2.0.1
4
+ Summary: Construct reStructuredText markup and directives from Python code.
5
+ Author-email: Sanhe Hu <husanhe@gmail.com>
6
+ Maintainer-email: Sanhe Hu <husanhe@gmail.com>
7
+ License-Expression: MIT
8
+ Project-URL: Homepage, https://github.com/MacHu-GWU/rstobj-project
9
+ Project-URL: Documentation, https://rstobj.readthedocs.io/en/latest/
10
+ Project-URL: Repository, https://github.com/MacHu-GWU/rstobj-project
11
+ Project-URL: Issues, https://github.com/MacHu-GWU/rstobj-project/issues
12
+ Project-URL: Changelog, https://github.com/MacHu-GWU/rstobj-project/blob/main/release-history.rst
13
+ Project-URL: Download, https://pypi.org/pypi/rstobj#files
14
+ Classifier: Development Status :: 4 - Beta
16
15
  Classifier: Intended Audience :: Developers
17
- Classifier: License :: OSI Approved :: MIT License
18
16
  Classifier: Natural Language :: English
19
17
  Classifier: Operating System :: Microsoft :: Windows
20
18
  Classifier: Operating System :: MacOS
21
19
  Classifier: Operating System :: Unix
22
- Classifier: Programming Language :: Python
23
- Classifier: Programming Language :: Python :: 3.6
24
- Classifier: Programming Language :: Python :: 3.7
25
- Classifier: Programming Language :: Python :: 3.8
26
- Classifier: Programming Language :: Python :: 3.9
27
- Classifier: Programming Language :: Python :: 3.10
28
- Classifier: Programming Language :: Python :: 3 :: Only
29
- Provides-Extra: tests
30
- Provides-Extra: docs
20
+ Classifier: Programming Language :: Python :: 3
21
+ Classifier: Programming Language :: Python :: 3.11
22
+ Classifier: Programming Language :: Python :: 3.12
23
+ Classifier: Programming Language :: Python :: 3.13
24
+ Classifier: Programming Language :: Python :: 3.14
25
+ Requires-Python: <4.0,>=3.11
26
+ Description-Content-Type: text/x-rst
31
27
  License-File: LICENSE.txt
32
28
  License-File: AUTHORS.rst
29
+ Requires-Dist: jinja2<4.0.0,>=3.1.0
30
+ Provides-Extra: dev
31
+ Requires-Dist: rich<15.0.0,>=14.3.4; extra == "dev"
32
+ Provides-Extra: test
33
+ Requires-Dist: pytest<10.0.0,>=9.1.1; extra == "test"
34
+ Requires-Dist: pytest-cov<8.0.0,>=7.1.0; extra == "test"
35
+ Requires-Dist: docutils<1.0.0,>=0.21.2; extra == "test"
36
+ Provides-Extra: doc
37
+ Requires-Dist: Sphinx<9.0.0,>=8.2.3; extra == "doc"
38
+ Requires-Dist: sphinx-copybutton<1.0.0,>=0.5.2; extra == "doc"
39
+ Requires-Dist: sphinx-design<1.0.0,>=0.7.0; extra == "doc"
40
+ Requires-Dist: sphinx-jinja<3.0.0,>=2.0.2; extra == "doc"
41
+ Requires-Dist: furo==2025.12.19; extra == "doc"
42
+ Requires-Dist: pygments<3.0.0,>=2.18.0; extra == "doc"
43
+ Requires-Dist: ipython<8.19.0,>=8.18.1; extra == "doc"
44
+ Requires-Dist: ipykernel<8.0.0,>=7.3.0; extra == "doc"
45
+ Requires-Dist: nbsphinx<1.0.0,>=0.9.8; extra == "doc"
46
+ Requires-Dist: docfly<4.0.0,>=3.0.3; extra == "doc"
47
+ Provides-Extra: mise
48
+ Requires-Dist: PyGithub<3.0.0,>=2.8.0; extra == "mise"
49
+ Requires-Dist: httpx2<3.0.0,>=2.13.1; extra == "mise"
50
+ Dynamic: license-file
33
51
 
34
52
 
35
53
  .. image:: https://readthedocs.org/projects/rstobj/badge/?version=latest
36
- :target: https://rstobj.readthedocs.io/index.html
54
+ :target: https://rstobj.readthedocs.io/en/latest/
37
55
  :alt: Documentation Status
38
56
 
39
- .. image:: https://github.com/MacHu-GWU/rstobj-project/workflows/CI/badge.svg
57
+ .. image:: https://github.com/MacHu-GWU/rstobj-project/actions/workflows/main.yml/badge.svg
40
58
  :target: https://github.com/MacHu-GWU/rstobj-project/actions?query=workflow:CI
41
59
 
42
- .. image:: https://codecov.io/gh/MacHu-GWU/rstobj-project/branch/master/graph/badge.svg
60
+ .. image:: https://codecov.io/gh/MacHu-GWU/rstobj-project/branch/main/graph/badge.svg
43
61
  :target: https://codecov.io/gh/MacHu-GWU/rstobj-project
44
62
 
45
63
  .. image:: https://img.shields.io/pypi/v/rstobj.svg
@@ -51,20 +69,16 @@ License-File: AUTHORS.rst
51
69
  .. image:: https://img.shields.io/pypi/pyversions/rstobj.svg
52
70
  :target: https://pypi.python.org/pypi/rstobj
53
71
 
54
- .. image:: https://img.shields.io/badge/STAR_Me_on_GitHub!--None.svg?style=social
72
+ .. image:: https://img.shields.io/badge/✍️_Release_History!--None.svg?style=social&logo=github
73
+ :target: https://github.com/MacHu-GWU/rstobj-project/blob/main/release-history.rst
74
+
75
+ .. image:: https://img.shields.io/badge/⭐_Star_me_on_GitHub!--None.svg?style=social&logo=github
55
76
  :target: https://github.com/MacHu-GWU/rstobj-project
56
77
 
57
78
  ------
58
79
 
59
-
60
- .. image:: https://img.shields.io/badge/Link-Document-blue.svg
61
- :target: https://rstobj.readthedocs.io/index.html
62
-
63
80
  .. image:: https://img.shields.io/badge/Link-API-blue.svg
64
- :target: https://rstobj.readthedocs.io/py-modindex.html
65
-
66
- .. image:: https://img.shields.io/badge/Link-Source_Code-blue.svg
67
- :target: https://rstobj.readthedocs.io/py-modindex.html
81
+ :target: https://rstobj.readthedocs.io/en/latest/py-modindex.html
68
82
 
69
83
  .. image:: https://img.shields.io/badge/Link-Install-blue.svg
70
84
  :target: `install`_
@@ -84,6 +98,8 @@ License-File: AUTHORS.rst
84
98
 
85
99
  Welcome to ``rstobj`` Documentation
86
100
  ==============================================================================
101
+ .. image:: https://rstobj.readthedocs.io/en/latest/_static/rstobj-logo.png
102
+ :target: https://rstobj.readthedocs.io/en/latest/
87
103
 
88
104
  ``rstobj`` is a library that construct Restructured Text markup or directives from Python Code. ``rstobj`` is based on ``jinja2``.
89
105
 
@@ -106,23 +122,21 @@ I have a `Blog Post <https://github.com/MacHu-GWU/Tech-Blog/issues/6>`_ to share
106
122
 
107
123
  .. code-block:: python
108
124
 
109
- import rstobj # or from rstobj import *
125
+ import rstobj.api as rstobj
110
126
 
111
127
  header = rstobj.markup.Header(title="Section1", header_level=1, auto_label=True)
112
- rst_header = header.render()
113
- print(rst_header)
128
+ print(header.render())
114
129
 
115
130
  ltable = rstobj.directives.ListTable(
116
131
  data=[["id", "name"], [1, "Alice"], [2, "Bob"]],
117
132
  title="Users",
118
133
  header=True,
119
134
  )
120
- rst = ltable.render()
121
- print(rst_ltable)
135
+ print(ltable.render())
122
136
 
123
137
  Output::
124
138
 
125
- .. _section1:
139
+ .. _Section1:
126
140
 
127
141
  Section1
128
142
  ========
@@ -138,7 +152,9 @@ Output::
138
152
  * - 2
139
153
  - Bob
140
154
 
141
- I recommend to use this in your jinja2 template, content of ``outut.rst``::
155
+ See the `Rendering Gallery <https://rstobj.readthedocs.io/en/latest/01-Rendering-Gallery/index.html>`_ for every supported markup and directive, with its Python code, its output, and how it renders.
156
+
157
+ I recommend to use this in your jinja2 template, content of ``output.rst``::
142
158
 
143
159
  {{ header.render() }}
144
160
  {{ ltable.render() }}
@@ -185,3 +201,16 @@ To upgrade to latest version:
185
201
  .. code-block:: console
186
202
 
187
203
  $ pip install --upgrade rstobj
204
+
205
+ .. _use-with-ai-coding-agents:
206
+
207
+ Use with AI Coding Agents
208
+ ------------------------------------------------------------------------------
209
+
210
+ This repo ships an `Agent Skill <https://code.claude.com/docs/en/skills>`_ that documents the public API of ``rstobj``, so an AI coding agent such as Claude Code can use the library without reading its source. It lives in `.claude/skills/pypi-rstobj <https://github.com/MacHu-GWU/rstobj-project/tree/main/.claude/skills/pypi-rstobj>`_. To use it in your project, copy it into your project's ``.claude/skills/`` folder. Run this from your project's root:
211
+
212
+ .. code-block:: console
213
+
214
+ $ git clone --depth 1 https://github.com/MacHu-GWU/rstobj-project.git /tmp/rstobj-project
215
+ $ mkdir -p .claude/skills
216
+ $ cp -R /tmp/rstobj-project/.claude/skills/pypi-rstobj .claude/skills/
@@ -1,12 +1,12 @@
1
1
 
2
2
  .. image:: https://readthedocs.org/projects/rstobj/badge/?version=latest
3
- :target: https://rstobj.readthedocs.io/index.html
3
+ :target: https://rstobj.readthedocs.io/en/latest/
4
4
  :alt: Documentation Status
5
5
 
6
- .. image:: https://github.com/MacHu-GWU/rstobj-project/workflows/CI/badge.svg
6
+ .. image:: https://github.com/MacHu-GWU/rstobj-project/actions/workflows/main.yml/badge.svg
7
7
  :target: https://github.com/MacHu-GWU/rstobj-project/actions?query=workflow:CI
8
8
 
9
- .. image:: https://codecov.io/gh/MacHu-GWU/rstobj-project/branch/master/graph/badge.svg
9
+ .. image:: https://codecov.io/gh/MacHu-GWU/rstobj-project/branch/main/graph/badge.svg
10
10
  :target: https://codecov.io/gh/MacHu-GWU/rstobj-project
11
11
 
12
12
  .. image:: https://img.shields.io/pypi/v/rstobj.svg
@@ -18,20 +18,16 @@
18
18
  .. image:: https://img.shields.io/pypi/pyversions/rstobj.svg
19
19
  :target: https://pypi.python.org/pypi/rstobj
20
20
 
21
- .. image:: https://img.shields.io/badge/STAR_Me_on_GitHub!--None.svg?style=social
21
+ .. image:: https://img.shields.io/badge/✍️_Release_History!--None.svg?style=social&logo=github
22
+ :target: https://github.com/MacHu-GWU/rstobj-project/blob/main/release-history.rst
23
+
24
+ .. image:: https://img.shields.io/badge/⭐_Star_me_on_GitHub!--None.svg?style=social&logo=github
22
25
  :target: https://github.com/MacHu-GWU/rstobj-project
23
26
 
24
27
  ------
25
28
 
26
-
27
- .. image:: https://img.shields.io/badge/Link-Document-blue.svg
28
- :target: https://rstobj.readthedocs.io/index.html
29
-
30
29
  .. image:: https://img.shields.io/badge/Link-API-blue.svg
31
- :target: https://rstobj.readthedocs.io/py-modindex.html
32
-
33
- .. image:: https://img.shields.io/badge/Link-Source_Code-blue.svg
34
- :target: https://rstobj.readthedocs.io/py-modindex.html
30
+ :target: https://rstobj.readthedocs.io/en/latest/py-modindex.html
35
31
 
36
32
  .. image:: https://img.shields.io/badge/Link-Install-blue.svg
37
33
  :target: `install`_
@@ -51,6 +47,8 @@
51
47
 
52
48
  Welcome to ``rstobj`` Documentation
53
49
  ==============================================================================
50
+ .. image:: https://rstobj.readthedocs.io/en/latest/_static/rstobj-logo.png
51
+ :target: https://rstobj.readthedocs.io/en/latest/
54
52
 
55
53
  ``rstobj`` is a library that construct Restructured Text markup or directives from Python Code. ``rstobj`` is based on ``jinja2``.
56
54
 
@@ -73,23 +71,21 @@ I have a `Blog Post <https://github.com/MacHu-GWU/Tech-Blog/issues/6>`_ to share
73
71
 
74
72
  .. code-block:: python
75
73
 
76
- import rstobj # or from rstobj import *
74
+ import rstobj.api as rstobj
77
75
 
78
76
  header = rstobj.markup.Header(title="Section1", header_level=1, auto_label=True)
79
- rst_header = header.render()
80
- print(rst_header)
77
+ print(header.render())
81
78
 
82
79
  ltable = rstobj.directives.ListTable(
83
80
  data=[["id", "name"], [1, "Alice"], [2, "Bob"]],
84
81
  title="Users",
85
82
  header=True,
86
83
  )
87
- rst = ltable.render()
88
- print(rst_ltable)
84
+ print(ltable.render())
89
85
 
90
86
  Output::
91
87
 
92
- .. _section1:
88
+ .. _Section1:
93
89
 
94
90
  Section1
95
91
  ========
@@ -105,7 +101,9 @@ Output::
105
101
  * - 2
106
102
  - Bob
107
103
 
108
- I recommend to use this in your jinja2 template, content of ``outut.rst``::
104
+ See the `Rendering Gallery <https://rstobj.readthedocs.io/en/latest/01-Rendering-Gallery/index.html>`_ for every supported markup and directive, with its Python code, its output, and how it renders.
105
+
106
+ I recommend to use this in your jinja2 template, content of ``output.rst``::
109
107
 
110
108
  {{ header.render() }}
111
109
  {{ ltable.render() }}
@@ -151,4 +149,17 @@ To upgrade to latest version:
151
149
 
152
150
  .. code-block:: console
153
151
 
154
- $ pip install --upgrade rstobj
152
+ $ pip install --upgrade rstobj
153
+
154
+ .. _use-with-ai-coding-agents:
155
+
156
+ Use with AI Coding Agents
157
+ ------------------------------------------------------------------------------
158
+
159
+ This repo ships an `Agent Skill <https://code.claude.com/docs/en/skills>`_ that documents the public API of ``rstobj``, so an AI coding agent such as Claude Code can use the library without reading its source. It lives in `.claude/skills/pypi-rstobj <https://github.com/MacHu-GWU/rstobj-project/tree/main/.claude/skills/pypi-rstobj>`_. To use it in your project, copy it into your project's ``.claude/skills/`` folder. Run this from your project's root:
160
+
161
+ .. code-block:: console
162
+
163
+ $ git clone --depth 1 https://github.com/MacHu-GWU/rstobj-project.git /tmp/rstobj-project
164
+ $ mkdir -p .claude/skills
165
+ $ cp -R /tmp/rstobj-project/.claude/skills/pypi-rstobj .claude/skills/
@@ -0,0 +1,131 @@
1
+ # [project] table: https://packaging.python.org/en/latest/guides/writing-pyproject-toml/
2
+ [project]
3
+ name = "rstobj"
4
+ # Bump before each release (https://semver.org/), then ``mise run inst`` to update ``uv.lock``.
5
+ version = "2.0.1"
6
+ description = "Construct reStructuredText markup and directives from Python code."
7
+ # An SPDX license expression (PEP 639); keep ``LICENSE.txt`` in sync.
8
+ # Read: https://packaging.python.org/en/latest/guides/writing-pyproject-toml/#license-and-license-files
9
+ # Valid identifiers: https://spdx.org/licenses/
10
+ license = "MIT"
11
+ license-files = ["LICENSE.txt", "AUTHORS.rst"]
12
+ authors = [
13
+ { name = "Sanhe Hu", email = "husanhe@gmail.com" },
14
+ ]
15
+ maintainers = [
16
+ { name = "Sanhe Hu", email = "husanhe@gmail.com" },
17
+ ]
18
+ keywords = []
19
+ readme = "README.rst"
20
+ requires-python = ">=3.11,<4.0"
21
+ # Read: https://pypi.org/classifiers/
22
+ classifiers = [
23
+ "Development Status :: 4 - Beta",
24
+ "Intended Audience :: Developers",
25
+ "Natural Language :: English",
26
+ "Operating System :: Microsoft :: Windows",
27
+ "Operating System :: MacOS",
28
+ "Operating System :: Unix",
29
+ "Programming Language :: Python :: 3",
30
+ "Programming Language :: Python :: 3.11",
31
+ "Programming Language :: Python :: 3.12",
32
+ "Programming Language :: Python :: 3.13",
33
+ "Programming Language :: Python :: 3.14",
34
+ ]
35
+
36
+ # --- Dependencies ---
37
+ # Edit these lists, then ``mise run inst`` to update ``uv.lock`` and ``.venv``.
38
+ dependencies = [
39
+ "jinja2>=3.1.0,<4.0.0", # renders the reST templates in rstobj/templates
40
+ ]
41
+
42
+ # --- Optional dependencies (extras) ---
43
+ # Read: https://packaging.python.org/en/latest/guides/writing-pyproject-toml/#dependencies-optional-dependencies
44
+ # Each one must support every Python version in ``requires-python``.
45
+ [project.optional-dependencies]
46
+
47
+ # local development
48
+ dev = [
49
+ "rich>=14.3.4,<15.0.0",
50
+ ]
51
+
52
+ # tests and coverage
53
+ test = [
54
+ "pytest>=9.1.1,<10.0.0",
55
+ "pytest-cov>=7.1.0,<8.0.0",
56
+ "docutils>=0.21.2,<1.0.0", # checks that the rendered reST is valid
57
+ ]
58
+
59
+ # docs build
60
+ doc = [
61
+ "Sphinx>=8.2.3,<9.0.0", # held below 9 until its autodoc rewrite is verified
62
+ "sphinx-copybutton>=0.5.2,<1.0.0", # copy button on code blocks
63
+ "sphinx-design>=0.7.0,<1.0.0", # cards, tabs, grids
64
+ "sphinx-jinja>=2.0.2,<3.0.0", # jinja in reST
65
+ "furo==2025.12.19", # theme
66
+ "pygments>=2.18.0,<3.0.0", # syntax highlighting
67
+ "ipython>=8.18.1,<8.19.0", # notebook execution
68
+ "ipykernel>=7.3.0,<8.0.0", # notebook kernel
69
+ "nbsphinx>=0.9.8,<1.0.0", # notebooks as doc pages
70
+ "docfly>=3.0.3,<4.0.0", # toctree and API reference
71
+ ]
72
+
73
+ # mise tasks
74
+ mise = [
75
+ "PyGithub>=2.8.0,<3.0.0", # GitHub API client
76
+ "httpx2>=2.13.1,<3.0.0", # Codecov and Read the Docs APIs
77
+ ]
78
+
79
+ [project.urls]
80
+ Homepage = "https://github.com/MacHu-GWU/rstobj-project"
81
+ Documentation = "https://rstobj.readthedocs.io/en/latest/"
82
+ Repository = "https://github.com/MacHu-GWU/rstobj-project"
83
+ Issues = "https://github.com/MacHu-GWU/rstobj-project/issues"
84
+ Changelog = "https://github.com/MacHu-GWU/rstobj-project/blob/main/release-history.rst"
85
+ Download = "https://pypi.org/pypi/rstobj#files"
86
+
87
+ # Read: https://packaging.python.org/en/latest/guides/writing-pyproject-toml/#creating-executable-scripts
88
+ [project.scripts]
89
+
90
+ [tool.setuptools.packages.find]
91
+ where = ["."]
92
+ include = [
93
+ "rstobj*",
94
+ ]
95
+ exclude = [
96
+ "rstobj.tests",
97
+ "rstobj.tests.*",
98
+ "rstobj.docs",
99
+ "rstobj.docs.*",
100
+ ]
101
+
102
+ # Non-Python files shipped in the wheel: the jinja2 templates rendered by ``rstobj.templates``.
103
+ [tool.setuptools.package-data]
104
+ rstobj = [
105
+ "templates/*.rst",
106
+ ]
107
+
108
+ # --- ruff: ``mise run format`` / ``mise run lint`` ---
109
+ [tool.ruff]
110
+ extend-exclude = [
111
+ "rstobj/vendor",
112
+ ".claude/skills/*/assets", # templates, not valid Python
113
+ ]
114
+
115
+ [tool.ruff.lint.per-file-ignores]
116
+ # re-export modules
117
+ "**/__init__.py" = ["F401"]
118
+ "**/api.py" = ["F401"]
119
+
120
+ # --- pytest 9+ native table ---
121
+ # Read: https://docs.pytest.org/en/stable/reference/customize.html#pyproject-toml
122
+ [tool.pytest]
123
+ testpaths = ["tests"]
124
+ # strict = true # only with a pinned pytest
125
+ # filterwarnings = ["error"]
126
+ # markers = ["slow: tests that take more than a few seconds"]
127
+
128
+ # --- Build (``mise run build``); setuptools 77+ for PEP 639 ``license`` ---
129
+ [build-system]
130
+ requires = ["setuptools>=77.0"]
131
+ build-backend = "setuptools.build_meta"
@@ -0,0 +1,5 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ """
4
+ Construct RestructuredText markup and directives from Python Code.
5
+ """
@@ -0,0 +1,4 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ from .directives import api as directives
4
+ from .markup import api as markup
@@ -0,0 +1,139 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ """
4
+ RestructuredText Object abstraction.
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ import typing as T
10
+ from dataclasses import dataclass
11
+
12
+ if T.TYPE_CHECKING: # pragma: no cover
13
+ from jinja2 import Template
14
+
15
+ from .templates import env
16
+ from .option import Options
17
+
18
+
19
+ def _indent_line(line: str, prefix: str) -> str:
20
+ """
21
+ Prefix a line and strip its trailing whitespace. A blank line stays empty,
22
+ so indenting never leaves whitespace-only lines.
23
+ """
24
+ line = line.rstrip()
25
+ if line:
26
+ return prefix + line
27
+ else:
28
+ return ""
29
+
30
+
31
+ def _indent_continuation(text: str, width: int, force: bool) -> str:
32
+ """
33
+ Indent every line after the first by ``width`` spaces, so a multi-line
34
+ text stays inside the list item or table cell it starts in.
35
+
36
+ :param force: if False, text whose continuation lines are all indented by
37
+ at least ``width`` already is returned unchanged, so callers that
38
+ indented their strings by hand keep the same output.
39
+ """
40
+ lines = text.split("\n")
41
+ rest = lines[1:]
42
+ if not force:
43
+ is_indented = all(
44
+ (not line.strip()) or (len(line) - len(line.lstrip(" ")) >= width)
45
+ for line in rest
46
+ )
47
+ if is_indented:
48
+ return text
49
+ prefix = " " * width
50
+ return "\n".join([lines[0]] + [_indent_line(line, prefix) for line in rest])
51
+
52
+
53
+ @dataclass(kw_only=True)
54
+ class RstObj:
55
+ """
56
+ The base restructured text object.
57
+ """
58
+
59
+ @property
60
+ def template_name(self) -> str:
61
+ """
62
+ Find template file.
63
+ """
64
+ return "{}.{}.rst".format(self.__module__, self.__class__.__name__)
65
+
66
+ @property
67
+ def template(self) -> Template:
68
+ """
69
+ Return ``jinja2.Template`` instance.
70
+ """
71
+ return env.get_template(self.template_name)
72
+
73
+ def render(
74
+ self,
75
+ indent: int | None = None,
76
+ first_line_indent: int | None = None,
77
+ **kwargs,
78
+ ) -> str:
79
+ """
80
+ Render this object into text.
81
+
82
+ :param indent: global indent. Indent length can be changed in
83
+ :attr:`rstobj.option.Options.tab`.
84
+
85
+ :param first_line_indent: sometimes we only need to indent
86
+ first line, this option will overwrite the ``indent`` argument.
87
+
88
+ :param kwargs: other optional arguments.
89
+ """
90
+ out = self.template.render(obj=self, tab=Options.tab)
91
+ if indent or first_line_indent:
92
+ origin_lines = out.split("\n")
93
+ target_lines = [
94
+ _indent_line(line, Options.tab * (indent or 0)) for line in origin_lines
95
+ ]
96
+ if first_line_indent is not None:
97
+ if first_line_indent >= 0:
98
+ target_lines[0] = _indent_line(
99
+ origin_lines[0],
100
+ Options.tab * first_line_indent,
101
+ )
102
+ else: # pragma: no cover
103
+ raise TypeError
104
+ out = "\n".join(target_lines)
105
+ return out
106
+
107
+ @staticmethod
108
+ def str_or_render(
109
+ value: str | RstObj,
110
+ **kwargs,
111
+ ) -> str:
112
+ """
113
+ If it is a string type, then just return. If it is a RstObj type,
114
+ then return the rendered string.
115
+ """
116
+ if isinstance(value, RstObj):
117
+ return value.render(**kwargs)
118
+ else:
119
+ return str(value)
120
+
121
+ @staticmethod
122
+ def _render_nested(
123
+ value: str | RstObj,
124
+ width: int,
125
+ ) -> str:
126
+ """
127
+ Render a list item or table cell whose text starts after a marker
128
+ ``width`` characters wide, such as ``"- "`` or ``" * - "``.
129
+
130
+ A :class:`RstObj` is rendered without its leading and trailing blank
131
+ lines, and all its continuation lines are indented. A string is taken
132
+ as reStructuredText; its continuation lines are indented unless they
133
+ already are.
134
+ """
135
+ if isinstance(value, RstObj):
136
+ text = value.render().strip("\n")
137
+ return _indent_continuation(text, width, force=True)
138
+ else:
139
+ return _indent_continuation(str(value), width, force=False)
@@ -0,0 +1,5 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ """
4
+ reStructuredText Directives: http://docutils.sourceforge.net/docs/ref/rst/directives.html
5
+ """
@@ -0,0 +1,26 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ from .image import Image
4
+ from .table import ListTable
5
+ from .codeblock import Code
6
+ from .codeblock import CodeBlockEmpty
7
+ from .codeblock import CodeBlockBase
8
+ from .codeblock import CodeBlock
9
+ from .codeblock import CodeBlockPython
10
+ from .codeblock import CodeBlockRuby
11
+ from .codeblock import CodeBlockR
12
+ from .codeblock import CodeBlockPerl
13
+ from .codeblock import CodeBlockC
14
+ from .codeblock import CodeBlockCPP
15
+ from .codeblock import CodeBlockHTML
16
+ from .codeblock import CodeBlockCSS
17
+ from .codeblock import CodeBlockJavaScript
18
+ from .codeblock import CodeBlockSQL
19
+ from .codeblock import CodeBlockScala
20
+ from .codeblock import CodeBlockMake
21
+ from .codeblock import CodeBlockBash
22
+ from .codeblock import CodeBlockLua
23
+ from .codeblock import CodeBlockRst
24
+ from .codeblock import CodeBlockMarkdown
25
+ from .toc import TableOfContent
26
+ from .miscellaneous import Include
@@ -0,0 +1,22 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ from __future__ import annotations
4
+
5
+ import typing as T
6
+ from dataclasses import dataclass
7
+ from dataclasses import field
8
+ from ..base import RstObj
9
+
10
+
11
+ @dataclass(kw_only=True)
12
+ class Directive(RstObj):
13
+ class_: str | None = field(default=None)
14
+ name: str | None = field(default=None)
15
+
16
+ meta_directive_keyword: T.ClassVar[str | None] = None
17
+ #: False for a directive that has no ``:name:`` option, such as ``contents``.
18
+ meta_supports_name: T.ClassVar[bool] = True
19
+
20
+ @property
21
+ def arg(self): # pragma: no cover
22
+ raise NotImplementedError