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.
- rstobj-2.0.1/AUTHORS.rst +15 -0
- {rstobj-1.2.1 → rstobj-2.0.1}/LICENSE.txt +2 -2
- {rstobj-1.2.1/rstobj.egg-info → rstobj-2.0.1}/PKG-INFO +72 -43
- {rstobj-1.2.1 → rstobj-2.0.1}/README.rst +31 -20
- rstobj-2.0.1/pyproject.toml +131 -0
- rstobj-2.0.1/rstobj/__init__.py +5 -0
- rstobj-2.0.1/rstobj/api.py +4 -0
- rstobj-2.0.1/rstobj/base.py +139 -0
- rstobj-2.0.1/rstobj/directives/__init__.py +5 -0
- rstobj-2.0.1/rstobj/directives/api.py +26 -0
- rstobj-2.0.1/rstobj/directives/base.py +22 -0
- {rstobj-1.2.1 → rstobj-2.0.1}/rstobj/directives/codeblock.py +31 -31
- {rstobj-1.2.1 → rstobj-2.0.1}/rstobj/directives/image.py +26 -31
- rstobj-2.0.1/rstobj/directives/miscellaneous.py +47 -0
- {rstobj-1.2.1 → rstobj-2.0.1}/rstobj/directives/table.py +17 -14
- {rstobj-1.2.1 → rstobj-2.0.1}/rstobj/directives/toc.py +22 -23
- rstobj-2.0.1/rstobj/markup/__init__.py +5 -0
- rstobj-2.0.1/rstobj/markup/api.py +16 -0
- {rstobj-1.2.1 → rstobj-2.0.1}/rstobj/markup/bullet_list.py +6 -3
- {rstobj-1.2.1 → rstobj-2.0.1}/rstobj/markup/enum_list.py +8 -4
- {rstobj-1.2.1 → rstobj-2.0.1}/rstobj/markup/header.py +58 -53
- {rstobj-1.2.1 → rstobj-2.0.1}/rstobj/markup/hyperlink.py +11 -7
- rstobj-2.0.1/rstobj/paths.py +60 -0
- rstobj-2.0.1/rstobj/templates/__init__.py +12 -0
- rstobj-2.0.1/rstobj/templates/rstobj.directives.base.Directive.rst +8 -0
- rstobj-2.0.1/rstobj/templates/rstobj.directives.codeblock.CodeBlockBase.rst +9 -0
- rstobj-2.0.1/rstobj/templates/rstobj.directives.image.Image.rst +18 -0
- {rstobj-1.2.1 → rstobj-2.0.1}/rstobj/templates/rstobj.directives.miscellaneous.Include.rst +10 -10
- rstobj-2.0.1/rstobj/templates/rstobj.directives.table.ListTable.rst +29 -0
- {rstobj-1.2.1 → rstobj-2.0.1}/rstobj/templates/rstobj.directives.toc.TableOfContent.rst +3 -3
- {rstobj-1.2.1 → rstobj-2.0.1}/rstobj/templates/rstobj.markup.bullet_list.BulletList.rst +1 -1
- rstobj-2.0.1/rstobj/templates/rstobj.markup.enum_list.EnumList.rst +4 -0
- rstobj-2.0.1/rstobj/templates/rstobj.markup.header.Header.rst +5 -0
- {rstobj-1.2.1/rstobj/docs → rstobj-2.0.1/rstobj/vendor}/__init__.py +0 -1
- rstobj-2.0.1/rstobj/vendor/pytest_cov_helper.py +148 -0
- {rstobj-1.2.1 → rstobj-2.0.1/rstobj.egg-info}/PKG-INFO +72 -43
- rstobj-2.0.1/rstobj.egg-info/SOURCES.txt +47 -0
- rstobj-2.0.1/rstobj.egg-info/requires.txt +25 -0
- rstobj-2.0.1/tests/test_api.py +19 -0
- rstobj-2.0.1/tests/test_base.py +85 -0
- rstobj-2.0.1/tests/test_option.py +52 -0
- rstobj-1.2.1/AUTHORS.rst +0 -14
- rstobj-1.2.1/MANIFEST.in +0 -10
- rstobj-1.2.1/release-history.rst +0 -97
- rstobj-1.2.1/requirements-dev.txt +0 -4
- rstobj-1.2.1/requirements-doc.txt +0 -15
- rstobj-1.2.1/requirements-test.txt +0 -3
- rstobj-1.2.1/requirements.txt +0 -4
- rstobj-1.2.1/rstobj/__init__.py +0 -22
- rstobj-1.2.1/rstobj/_version.py +0 -4
- rstobj-1.2.1/rstobj/base.py +0 -103
- rstobj-1.2.1/rstobj/demo.py +0 -107
- rstobj-1.2.1/rstobj/directives/__init__.py +0 -11
- rstobj-1.2.1/rstobj/directives/base.py +0 -16
- rstobj-1.2.1/rstobj/directives/miscellaneous.py +0 -43
- rstobj-1.2.1/rstobj/markup/__init__.py +0 -13
- rstobj-1.2.1/rstobj/templates/__init__.py +0 -6
- rstobj-1.2.1/rstobj/templates/rstobj.directives.base.Directive.rst +0 -8
- rstobj-1.2.1/rstobj/templates/rstobj.directives.codeblock.CodeBlockBase.rst +0 -3
- rstobj-1.2.1/rstobj/templates/rstobj.directives.image.Image.rst +0 -15
- rstobj-1.2.1/rstobj/templates/rstobj.directives.table.ListTable.rst +0 -28
- rstobj-1.2.1/rstobj/templates/rstobj.markup.enum_list.EnumList.rst +0 -3
- rstobj-1.2.1/rstobj/templates/rstobj.markup.header.Header.rst +0 -5
- rstobj-1.2.1/rstobj/tests/__init__.py +0 -23
- rstobj-1.2.1/rstobj/tests/rstobj.directives.codeblock.Code.render-indent.rst +0 -4
- rstobj-1.2.1/rstobj/tests/rstobj.directives.codeblock.CodeBlock.render.rst +0 -6
- rstobj-1.2.1/rstobj/tests/rstobj.directives.codeblock.CodeBlockEmpty.render-indent.rst +0 -6
- rstobj-1.2.1/rstobj/tests/rstobj.directives.codeblock.CodeBlockEmpty.render.rst +0 -6
- rstobj-1.2.1/rstobj/tests/rstobj.directives.codeblock.CodeBlockPython.render.rst +0 -6
- rstobj-1.2.1/rstobj/tests/rstobj.directives.image.Image.render-indent.rst +0 -1
- rstobj-1.2.1/rstobj/tests/rstobj.directives.image.Image.uri-only.rst +0 -1
- rstobj-1.2.1/rstobj/tests/rstobj.directives.image.Image.with-everything.rst +0 -5
- rstobj-1.2.1/rstobj/tests/rstobj.directives.miscellaneous.Include.render.rst +0 -1
- rstobj-1.2.1/rstobj/tests/rstobj.directives.table.ListTable.with-codeblock-indent.rst +0 -18
- rstobj-1.2.1/rstobj/tests/rstobj.directives.table.ListTable.with-codeblock.rst +0 -18
- rstobj-1.2.1/rstobj/tests/rstobj.directives.table.ListTable.with-header.rst +0 -10
- rstobj-1.2.1/rstobj/tests/rstobj.directives.table.ListTable.with-index.rst +0 -10
- rstobj-1.2.1/rstobj/tests/rstobj.directives.table.ListTable.with-widths.rst +0 -11
- rstobj-1.2.1/rstobj/tests/rstobj.directives.toc.TableOfContent.basic.rst +0 -1
- rstobj-1.2.1/rstobj/tests/rstobj.directives.toc.TableOfContent.rich-options.rst +0 -4
- rstobj-1.2.1/rstobj/tests/rstobj.markup.bullet_list.BulletList.render.rst +0 -3
- rstobj-1.2.1/rstobj/tests/rstobj.markup.enum_list.EnumList.render.rst +0 -3
- rstobj-1.2.1/rstobj/tests/rstobj.markup.header.Header.has-ref_key-auto-bar.rst +0 -4
- rstobj-1.2.1/rstobj/tests/rstobj.markup.header.Header.no-ref_key-auto-bar.rst +0 -2
- rstobj-1.2.1/rstobj/tests/rstobj.markup.header.Header.no-ref_key.rst +0 -2
- rstobj-1.2.1/rstobj/tests/rstobj.markup.header.Header2.auto-ref_key.rst +0 -4
- rstobj-1.2.1/rstobj/tests/rstobj.markup.header.Header2.has-ref_key-auto-bar.rst +0 -4
- rstobj-1.2.1/rstobj.egg-info/SOURCES.txt +0 -71
- rstobj-1.2.1/rstobj.egg-info/requires.txt +0 -17
- rstobj-1.2.1/setup.py +0 -245
- {rstobj-1.2.1 → rstobj-2.0.1}/rstobj/option.py +0 -0
- {rstobj-1.2.1 → rstobj-2.0.1}/rstobj/templates/rstobj.directives.codeblock.Code.rst +0 -0
- {rstobj-1.2.1 → rstobj-2.0.1}/rstobj/templates/rstobj.directives.codeblock.CodeBlockEmpty.rst +0 -0
- {rstobj-1.2.1 → rstobj-2.0.1}/rstobj/templates/rstobj.markup.hyperlink.Reference.rst +0 -0
- {rstobj-1.2.1 → rstobj-2.0.1}/rstobj/templates/rstobj.markup.hyperlink.URI.rst +0 -0
- {rstobj-1.2.1 → rstobj-2.0.1}/rstobj.egg-info/dependency_links.txt +0 -0
- {rstobj-1.2.1 → rstobj-2.0.1}/rstobj.egg-info/top_level.txt +0 -0
- {rstobj-1.2.1 → rstobj-2.0.1}/setup.cfg +0 -0
rstobj-2.0.1/AUTHORS.rst
ADDED
|
@@ -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
|
-
|
|
1
|
+
MIT License
|
|
2
2
|
|
|
3
|
-
Copyright
|
|
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
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: rstobj
|
|
3
|
-
Version:
|
|
4
|
-
Summary: Construct
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
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.
|
|
24
|
-
Classifier: Programming Language :: Python :: 3.
|
|
25
|
-
Classifier: Programming Language :: Python :: 3.
|
|
26
|
-
Classifier: Programming Language :: Python :: 3.
|
|
27
|
-
|
|
28
|
-
|
|
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/
|
|
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/
|
|
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/
|
|
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
|
|
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
|
|
125
|
+
import rstobj.api as rstobj
|
|
110
126
|
|
|
111
127
|
header = rstobj.markup.Header(title="Section1", header_level=1, auto_label=True)
|
|
112
|
-
|
|
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
|
-
|
|
121
|
-
print(rst_ltable)
|
|
135
|
+
print(ltable.render())
|
|
122
136
|
|
|
123
137
|
Output::
|
|
124
138
|
|
|
125
|
-
..
|
|
139
|
+
.. _Section1:
|
|
126
140
|
|
|
127
141
|
Section1
|
|
128
142
|
========
|
|
@@ -138,7 +152,9 @@ Output::
|
|
|
138
152
|
* - 2
|
|
139
153
|
- Bob
|
|
140
154
|
|
|
141
|
-
|
|
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/
|
|
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/
|
|
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/
|
|
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
|
|
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
|
|
74
|
+
import rstobj.api as rstobj
|
|
77
75
|
|
|
78
76
|
header = rstobj.markup.Header(title="Section1", header_level=1, auto_label=True)
|
|
79
|
-
|
|
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
|
-
|
|
88
|
-
print(rst_ltable)
|
|
84
|
+
print(ltable.render())
|
|
89
85
|
|
|
90
86
|
Output::
|
|
91
87
|
|
|
92
|
-
..
|
|
88
|
+
.. _Section1:
|
|
93
89
|
|
|
94
90
|
Section1
|
|
95
91
|
========
|
|
@@ -105,7 +101,9 @@ Output::
|
|
|
105
101
|
* - 2
|
|
106
102
|
- Bob
|
|
107
103
|
|
|
108
|
-
|
|
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,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,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
|