pax_global_header 0000666 0000000 0000000 00000000064 14635002517 0014515 g ustar 00root root 0000000 0000000 52 comment=ed18c5fe9255feb059abfb64186b6e43af209046
markdown-exec-1.9.2/ 0000775 0000000 0000000 00000000000 14635002517 0014272 5 ustar 00root root 0000000 0000000 markdown-exec-1.9.2/.copier-answers.yml 0000664 0000000 0000000 00000001362 14635002517 0020036 0 ustar 00root root 0000000 0000000 # Changes here will be overwritten by Copier
_commit: 1.2.9
_src_path: gh:pawamoy/copier-uv
author_email: dev@pawamoy.fr
author_fullname: Timothée Mazzucotelli
author_username: pawamoy
copyright_date: '2022'
copyright_holder: Timothée Mazzucotelli
copyright_holder_email: dev@pawamoy.fr
copyright_license: ISC License
insiders: true
insiders_email: insiders@pawamoy.fr
insiders_repository_name: markdown-exec
project_description: Utilities to execute code blocks in Markdown files.
project_name: Markdown Exec
public_release: true
python_package_command_line_name: ''
python_package_distribution_name: markdown-exec
python_package_import_name: markdown_exec
repository_name: markdown-exec
repository_namespace: pawamoy
repository_provider: github.com
markdown-exec-1.9.2/.envrc 0000664 0000000 0000000 00000000021 14635002517 0015401 0 ustar 00root root 0000000 0000000 PATH_add scripts
markdown-exec-1.9.2/.github/ 0000775 0000000 0000000 00000000000 14635002517 0015632 5 ustar 00root root 0000000 0000000 markdown-exec-1.9.2/.github/FUNDING.yml 0000664 0000000 0000000 00000000126 14635002517 0017446 0 ustar 00root root 0000000 0000000 github: pawamoy
ko_fi: pawamoy
polar: pawamoy
custom:
- https://www.paypal.me/pawamoy
markdown-exec-1.9.2/.github/ISSUE_TEMPLATE/ 0000775 0000000 0000000 00000000000 14635002517 0020015 5 ustar 00root root 0000000 0000000 markdown-exec-1.9.2/.github/ISSUE_TEMPLATE/bug_report.md 0000664 0000000 0000000 00000002700 14635002517 0022506 0 ustar 00root root 0000000 0000000 ---
name: Bug report
about: Create a bug report to help us improve.
title: "bug: "
labels: unconfirmed
assignees: [pawamoy]
---
### Description of the bug
### To Reproduce
```
WRITE MRE / INSTRUCTIONS HERE
```
### Full traceback
Full traceback
```python
PASTE TRACEBACK HERE
```
` ([500ed1b](https://github.com/pawamoy/markdown-exec/commit/500ed1b3a6bb94edd3d5d7152cd818bc3db27bbd) by Timothée Mazzucotelli).
## [1.8.3](https://github.com/pawamoy/markdown-exec/releases/tag/1.8.3) - 2024-05-22
[Compare with 1.8.2](https://github.com/pawamoy/markdown-exec/compare/1.8.2...1.8.3)
### Bug Fixes
- Don't leak future annotations in user code ([ba0c35e](https://github.com/pawamoy/markdown-exec/commit/ba0c35e89e3056325b3dcbc7e61b6f108ec55885) by Timothée Mazzucotelli). [Issue-47](https://github.com/pawamoy/markdown-exec/issues/47)
## [1.8.2](https://github.com/pawamoy/markdown-exec/releases/tag/1.8.2) - 2024-05-20
[Compare with 1.8.1](https://github.com/pawamoy/markdown-exec/compare/1.8.1...1.8.2)
### Bug Fixes
- Give `__name__` to executed Python "modules", and populate `sys.modules` too ([db25ee7](https://github.com/pawamoy/markdown-exec/commit/db25ee703da9b70cb4a13b2b4b61634d697119c4) by Timothée Mazzucotelli). [Issue-47](https://github.com/pawamoy/markdown-exec/issues/47)
## [1.8.1](https://github.com/pawamoy/markdown-exec/releases/tag/1.8.1) - 2024-04-15
[Compare with 1.8.0](https://github.com/pawamoy/markdown-exec/compare/1.8.0...1.8.1)
### Bug Fixes
- Add missing CSS classes to the ANSI stylesheet ([51493f2](https://github.com/pawamoy/markdown-exec/commit/51493f255dd91f28ce6c8d7e7176ec5687e28b4a) by Timothée Mazzucotelli). [Issue-43](https://github.com/pawamoy/markdown-exec/issues/43)
## [1.8.0](https://github.com/pawamoy/markdown-exec/releases/tag/1.8.0) - 2024-01-05
[Compare with 1.7.0](https://github.com/pawamoy/markdown-exec/compare/1.7.0...1.8.0)
### Features
- Add `pyodide` fence ([3a2fab0](https://github.com/pawamoy/markdown-exec/commit/3a2fab0b23196a4122bcee6d9b81d3f421f11bbb) by Timothée Mazzucotelli).
- Add `ansi` option to mark ANSI extra as required or not ([27743c2](https://github.com/pawamoy/markdown-exec/commit/27743c20f56dd00ce730e1d028d362a4f95e48c7) by Timothée Mazzucotelli). [Issue #28](https://github.com/pawamoy/markdown-exec/issues/28), [Issue #29](https://github.com/pawamoy/markdown-exec/issues/29)
### Code Refactoring
- Modernize MkDocs plugin ([4864608](https://github.com/pawamoy/markdown-exec/commit/48646081746c6c5ece0c6566a4b9733ace518791) by Timothée Mazzucotelli).
## [1.7.0](https://github.com/pawamoy/markdown-exec/releases/tag/1.7.0) - 2023-10-17
[Compare with 1.6.0](https://github.com/pawamoy/markdown-exec/compare/1.6.0...1.7.0)
### Features
- Set `MKDOCS_CONFIG_DIR` environment variable to build file path relative to it ([a2cbea5](https://github.com/pawamoy/markdown-exec/commit/a2cbea52d39ef43960c910830eae14dc846624d0) by Timothée Mazzucotelli).
## [1.6.0](https://github.com/pawamoy/markdown-exec/releases/tag/1.6.0) - 2023-04-18
[Compare with 1.5.3](https://github.com/pawamoy/markdown-exec/compare/1.5.3...1.6.0)
### Features
- Add `idprefix` option allowing to change/remove HTML id/href prefixes ([4d91463](https://github.com/pawamoy/markdown-exec/commit/4d914630e5642feb87103644800d3c9f7b59c6ad) by Timothée Mazzucotelli).
## [1.5.3](https://github.com/pawamoy/markdown-exec/releases/tag/1.5.3) - 2023-04-18
[Compare with 1.5.2](https://github.com/pawamoy/markdown-exec/compare/1.5.2...1.5.3)
### Code Refactoring
- Reuse Markdown configuration as declared in mkdocs.yml ([afe091c](https://github.com/pawamoy/markdown-exec/commit/afe091caa33ed54fd65e25e4f90b8b60786ba3f9) by Timothée Mazzucotelli).
## [1.5.2](https://github.com/pawamoy/markdown-exec/releases/tag/1.5.2) - 2023-04-18
[Compare with 1.5.1](https://github.com/pawamoy/markdown-exec/compare/1.5.1...1.5.2)
### Code Refactoring
- Reset counter in post build event ([3bf80de](https://github.com/pawamoy/markdown-exec/commit/3bf80deabe9a7438b459c73e962c9693bce71135) by Timothée Mazzucotelli).
## [1.5.1](https://github.com/pawamoy/markdown-exec/releases/tag/1.5.1) - 2023-04-17
[Compare with 1.5.0](https://github.com/pawamoy/markdown-exec/compare/1.5.0...1.5.1)
### Bug Fixes
- Remove pycon output lines when rendering source as console ([fb5a23d](https://github.com/pawamoy/markdown-exec/commit/fb5a23d8d1d50aa2a1ede97150c269a07fa200ec) by Timothée Mazzucotelli).
- Fix nested rendering ([a110d44](https://github.com/pawamoy/markdown-exec/commit/a110d446209b390ec8a4ad8868818352f72a9808) by Timothée Mazzucotelli).
## [1.5.0](https://github.com/pawamoy/markdown-exec/releases/tag/1.5.0) - 2023-04-17
[Compare with 1.4.1](https://github.com/pawamoy/markdown-exec/compare/1.4.1...1.5.0)
### Features
- Update ToC with generated headings ([5ea2263](https://github.com/pawamoy/markdown-exec/commit/5ea2263d53729b6d3e79da69c29b171bb6c3e22d) by Timothée Mazzucotelli).
## [1.4.1](https://github.com/pawamoy/markdown-exec/releases/tag/1.4.1) - 2023-04-16
[Compare with 1.4.0](https://github.com/pawamoy/markdown-exec/compare/1.4.0...1.4.1)
### Bug Fixes
- Improve handling of errors within sessions ([87ac5f3](https://github.com/pawamoy/markdown-exec/commit/87ac5f352ce44370f52a7fb56d846c04b76447f9) by Timothée Mazzucotelli).
- Swallow non-extra parameters in run functions ([f5d4fef](https://github.com/pawamoy/markdown-exec/commit/f5d4fef1f78d94c3f8850f873076e3cd68c0a981) by Timothée Mazzucotelli).
### Code Refactoring
- Simplify tree formatter signature ([09d5427](https://github.com/pawamoy/markdown-exec/commit/09d542772ccb0d1250366b39fa3a9c9362e1ed42) by Timothée Mazzucotelli).
## [1.4.0](https://github.com/pawamoy/markdown-exec/releases/tag/1.4.0) - 2023-03-15
[Compare with 1.3.0](https://github.com/pawamoy/markdown-exec/compare/1.3.0...1.4.0)
### Features
- Sessions: persist and reuse state for Python and Pycon code blocks ([a8fef5e](https://github.com/pawamoy/markdown-exec/commit/a8fef5e90b1d7165e16ff5afe4b84e8441503098) by Timothée Mazzucotelli). [Issue #16](https://github.com/pawamoy/markdown-exec/issues/16)
## [1.3.0](https://github.com/pawamoy/markdown-exec/releases/tag/1.3.0) - 2023-02-18
[Compare with 1.2.0](https://github.com/pawamoy/markdown-exec/compare/1.2.0...1.3.0)
### Features
- Support wrapping result with console source ([268c82e](https://github.com/pawamoy/markdown-exec/commit/268c82e6f005dcaa1ddc75608d2f28927f069761) by Timothée Mazzucotelli). [Issue #13](https://github.com/pawamoy/markdown-exec/issues/13)
### Code Refactoring
- Remove margin hack from Material source ([beec237](https://github.com/pawamoy/markdown-exec/commit/beec2374b27075e66ddb4a7cdc2f2c81b7455b95) by Timothée Mazzucotelli).
- Better support pycon syntax ([22b51c6](https://github.com/pawamoy/markdown-exec/commit/22b51c64155060922e46ea10e6c0d1c1c1b00a2f) by Timothée Mazzucotelli).
## [1.2.0](https://github.com/pawamoy/markdown-exec/releases/tag/1.2.0) - 2023-02-01
[Compare with 1.1.0](https://github.com/pawamoy/markdown-exec/compare/1.1.0...1.2.0)
### Features
- Support ANSI code blocks ([39719c5](https://github.com/pawamoy/markdown-exec/commit/39719c5d7ac1bbde6d60002082a0ad3b48730545) by Timothée Mazzucotelli). [Issue #11](https://github.com/pawamoy/markdown-exec/issues/11)
## [1.1.0](https://github.com/pawamoy/markdown-exec/releases/tag/1.1.0) - 2023-01-27
[Compare with 1.0.0](https://github.com/pawamoy/markdown-exec/compare/1.0.0...1.1.0)
### Features
- Log details to help debugging errors ([4c0228d](https://github.com/pawamoy/markdown-exec/commit/4c0228da41f5970e719b20a40c0fab47a9d12244) by Timothée Mazzucotelli). [Issue #12](https://github.com/pawamoy/markdown-exec/issues/12)
- Allow expecting specific exit codes ([620ec66](https://github.com/pawamoy/markdown-exec/commit/620ec66182dd0f84600258408720779822615085) by Timothée Mazzucotelli). [Issue #10](https://github.com/pawamoy/markdown-exec/issues/10)
### Code Refactoring
- Formatters now only accept keyword arguments ([0940ca9](https://github.com/pawamoy/markdown-exec/commit/0940ca98e81548474351e234715df2fc290fdc1e) by Timothée Mazzucotelli).
## [1.0.0](https://github.com/pawamoy/markdown-exec/releases/tag/1.0.0) - 2022-11-24
[Compare with 0.7.4](https://github.com/pawamoy/markdown-exec/compare/0.7.4...1.0.0)
### Features
- Allow defining IDs on code blocks (for warnings) ([0091167](https://github.com/pawamoy/markdown-exec/commit/009116719e81dd91190b391c82709fb179a62364) by Timothée Mazzucotelli).
### Code Refactoring
- Use base format everywhere (more flexible) ([cefba70](https://github.com/pawamoy/markdown-exec/commit/cefba704ae45df1b115b969e3d4d5105ebd052dd) by Timothée Mazzucotelli).
## [0.7.4](https://github.com/pawamoy/markdown-exec/releases/tag/0.7.4) - 2022-11-13
[Compare with 0.7.3](https://github.com/pawamoy/markdown-exec/compare/0.7.3...0.7.4)
### Bug Fixes
- Render source for non-HTML output (regression) ([3028dcd](https://github.com/pawamoy/markdown-exec/commit/3028dcd4f20f94b578995c326fd68d53a6dc3638) by Timothée Mazzucotelli).
## [0.7.3](https://github.com/pawamoy/markdown-exec/releases/tag/0.7.3) - 2022-11-13
[Compare with 0.7.2](https://github.com/pawamoy/markdown-exec/compare/0.7.2...0.7.3)
### Bug Fixes
- Don't wrap HTML in `p` tag ([420d79d](https://github.com/pawamoy/markdown-exec/commit/420d79d67c2a6bdc925b3bc3d89790258f922317) by Timothée Mazzucotelli).
## [0.7.2](https://github.com/pawamoy/markdown-exec/releases/tag/0.7.2) - 2022-09-01
[Compare with 0.7.1](https://github.com/pawamoy/markdown-exec/compare/0.7.1...0.7.2)
### Bug Fixes
- Make `tree` formatter forward extra options ([54996a9](https://github.com/pawamoy/markdown-exec/commit/54996a9bc2c803bb8c9de0861af69723ddb000fa) by Timothée Mazzucotelli).
- Fix race condition issue ([37d7f86](https://github.com/pawamoy/markdown-exec/commit/37d7f86eeaa73029ae89c1c5d07146d2387b10d3) by Timothée Mazzucotelli).
## [0.7.1](https://github.com/pawamoy/markdown-exec/releases/tag/0.7.1) - 2022-08-28
[Compare with 0.7.0](https://github.com/pawamoy/markdown-exec/compare/0.7.0...0.7.1)
### Bug Fixes
- Allow printing non-string objects ([ceaa482](https://github.com/pawamoy/markdown-exec/commit/ceaa482d16adfbd1609595a2ed6a241bad71f9de) by Timothée Mazzucotelli). [Issue #7](https://github.com/pawamoy/markdown-exec/issues/7)
## [0.7.0](https://github.com/pawamoy/markdown-exec/releases/tag/0.7.0) - 2022-05-28
[Compare with 0.6.0](https://github.com/pawamoy/markdown-exec/compare/0.6.0...0.7.0)
### Features
- Add ability to hide source lines ([3cb1934](https://github.com/pawamoy/markdown-exec/commit/3cb19345fa2b65478ac439b5f486d04bf5ff5337) by Timothée Mazzucotelli).
## [0.6.0](https://github.com/pawamoy/markdown-exec/releases/tag/0.6.0) - 2022-05-21
[Compare with 0.5.0](https://github.com/pawamoy/markdown-exec/compare/0.5.0...0.6.0)
### Features
- Add tree formatter ([8096990](https://github.com/pawamoy/markdown-exec/commit/8096990dcbf6795572e5e5afee12195d5a56c6f6) by Timothée Mazzucotelli).
- Handle code blocks execution errors and log warnings ([34e16db](https://github.com/pawamoy/markdown-exec/commit/34e16db679721db7d1df375912d512b5aed80b1a) by Timothée Mazzucotelli).
### Bug Fixes
- Fix Python execution to support nested scopes ([74b9a95](https://github.com/pawamoy/markdown-exec/commit/74b9a95ade3862752fb78d6c64be8b9b1d4d3886) by Timothée Mazzucotelli).
## [0.5.0](https://github.com/pawamoy/markdown-exec/releases/tag/0.5.0) - 2022-05-09
[Compare with 0.4.0](https://github.com/pawamoy/markdown-exec/compare/0.4.0...0.5.0)
### Features
- Allow wrapping result in code block ([37201e4](https://github.com/pawamoy/markdown-exec/commit/37201e4409badec903f311bcc0a6ab7acddff37c) by Timothée Mazzucotelli).
- Add support for shell code blocks ([f2b4b67](https://github.com/pawamoy/markdown-exec/commit/f2b4b671f4399637d0dac235a0af7739033f9526) by Timothée Mazzucotelli).
### Code Refactoring
- Fetch plugin languages from dict ([de8309e](https://github.com/pawamoy/markdown-exec/commit/de8309e6895a079031461bfea317215bcff9bc21) by Timothée Mazzucotelli).
- Add reusable base formatter ([c265bee](https://github.com/pawamoy/markdown-exec/commit/c265bee9abf0ad545b7fdc6ccf2e320071295a18) by Timothée Mazzucotelli).
## [0.4.0](https://github.com/pawamoy/markdown-exec/releases/tag/0.4.0) - 2022-05-09
[Compare with 0.3.1](https://github.com/pawamoy/markdown-exec/compare/0.3.1...0.4.0)
### Features
- Add literate Markdown support ([8d3ed7e](https://github.com/pawamoy/markdown-exec/commit/8d3ed7ef5c9a88849be0a5da44e7b478eb44c180) by Timothée Mazzucotelli).
- Add `material-block` style to show source ([ff10ee1](https://github.com/pawamoy/markdown-exec/commit/ff10ee1f0b55b2e77b97f272b49b24024f9de2ac) by Timothée Mazzucotelli).
- Support up to 8 levels of exec code block nesting ([bfde808](https://github.com/pawamoy/markdown-exec/commit/bfde8087ca6f4eb91aba8eb01b37755dfacb4cdb) by Timothée Mazzucotelli).
## [0.3.1](https://github.com/pawamoy/markdown-exec/releases/tag/0.3.1) - 2022-05-07
[Compare with 0.3.0](https://github.com/pawamoy/markdown-exec/compare/0.3.0...0.3.1)
### Bug Fixes
- Actually prevent HTML re-rendering ([4374852](https://github.com/pawamoy/markdown-exec/commit/4374852706207beac3b8dbd8dc9d75be51b1df0d) by Timothée Mazzucotelli).
## [0.3.0](https://github.com/pawamoy/markdown-exec/releases/tag/0.3.0) - 2022-05-01
[Compare with 0.2.0](https://github.com/pawamoy/markdown-exec/compare/0.2.0...0.3.0)
### Features
- Support `pycon` code blocks ([2c86394](https://github.com/pawamoy/markdown-exec/commit/2c86394417858654af21316c3555aff0e9fd2d26) by Timothée Mazzucotelli).
- Add `console` source integration option ([62dfd74](https://github.com/pawamoy/markdown-exec/commit/62dfd74185f7f33cdf6f4726b3aa898a1ac5d22f) by Timothée Mazzucotelli).
- Provide a MkDocs plugin for easier setup ([5fce814](https://github.com/pawamoy/markdown-exec/commit/5fce81462063b7c61d9833939e44958a466d4b24) by Timothée Mazzucotelli).
- Support changing tabs titles ([d150596](https://github.com/pawamoy/markdown-exec/commit/d150596beda1e5a5304bc06e27668294a75ff220) by Timothée Mazzucotelli).
- Allow using `print` in code blocks ([7c124fd](https://github.com/pawamoy/markdown-exec/commit/7c124fd416d6923bea2834479d972b14c3e22112) by Timothée Mazzucotelli).
- Allow passing extra opts like title to source code blocks ([bb3252a](https://github.com/pawamoy/markdown-exec/commit/bb3252a3e959cea198966ba59a70f6f5aa57a963) by Timothée Mazzucotelli).
### Code Refactoring
- Split Python formatter to allow reuse ([fc56702](https://github.com/pawamoy/markdown-exec/commit/fc56702b9c393323adc30abba42c823f601ef738) by Timothée Mazzucotelli).
- Setup a more robust Markdown converter ([395f4c4](https://github.com/pawamoy/markdown-exec/commit/395f4c4c21ab7f4afcc88250c1fd882269a06d02) by Timothée Mazzucotelli).
## [0.2.0](https://github.com/pawamoy/markdown-exec/releases/tag/0.2.0) - 2022-04-18
[Compare with 0.1.0](https://github.com/pawamoy/markdown-exec/compare/0.1.0...0.2.0)
### Features
- Add ability to render using tabs ([91a95ae](https://github.com/pawamoy/markdown-exec/commit/91a95ae4c6ad82e85dac24a110d09ca71eff688a) by Timothée Mazzucotelli).
## [0.1.0](https://github.com/pawamoy/markdown-exec/releases/tag/0.1.0) - 2022-02-19
[Compare with first commit](https://github.com/pawamoy/markdown-exec/compare/41c8d81992d2443cd5c3418df0f461b0af1a6ec8...0.1.0)
### Features
- Implement execution of code blocks ([41c8d81](https://github.com/pawamoy/markdown-exec/commit/41c8d81992d2443cd5c3418df0f461b0af1a6ec8) by Timothée Mazzucotelli).
markdown-exec-1.9.2/CODE_OF_CONDUCT.md 0000664 0000000 0000000 00000012550 14635002517 0017074 0 ustar 00root root 0000000 0000000 # Contributor Covenant Code of Conduct
## Our Pledge
We as members, contributors, and leaders pledge to make participation in our
community a harassment-free experience for everyone, regardless of age, body
size, visible or invisible disability, ethnicity, sex characteristics, gender
identity and expression, level of experience, education, socio-economic status,
nationality, personal appearance, race, caste, color, religion, or sexual
identity and orientation.
We pledge to act and interact in ways that contribute to an open, welcoming,
diverse, inclusive, and healthy community.
## Our Standards
Examples of behavior that contributes to a positive environment for our
community include:
* Demonstrating empathy and kindness toward other people
* Being respectful of differing opinions, viewpoints, and experiences
* Giving and gracefully accepting constructive feedback
* Accepting responsibility and apologizing to those affected by our mistakes,
and learning from the experience
* Focusing on what is best not just for us as individuals, but for the overall
community
Examples of unacceptable behavior include:
* The use of sexualized language or imagery, and sexual attention or advances of
any kind
* Trolling, insulting or derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or email address,
without their explicit permission
* Other conduct which could reasonably be considered inappropriate in a
professional setting
## Enforcement Responsibilities
Community leaders are responsible for clarifying and enforcing our standards of
acceptable behavior and will take appropriate and fair corrective action in
response to any behavior that they deem inappropriate, threatening, offensive,
or harmful.
Community leaders have the right and responsibility to remove, edit, or reject
comments, commits, code, wiki edits, issues, and other contributions that are
not aligned to this Code of Conduct, and will communicate reasons for moderation
decisions when appropriate.
## Scope
This Code of Conduct applies within all community spaces, and also applies when
an individual is officially representing the community in public spaces.
Examples of representing our community include using an official e-mail address,
posting via an official social media account, or acting as an appointed
representative at an online or offline event.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported to the community leaders responsible for enforcement at
dev@pawamoy.fr.
All complaints will be reviewed and investigated promptly and fairly.
All community leaders are obligated to respect the privacy and security of the
reporter of any incident.
## Enforcement Guidelines
Community leaders will follow these Community Impact Guidelines in determining
the consequences for any action they deem in violation of this Code of Conduct:
### 1. Correction
**Community Impact**: Use of inappropriate language or other behavior deemed
unprofessional or unwelcome in the community.
**Consequence**: A private, written warning from community leaders, providing
clarity around the nature of the violation and an explanation of why the
behavior was inappropriate. A public apology may be requested.
### 2. Warning
**Community Impact**: A violation through a single incident or series of
actions.
**Consequence**: A warning with consequences for continued behavior. No
interaction with the people involved, including unsolicited interaction with
those enforcing the Code of Conduct, for a specified period of time. This
includes avoiding interactions in community spaces as well as external channels
like social media. Violating these terms may lead to a temporary or permanent
ban.
### 3. Temporary Ban
**Community Impact**: A serious violation of community standards, including
sustained inappropriate behavior.
**Consequence**: A temporary ban from any sort of interaction or public
communication with the community for a specified period of time. No public or
private interaction with the people involved, including unsolicited interaction
with those enforcing the Code of Conduct, is allowed during this period.
Violating these terms may lead to a permanent ban.
### 4. Permanent Ban
**Community Impact**: Demonstrating a pattern of violation of community
standards, including sustained inappropriate behavior, harassment of an
individual, or aggression toward or disparagement of classes of individuals.
**Consequence**: A permanent ban from any sort of public interaction within the
community.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
version 2.1, available at
[https://www.contributor-covenant.org/version/2/1/code_of_conduct.html][v2.1].
Community Impact Guidelines were inspired by
[Mozilla's code of conduct enforcement ladder][Mozilla CoC].
For answers to common questions about this code of conduct, see the FAQ at
[https://www.contributor-covenant.org/faq][FAQ]. Translations are available at
[https://www.contributor-covenant.org/translations][translations].
[homepage]: https://www.contributor-covenant.org
[v2.1]: https://www.contributor-covenant.org/version/2/1/code_of_conduct.html
[Mozilla CoC]: https://github.com/mozilla/diversity
[FAQ]: https://www.contributor-covenant.org/faq
[translations]: https://www.contributor-covenant.org/translations
markdown-exec-1.9.2/CONTRIBUTING.md 0000664 0000000 0000000 00000010233 14635002517 0016522 0 ustar 00root root 0000000 0000000 # Contributing
Contributions are welcome, and they are greatly appreciated!
Every little bit helps, and credit will always be given.
## Environment setup
Nothing easier!
Fork and clone the repository, then:
```bash
cd markdown-exec
make setup
```
> NOTE:
> If it fails for some reason,
> you'll need to install
> [uv](https://github.com/astral-sh/uv)
> manually.
>
> You can install it with:
>
> ```bash
> python3 -m pip install --user pipx
> pipx install uv
> ```
>
> Now you can try running `make setup` again,
> or simply `uv install`.
You now have the dependencies installed.
Run `make help` to see all the available actions!
## Tasks
This project uses [duty](https://github.com/pawamoy/duty) to run tasks.
A Makefile is also provided. The Makefile will try to run certain tasks
on multiple Python versions. If for some reason you don't want to run the task
on multiple Python versions, you run the task directly with `make run duty TASK`.
The Makefile detects if a virtual environment is activated,
so `make` will work the same with the virtualenv activated or not.
If you work in VSCode, we provide
[an action to configure VSCode](https://pawamoy.github.io/copier-uv/work/#vscode-setup)
for the project.
## Development
As usual:
1. create a new branch: `git switch -c feature-or-bugfix-name`
1. edit the code and/or the documentation
**Before committing:**
1. run `make format` to auto-format the code
1. run `make check` to check everything (fix any warning)
1. run `make test` to run the tests (fix any issue)
1. if you updated the documentation or the project dependencies:
1. run `make docs`
1. go to http://localhost:8000 and check that everything looks good
1. follow our [commit message convention](#commit-message-convention)
If you are unsure about how to fix or ignore a warning,
just let the continuous integration fail,
and we will help you during review.
Don't bother updating the changelog, we will take care of this.
## Commit message convention
Commit messages must follow our convention based on the
[Angular style](https://gist.github.com/stephenparish/9941e89d80e2bc58a153#format-of-the-commit-message)
or the [Karma convention](https://karma-runner.github.io/4.0/dev/git-commit-msg.html):
```
`
sponsors.forEach(function (sponsor) {
html += `
/ Bold! Bold! **Bold!**\n Bold! **Bold!**\n
If you sponsor publicly, you're automatically added here with a link to
your profile and avatar to show your support for *Markdown Exec*.
Alternatively, if you wish to keep your sponsorship private, you'll be a
silent +1. You can select visibility during checkout and change it
afterwards.
## Funding
### Goals
The following section lists all funding goals. Each goal contains a list of
features prefixed with a checkmark symbol, denoting whether a feature is
:octicons-check-circle-fill-24:{ style="color: #00e676" } already available or
:octicons-check-circle-fill-24:{ style="color: var(--md-default-fg-color--lightest)" } planned,
but not yet implemented. When the funding goal is hit,
the features are released for general availability.
```python exec="1" session="insiders" idprefix=""
for goal in goals.values():
if not goal.complete:
goal.render()
```
### Goals completed
This section lists all funding goals that were previously completed, which means
that those features were part of Insiders, but are now generally available and
can be used by all users.
```python exec="1" session="insiders" idprefix=""
for goal in goals.values():
if goal.complete:
goal.render()
```
## Frequently asked questions
### Compatibility
> We're building an open source project and want to allow outside collaborators
to use *Markdown Exec* locally without having access to Insiders.
Is this still possible?
Yes. Insiders is compatible with *Markdown Exec*. Almost all new features
and configuration options are either backward-compatible or implemented behind
feature flags. Most Insiders features enhance the overall experience,
though while these features add value for the users of your project, they
shouldn't be necessary for previewing when making changes to content.
### Payment
> We don't want to pay for sponsorship every month. Are there any other options?
Yes. You can sponsor on a yearly basis by [switching your GitHub account to a
yearly billing cycle][billing cycle]. If for some reason you cannot do that, you
could also create a dedicated GitHub account with a yearly billing cycle, which
you only use for sponsoring (some sponsors already do that).
If you have any problems or further questions, please reach out to insiders@pawamoy.fr.
### Terms
> Are we allowed to use Insiders under the same terms and conditions as
*Markdown Exec*?
Yes. Whether you're an individual or a company, you may use *Markdown Exec
Insiders* precisely under the same terms as *Markdown Exec*, which are given
by the [ISC License][license]. However, we kindly ask you to respect our
**fair use policy**:
- Please **don't distribute the source code** of Insiders. You may freely use
it for public, private or commercial projects, privately fork or mirror it,
but please don't make the source code public, as it would counteract the
sponsorware strategy.
- If you cancel your subscription, you're automatically removed as a
collaborator and will miss out on all future updates of Insiders. However, you
may **use the latest version** that's available to you **as long as you like**.
Just remember that [GitHub deletes private forks][private forks].
[insiders]: #what-is-insiders
[sponsorship]: #what-sponsorships-achieve
[sponsors]: #how-to-become-a-sponsor
[features]: #whats-in-it-for-me
[funding]: #funding
[goals completed]: #goals-completed
[github sponsor profile]: https://github.com/sponsors/pawamoy
[billing cycle]: https://docs.github.com/en/github/setting-up-and-managing-billing-and-payments-on-github/changing-the-duration-of-your-billing-cycle
[license]: ../license.md
[private forks]: https://docs.github.com/en/github/setting-up-and-managing-your-github-user-account/removing-a-collaborator-from-a-personal-repository
markdown-exec-1.9.2/docs/insiders/installation.md 0000664 0000000 0000000 00000005653 14635002517 0022076 0 ustar 00root root 0000000 0000000 ---
title: Getting started with Insiders
---
# Getting started with Insiders
*Markdown Exec Insiders* is a compatible drop-in replacement for *Markdown Exec*,
and can be installed similarly using `pip` or `git`.
Note that in order to access the Insiders repository,
you need to [become an eligible sponsor] of @pawamoy on GitHub.
[become an eligible sponsor]: index.md#how-to-become-a-sponsor
## Installation
### with PyPI Insiders
[PyPI Insiders](https://pawamoy.github.io/pypi-insiders/)
is a tool that helps you keep up-to-date versions
of Insiders projects in the PyPI index of your choice
(self-hosted, Google registry, Artifactory, etc.).
See [how to install it](https://pawamoy.github.io/pypi-insiders/#installation)
and [how to use it](https://pawamoy.github.io/pypi-insiders/#usage).
**We kindly ask that you do not upload the distributions to public registries,
as it is against our [Terms of use](index.md#terms).**
### with pip (ssh/https)
*Markdown Exec Insiders* can be installed with `pip` [using SSH][using ssh]:
```bash
pip install git+ssh://git@github.com/pawamoy-insiders/markdown-exec.git
```
[using ssh]: https://docs.github.com/en/authentication/connecting-to-github-with-ssh
Or using HTTPS:
```bash
pip install git+https://${GH_TOKEN}@github.com/pawamoy-insiders/markdown-exec.git
```
>? NOTE: **How to get a GitHub personal access token**
> The `GH_TOKEN` environment variable is a GitHub token.
> It can be obtained by creating a [personal access token] for
> your GitHub account. It will give you access to the Insiders repository,
> programmatically, from the command line or GitHub Actions workflows:
>
> 1. Go to https://github.com/settings/tokens
> 2. Click on [Generate a new token]
> 3. Enter a name and select the [`repo`][scopes] scope
> 4. Generate the token and store it in a safe place
>
> [personal access token]: https://docs.github.com/en/github/authenticating-to-github/creating-a-personal-access-token
> [Generate a new token]: https://github.com/settings/tokens/new
> [scopes]: https://docs.github.com/en/developers/apps/scopes-for-oauth-apps#available-scopes
>
> Note that the personal access
> token must be kept secret at all times, as it allows the owner to access your
> private repositories.
### with Git
Of course, you can use *Markdown Exec Insiders* directly using Git:
```
git clone git@github.com:pawamoy-insiders/markdown-exec
```
When cloning with Git, the package must be installed:
```
pip install -e markdown-exec
```
## Upgrading
When upgrading Insiders, you should always check the version of *Markdown Exec*
which makes up the first part of the version qualifier. For example, a version like
`8.x.x.4.x.x` means that Insiders `4.x.x` is currently based on `8.x.x`.
If the major version increased, it's a good idea to consult the [changelog]
and go through the steps to ensure your configuration is up to date and
all necessary changes have been made.
[changelog]: ./changelog.md
markdown-exec-1.9.2/docs/js/ 0000775 0000000 0000000 00000000000 14635002517 0015636 5 ustar 00root root 0000000 0000000 markdown-exec-1.9.2/docs/js/insiders.js 0000664 0000000 0000000 00000005473 14635002517 0020025 0 ustar 00root root 0000000 0000000 function humanReadableAmount(amount) {
const strAmount = String(amount);
if (strAmount.length >= 4) {
return `${strAmount.slice(0, strAmount.length - 3)},${strAmount.slice(-3)}`;
}
return strAmount;
}
function getJSON(url, callback) {
var xhr = new XMLHttpRequest();
xhr.open('GET', url, true);
xhr.responseType = 'json';
xhr.onload = function () {
var status = xhr.status;
if (status === 200) {
callback(null, xhr.response);
} else {
callback(status, xhr.response);
}
};
xhr.send();
}
function updatePremiumSponsors(dataURL, rank) {
let capRank = rank.charAt(0).toUpperCase() + rank.slice(1);
getJSON(dataURL + `/sponsors${capRank}.json`, function (err, sponsors) {
const sponsorsDiv = document.getElementById(`${rank}-sponsors`);
if (sponsors.length > 0) {
let html = '';
html += `${capRank} sponsors
`
});
html += '
`;
});
if (privateSponsors > 0) {
sponsorsElem.innerHTML += `
+${privateSponsors}
`;
}
});
});
updatePremiumSponsors(dataURL, "gold");
updatePremiumSponsors(dataURL, "silver");
updatePremiumSponsors(dataURL, "bronze");
}
markdown-exec-1.9.2/docs/license.md 0000664 0000000 0000000 00000000044 14635002517 0017164 0 ustar 00root root 0000000 0000000 # License
```
--8<-- "LICENSE"
```
markdown-exec-1.9.2/docs/schema.json 0000664 0000000 0000000 00000001470 14635002517 0017357 0 ustar 00root root 0000000 0000000 {
"$schema": "https://json-schema.org/draft-07/schema",
"title": "Utilities to execute code blocks in Markdown files.nto your site.",
"oneOf": [
{
"markdownDescription": "https://pawamoy.github.io/markdown-exec",
"enum": [
"markdown-exec"
]
},
{
"type": "object",
"properties": {
"markdown-exec": {
"markdownDescription": "https://pawamoy.github.io/markdown-exec",
"type": "object",
"properties": {
"languages": {
"title": "The languages to enabled execution for.",
"type": "array",
"items": {
"type": "string"
}
}
},
"additionalProperties": false
}
},
"additionalProperties": false
}
]
} markdown-exec-1.9.2/docs/snippets/ 0000775 0000000 0000000 00000000000 14635002517 0017067 5 ustar 00root root 0000000 0000000 markdown-exec-1.9.2/docs/snippets/gallery/ 0000775 0000000 0000000 00000000000 14635002517 0020526 5 ustar 00root root 0000000 0000000 markdown-exec-1.9.2/docs/snippets/gallery/ansi.sh 0000664 0000000 0000000 00000001052 14635002517 0022012 0 ustar 00root root 0000000 0000000 #!/bin/bash
# credits to https://github.com/42picky/42picky.github.io
text="xYz" # Some test text
echo -e "\n 40m 41m 42m 43m 44m 45m 46m 47m"
for FGs in ' m' ' 1m' ' 30m' '1;30m' ' 31m' '1;31m' ' 32m' \
'1;32m' ' 33m' '1;33m' ' 34m' '1;34m' ' 35m' '1;35m' \
' 36m' '1;36m' ' 37m' '1;37m'; do
FG=${FGs// /}
echo -en " $FGs \033[$FG ${text} "
for BG in 40m 41m 42m 43m 44m 45m 46m 47m; do
echo -en "$EINS \033[$FG\033[${BG} ${text} \033[0m"
done
echo
done
echo markdown-exec-1.9.2/docs/snippets/gallery/argparse.py 0000664 0000000 0000000 00000001132 14635002517 0022701 0 ustar 00root root 0000000 0000000 import argparse
from duty.cli import get_parser
parser = get_parser()
lines = []
lines.append(f"## duty")
if parser.description:
lines.append(parser.description)
lines.append("\nOptions:\n")
for action in parser._actions:
opts = [f"`{opt}`" for opt in action.option_strings]
if not opts:
continue
line = "- " + ",".join(opts)
if action.metavar:
line += f" `{action.metavar}`"
line += f": {action.help}"
if action.default and action.default != argparse.SUPPRESS:
line += f"(default: {action.default})"
lines.append(line)
print("\n".join(lines))
markdown-exec-1.9.2/docs/snippets/gallery/argparse_format.py 0000664 0000000 0000000 00000000142 14635002517 0024251 0 ustar 00root root 0000000 0000000 from duty.cli import get_parser
parser = get_parser()
print(f"```\n{parser.format_help()}\n```")
markdown-exec-1.9.2/docs/snippets/gallery/chalk.py 0000664 0000000 0000000 00000001175 14635002517 0022166 0 ustar 00root root 0000000 0000000 from tempfile import NamedTemporaryFile
from chalk import Diagram, triangle, unit_x
from colour import Color
papaya = Color("#ff9700")
def sierpinski(n: int, size: int) -> Diagram:
if n <= 1:
return triangle(size)
else:
smaller = sierpinski(n - 1, size / 2)
return smaller.above(smaller.beside(smaller, unit_x).center_xy())
d = sierpinski(5, 4).fill_color(papaya)
# Chalk doesn't provide an easy method to get a string directly,
# so we use a temporary file.
with NamedTemporaryFile("w+") as tmpfile:
d.render_svg(tmpfile.name, height=256)
tmpfile.seek(0)
svg = tmpfile.read()
print(svg)
markdown-exec-1.9.2/docs/snippets/gallery/d2.py 0000664 0000000 0000000 00000002366 14635002517 0021414 0 ustar 00root root 0000000 0000000 import os # markdown-exec: hide
if "CI" in os.environ: # markdown-exec: hide
print("D2 is not installed in CI, skipping this gallery example.") # markdown-exec: hide
raise SystemExit(0) # markdown-exec: hide
import subprocess
diagram = """
direction: right
Before and after becoming friends: {
2007: Office chatter in 2007 {
shape: sequence_diagram
alice: Alice
bob: Bobby
awkward small talk: {
alice -> bob: uhm, hi
bob -> alice: oh, hello
icebreaker attempt: {
alice -> bob: what did you have for lunch?
}
unfortunate outcome: {
bob -> alice: that's personal
}
}
}
2012: Office chatter in 2012 {
shape: sequence_diagram
alice: Alice
bob: Bobby
alice -> bob: Want to play with ChatGPT?
bob -> alice: Yes!
bob -> alice.play: Write a play...
alice.play -> bob.play: about 2 friends...
bob.play -> alice.play: who find love...
alice.play -> bob.play: in a sequence diagram
}
2007 -> 2012: Five\nyears\nlater
}
"""
# We simply run `d2` in a subprocess, passing it our diagram as input and capturing its output to print it.
svg = subprocess.check_output(["d2", "-", "-"], input=diagram, stderr=subprocess.DEVNULL, text=True)
print(svg)
markdown-exec-1.9.2/docs/snippets/gallery/diagrams.py 0000664 0000000 0000000 00000002444 14635002517 0022673 0 ustar 00root root 0000000 0000000 from base64 import b64encode
from contextlib import suppress
from diagrams import Diagram
from diagrams.k8s.clusterconfig import HPA
from diagrams.k8s.compute import Deployment, Pod, ReplicaSet
from diagrams.k8s.network import Ingress, Service
# By default, Diagrams tries to write the result on disk, so we prevent that by patching its `render` method,
# and by ignoring the `FileNotFoundError` that ensues.
#
# Then we use its internal `dot` object and its `pipe` method to store the diagram in a variable,
# as base64 encoded PNG data.
#
# Finally we output an HTML image with the base64 data.
# Using SVG is not possible here since Diagrams embeds actual, smaller PNG files in the result,
# files which are not automatically added to the final site.
with suppress(FileNotFoundError):
with Diagram("Exposed Pod with 3 Replicas", show=False) as diagram:
diagram.render = lambda: None
net = Ingress("domain.com") >> Service("svc")
net >> [Pod("pod1"), Pod("pod2"), Pod("pod3")] << ReplicaSet("rs") << Deployment("dp") << HPA("hpa")
png = b64encode(diagram.dot.pipe(format="png")).decode()
# Wrapping the image in a div prevents it from being wrapped in a paragraph,
# which would add unnecessary space around it.
print(f'
"))
markdown-exec-1.9.2/docs/snippets/gallery/runpy.py 0000664 0000000 0000000 00000000676 14635002517 0022266 0 ustar 00root root 0000000 0000000 import sys
import warnings
from contextlib import suppress
from io import StringIO
from runpy import run_module
old_argv = list(sys.argv)
sys.argv = ["mkdocs"]
old_stdout = sys.stdout
sys.stdout = StringIO()
warnings.filterwarnings("ignore", category=RuntimeWarning)
with suppress(SystemExit):
run_module("mkdocs", run_name="__main__")
output = sys.stdout.getvalue()
sys.stdout = old_stdout
sys.argv = old_argv
print(f"```\n{output}\n```")
markdown-exec-1.9.2/docs/snippets/gallery/textual.py 0000664 0000000 0000000 00000001132 14635002517 0022563 0 ustar 00root root 0000000 0000000 from textual.app import App, ComposeResult
from textual.widgets import Static
from textual._doc import take_svg_screenshot
class TextApp(App):
CSS = """
Screen {
background: darkblue;
color: white;
layout: vertical;
}
Static {
height: auto;
padding: 2;
border: heavy white;
background: #ffffff 30%;
content-align: center middle;
}
"""
def compose(self) -> ComposeResult:
yield Static("Hello")
yield Static("[b]World![/b]")
print(take_svg_screenshot(app=TextApp(), terminal_size=(80, 24)))
markdown-exec-1.9.2/docs/snippets/usage/ 0000775 0000000 0000000 00000000000 14635002517 0020173 5 ustar 00root root 0000000 0000000 markdown-exec-1.9.2/docs/snippets/usage/boolean_matrix.py 0000664 0000000 0000000 00000000244 14635002517 0023550 0 ustar 00root root 0000000 0000000 print()
print("a | b | a \\|\\| b")
print("--- | --- | ---")
for a in (True, False):
for b in (True, False):
print(f"{a} | {b} | {a or b}")
print()
markdown-exec-1.9.2/docs/snippets/usage/hide.py 0000664 0000000 0000000 00000000073 14635002517 0021456 0 ustar 00root root 0000000 0000000 print("Hello World!")
print("{code}
") # markdown-exec: hide
markdown-exec-1.9.2/docs/snippets/usage/multiple.pycon 0000664 0000000 0000000 00000000114 14635002517 0023074 0 ustar 00root root 0000000 0000000 >>> name = "Baron"
>>> print(name)
Baron
>>> age = "???"
>>> print(age)
???
markdown-exec-1.9.2/docs/snippets/usage/platform_html.py 0000664 0000000 0000000 00000000436 14635002517 0023420 0 ustar 00root root 0000000 0000000 import platform
print(
f"""
"""
)
markdown-exec-1.9.2/docs/snippets/usage/platform_md.py 0000664 0000000 0000000 00000000530 14635002517 0023047 0 ustar 00root root 0000000 0000000 import platform
from textwrap import dedent
print(
# we must dedent, otherwise Markdown
# will render it as a code block!
dedent(
f"""
- machine: `{platform.machine()}`
- version: `{platform.version()}`
- platform: `{platform.platform()}`
- system: `{platform.system()}`
"""
)
)
markdown-exec-1.9.2/docs/snippets/usage/source.py 0000664 0000000 0000000 00000000031 14635002517 0022037 0 ustar 00root root 0000000 0000000 print("I'm the result!")
markdown-exec-1.9.2/docs/snippets/usage/source.pycon 0000664 0000000 0000000 00000000063 14635002517 0022544 0 ustar 00root root 0000000 0000000 >>> print("I'm the result!")
I'm not the result...
markdown-exec-1.9.2/docs/usage/ 0000775 0000000 0000000 00000000000 14635002517 0016326 5 ustar 00root root 0000000 0000000 markdown-exec-1.9.2/docs/usage/index.md 0000664 0000000 0000000 00000034100 14635002517 0017755 0 ustar 00root root 0000000 0000000 # Usage
Once the extension is configured (see README/Overview),
you can execute code blocks by enabling the `exec` option:
````md
```python exec="on"
print("Hello Markdown!")
```
````
The `exec` option will be true for every possible value
except `0`, `no`, `off` and `false` (case insensitive).
To enable automatic execution of code blocks for specific languages
(without having to add the `exec="on"` option to your code blocks),
set the `MARKDOWN_EXEC_AUTO` environment variable:
```bash
MARKDOWN_EXEC_AUTO=python,bash
```
## Options summary
As the number of options grew over time,
we now provide this summary listing every option,
linking to their related documentation:
- [`exec`](#usage): The mother of all other options, enabling code execution.
- [`html`](#html-vs-markdown): Whether the output is alredady HTML, or needs to be converted from Markdown to HTML.
- [`id`](#handling-errors): Give an identifier to your code blocks to help
[debugging errors](#handling-errors), or to [prefix HTML ids](#html-ids).
- [`idprefix`](#html-ids): Change or remove the prefix in front of HTML ids/hrefs.
- [`result`](#wrap-result-in-a-code-block): Choose the syntax highlight of your code block output.
- [`returncode`](shell.md#expecting-a-non-zero-exit-code): Tell what return code is expected (shell code).
- [`session`](#sessions): Execute code blocks within a named session, reusing previously defined variables, etc..
- [`source`](#render-the-source-code-as-well): Render the source as well as the output.
- [`tabs`](#change-the-titles-of-tabs): When rendering the source using tabs, choose the tabs titles.
- [`width`](#change-the-console-width): Change the console width through the `COLUMNS` environment variable.
- [`workdir`](#change-the-working-directory): Change the working directory.
- [`title`](#additional-options): Title is a [Material for MkDocs][material] option.
- [`updatetoc`](#generated-headings-in-table-of-contents): Whether to update the Table of Contents with generated headings.
## HTML vs. Markdown
By default, Markdown Exec will render what you print as Markdown.
If you want to skip rendering, to inject HTML directly,
you can set the `html` option to true.
HTML Example:
````md exec="1" source="tabbed-left" tabs="Markdown|Rendered"
System information:
```python exec="true" html="true"
--8<-- "usage/platform_html.py"
```
````
Markdown Example:
````md exec="1" source="tabbed-left" tabs="Markdown|Rendered"
System information:
```python exec="true"
--8<-- "usage/platform_md.py"
```
````
## Generated headings in Table of Contents
If you are using Python Markdown's `toc` extension,
or writing docs with MkDocs, you will notice that the headings
you generated by executing a code block appear in the table of contents.
If you don't want those headings to appear in the ToC, you can use
the `updatetoc="no"` boolean option:
````md
```python exec="1" updatetoc="no"
print("# XL heading\n")
print("## L heading\n")
print("### M heading\n")
print("#### S heading\n")
```
````
## HTML ids
When your executed code blocks output Markdown,
this Markdown is rendered to HTML, and every HTML id
is automatically prefixed with `exec-N--`, where N
is an integer incremented with each code block.
To avoid breaking links, every `href` attribute
is also updated when relevant.
You can change this prefix, or completely remove it
with the `idprefix` option.
The following ids are not prefixed:
````md exec="1" source="material-block"
```python exec="1" idprefix="" updatetoc="no"
print("#### Commands")
print("\n[link to commands](#commands)")
```
````
The following ids are prefixed with `cli-`:
````md exec="1" source="material-block"
```python exec="1" idprefix="cli-" updatetoc="no"
print("#### Commands")
print("\n[link to commands](#commands)")
```
````
If `idprefix` is not specified, and `id` is specified,
then the id is used as prefix:
The following ids are prefixed with `super-cli-`:
````md exec="1" source="material-block"
```python exec="1" id="super-cli" updatetoc="no"
print("#### Commands")
print("\n[link to commands](#commands)")
```
````
## Render the source code as well
It's possible to render both the result of the executed code block
*and* the code block itself. For this, use the `source` option
with one of the following values:
- `above`: The source code will be rendered above the result.
- `below`: The source code will be rendered below the result.
- `material-block`: The source code and result will be wrapped in a nice-looking block
(only works with [Material for MkDocs][material],
and requires the [`md_in_html`][md_in_html] extension)
- `tabbed-left`: The source code and result will be rendered in tabs, in that order
(requires the [`pymdownx.tabbed`][pymdownx.tabbed] extension).
- `tabbed-right`: The result and source code will be rendered in tabs, in that order
(requires the [`pymdownx.tabbed`][pymdownx.tabbed] extension).
- `console`: The source and result are concatenated in a single code block, like an interactive console session.
**Source above:**
````md exec="1" source="tabbed-left" tabs="Markdown|Rendered"
```python exec="true" source="above"
--8<-- "usage/source.py"
```
````
---
**Source below:**
````md exec="1" source="tabbed-left" tabs="Markdown|Rendered"
```python exec="true" source="below"
--8<-- "usage/source.py"
```
````
---
**Material block:**
````md exec="1" source="tabbed-left" tabs="Markdown|Rendered"
```python exec="true" source="material-block"
--8<-- "usage/source.py"
```
````
NOTE: **Important**
The `material-block` source option requires that you enable the [`md_in_html`][md_in_html] Markdown extension.
---
**Tabbed on the left:**
````md exec="1" source="tabbed-left" tabs="Markdown|Rendered"
```python exec="true" source="tabbed-left"
--8<-- "usage/source.py"
```
````
NOTE: **Important**
The `tabbed-left` source option requires that you enable the [`pymdownx.tabbed`][pymdownx.tabbed] Markdown extension.
---
**Tabbed on the right:**
````md exec="1" source="tabbed-left" tabs="Markdown|Rendered"
```python exec="true" source="tabbed-right"
--8<-- "usage/source.py"
```
````
NOTE: **Important**
The `tabbed-left` source option requires that you enable the [`pymdownx.tabbed`][pymdownx.tabbed] Markdown extension.
---
**Console** (best used with actual session syntax like
[`pycon`](python.md#python-console-code) or [`console`](shell.md#console)):
````md exec="1" source="tabbed-left" tabs="Markdown|Rendered"
```pycon exec="true" source="console"
--8<-- "usage/source.pycon"
```
````
[md_in_html]: https://python-markdown.github.io/extensions/md_in_html/
[pymdownx.tabbed]: https://facelessuser.github.io/pymdown-extensions/extensions/tabbed/
## Hiding lines from the source
Every line that contains the string `markdown-exec: hide` will be hidden from the
displayed source.
=== "Markdown"
````md
```python exec="true" source="above"
--8<-- "usage/hide.py"
```
````
=== "Rendered"
```python exec="true" source="above"
--8<-- "usage/hide.py"
```
## Change the titles of tabs
In the previous example, we didn't specify any title for tabs,
so Markdown Exec used "Source" and "Result" by default.
You can customize the titles with the `tabs` option:
````md exec="1" source="tabbed-left" tabs="Markdown|Rendered"
```python exec="1" source="tabbed-left" tabs="Source code|Output"
--8<-- "usage/source.py"
```
````
As you can see, titles are separated with a pipe `|`. Both titles are stripped
so you can add space around the pipe. If you need to use that character in a title,
simply escape it with `\|`:
````md exec="1" source="tabbed-left" tabs="Markdown|Rendered"
```python exec="1" source="tabbed-left" tabs="OR operator: a \|\| b | Boolean matrix"
--8<-- "usage/boolean_matrix.py"
```
````
IMPORTANT: The `tabs` option ***always*** expects the "Source" tab title first,
and the "Result" tab title second. It allows to switch from tabbed-left
to tabbed-right and inversely without having to switch the titles as well.
WARNING: **Limitation**
Changing the title for only one tab is not supported.
## Wrap result in a code block
You can wrap the result in a code block by specifying a code block language:
````md exec="1" source="tabbed-left" tabs="Markdown|Rendered"
```console exec="1" result="ini"
$ cat .git/config
```
````
WARNING: **Limitation**
Wrapping the result is not possible when HTML output is enabled.
## Change the console width
To change the console width for the execution of a code block, use the `width` option.
Internally, Markdown Exec will set the `COLUMNS` environment variable accordingly,
and restore its previous value after execution.
If the executed code doesn't support this environment variable,
the default console width will be used (it could be the current width or some arbitrary value).
````md exec="1" source="tabbed-left"
```bash exec="1" width="10"
echo $COLUMNS
```
```bash exec="1" width="1000"
echo $COLUMNS
```
````
## Change the working directory
To change the working directory for the execution of a code block, use the `workdir` option.
````md exec="1" source="tabbed-left"
```bash exec="1"
pwd
```
```bash exec="1" workdir=".."
pwd
```
````
## Additional options
If you are using [Material for MkDocs][material],
you are probably familiar with the `title` option on code blocks:
````md
```python title="setup.py"
from setuptools import setup
setup(...)
```
````
Markdown Exec will add back these unrecognized options
when rendering the source, so you can keep using them normally.
Example:
````md exec="1" source="tabbed-left" tabs="Markdown|Rendered"
```python exec="1" source="above" title="source.py"
--8<-- "usage/source.py"
```
````
## Handling errors
Code blocks execution can fail.
For example, your Python code may raise exceptions,
or your shell code may return a non-zero exit code
(for shell commands that are expected to return non-zero,
see [Expecting a non-zero exit code](shell.md#expecting-a-non-zero-exit-code)).
In these cases, the exception and traceback (Python),
or the current output (shell) will be rendered
instead of the result, and a warning will be logged.
Example of failing code:
````md
```python exec="true"
print("hello")
assert 1 + 1 == 11
```
````
```text title="MkDocs output"
WARNING - markdown_exec: Execution of python code block exited with errors
```
```python title="Rendered traceback"
Traceback (most recent call last):
File "/path/to/markdown_exec/formatters/python.py", line 23, in _run_python
exec(code, exec_globals) # noqa: S102
File "{platform.machine()}
{platform.version()}
{platform.platform()}
{platform.system()}
%(initial_code)s
"
def _run_python(
code: str,
returncode: int | None = None, # noqa: ARG001
session: str | None = None,
id: str | None = None, # noqa: A002
**extra: str,
) -> str:
title = extra.get("title", None)
code_block_id = _code_block_id(id, session, title)
_code_blocks[code_block_id] = code.split("\n")
exec_globals = _sessions_globals[session] if session else {}
# Other libraries expect functions to have a valid `__module__` attribute.
# To achieve this, we need to add a `__name__` attribute to the globals.
# We compute the name from the code block ID, replacing invalid characters with `_`.
# We also create a module object with the same name and add it to `sys.modules`,
# because that's what yet other libraries expect (`dataclasses` for example).
module_name = re.sub(r"[^a-zA-Z\d]+", "_", code_block_id)
exec_globals["__name__"] = module_name
sys.modules[module_name] = ModuleType(module_name)
buffer = StringIO()
exec_globals["print"] = partial(_buffer_print, buffer)
try:
exec_python(code, code_block_id, exec_globals)
except Exception as error:
trace = traceback.TracebackException.from_exception(error)
for frame in trace.stack:
if frame.filename.startswith("
str:
return base_format(language="python", run=_run_python, **kwargs)
markdown-exec-1.9.2/src/markdown_exec/formatters/sh.py 0000664 0000000 0000000 00000001554 14635002517 0023066 0 ustar 00root root 0000000 0000000 """Formatter for executing shell code."""
from __future__ import annotations
import subprocess
from typing import Any
from markdown_exec.formatters.base import ExecutionError, base_format
from markdown_exec.rendering import code_block
def _run_sh(
code: str,
returncode: int | None = None,
session: str | None = None, # noqa: ARG001
id: str | None = None, # noqa: A002,ARG001
**extra: str,
) -> str:
process = subprocess.run(
["sh", "-c", code], # noqa: S603,S607
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
text=True,
check=False,
)
if process.returncode != returncode:
raise ExecutionError(code_block("sh", process.stdout, **extra), process.returncode)
return process.stdout
def _format_sh(**kwargs: Any) -> str:
return base_format(language="sh", run=_run_sh, **kwargs)
markdown-exec-1.9.2/src/markdown_exec/formatters/tree.py 0000664 0000000 0000000 00000003776 14635002517 0023423 0 ustar 00root root 0000000 0000000 """Formatter for file-system trees."""
from __future__ import annotations
from textwrap import dedent
from typing import TYPE_CHECKING, Any
from markdown_exec.rendering import MarkdownConverter, code_block
if TYPE_CHECKING:
from markdown import Markdown
def _rec_build_tree(lines: list[str], parent: list, offset: int, base_indent: int) -> int:
while offset < len(lines):
line = lines[offset]
lstripped = line.lstrip()
indent = len(line) - len(lstripped)
if indent == base_indent:
parent.append((lstripped, []))
offset += 1
elif indent > base_indent:
offset = _rec_build_tree(lines, parent[-1][1], offset, indent)
else:
return offset
return offset
def _build_tree(code: str) -> list[tuple[str, list]]:
lines = dedent(code.strip()).split("\n")
root_layer: list[tuple[str, list]] = []
_rec_build_tree(lines, root_layer, 0, 0)
return root_layer
def _rec_format_tree(tree: list[tuple[str, list]], *, root: bool = True) -> list[str]:
lines = []
n_items = len(tree)
for index, node in enumerate(tree):
last = index == n_items - 1
prefix = "" if root else f"{'└' if last else '├'}── "
if node[1]:
lines.append(f"{prefix}📁 {node[0]}")
sublines = _rec_format_tree(node[1], root=False)
if root:
lines.extend(sublines)
else:
indent_char = " " if last else "│"
lines.extend([f"{indent_char} {line}" for line in sublines])
else:
name = node[0].split()[0]
icon = "📁" if name.endswith("/") else "📄"
lines.append(f"{prefix}{icon} {node[0]}")
return lines
def _format_tree(code: str, md: Markdown, result: str, **options: Any) -> str:
markdown = MarkdownConverter(md)
output = "\n".join(_rec_format_tree(_build_tree(code)))
return markdown.convert(code_block(result or "bash", output, **options.get("extra", {})))
markdown-exec-1.9.2/src/markdown_exec/logger.py 0000664 0000000 0000000 00000004566 14635002517 0021553 0 ustar 00root root 0000000 0000000 """This module contains logging utilities.
We provide the [`patch_loggers`][markdown_exec.logger.patch_loggers]
function so dependant libraries can patch loggers as they see fit.
For example, to fit in the MkDocs logging configuration
and prefix each log message with the module name:
```python
import logging
from markdown_exec.logger import patch_loggers
class LoggerAdapter(logging.LoggerAdapter):
def __init__(self, prefix, logger):
super().__init__(logger, {})
self.prefix = prefix
def process(self, msg, kwargs):
return f"{self.prefix}: {msg}", kwargs
def get_logger(name):
logger = logging.getLogger(f"mkdocs.plugins.{name}")
return LoggerAdapter(name.split(".", 1)[0], logger)
patch_loggers(get_logger)
```
"""
from __future__ import annotations
import logging
from typing import Any, Callable, ClassVar
class _Logger:
_default_logger: Any = logging.getLogger
_instances: ClassVar[dict[str, _Logger]] = {}
# See same code in Griffe project.
def __init__(self, name: str) -> None:
# Default logger that can be patched by third-party.
self._logger = self.__class__._default_logger(name)
def __getattr__(self, name: str) -> Any:
# Forward everything to the logger.
return getattr(self._logger, name)
@classmethod
def get(cls, name: str) -> _Logger:
"""Get a logger instance.
Parameters:
name: The logger name.
Returns:
The logger instance.
"""
if name not in cls._instances:
cls._instances[name] = cls(name)
return cls._instances[name]
@classmethod
def _patch_loggers(cls, get_logger_func: Callable) -> None:
# Patch current instances.
for name, instance in cls._instances.items():
instance._logger = get_logger_func(name)
# Future instances will be patched as well.
cls._default_logger = get_logger_func
def get_logger(name: str) -> _Logger:
"""Create and return a new logger instance.
Parameters:
name: The logger name.
Returns:
The logger.
"""
return _Logger.get(name)
def patch_loggers(get_logger_func: Callable[[str], Any]) -> None:
"""Patch loggers.
Parameters:
get_logger_func: A function accepting a name as parameter and returning a logger.
"""
_Logger._patch_loggers(get_logger_func)
markdown-exec-1.9.2/src/markdown_exec/mkdocs_plugin.py 0000664 0000000 0000000 00000012253 14635002517 0023122 0 ustar 00root root 0000000 0000000 """This module contains an optional plugin for MkDocs."""
from __future__ import annotations
import logging
import os
from pathlib import Path
from typing import TYPE_CHECKING, Any, MutableMapping
from mkdocs.config import config_options
from mkdocs.config.base import Config
from mkdocs.exceptions import PluginError
from mkdocs.plugins import BasePlugin
from mkdocs.utils import write_file
from markdown_exec import formatter, formatters, validator
from markdown_exec.logger import patch_loggers
from markdown_exec.rendering import MarkdownConverter, markdown_config
if TYPE_CHECKING:
from jinja2 import Environment
from mkdocs.config.defaults import MkDocsConfig
from mkdocs.structure.files import Files
try:
__import__("pygments_ansi_color")
except ImportError:
ansi_ok = False
else:
ansi_ok = True
class _LoggerAdapter(logging.LoggerAdapter):
def __init__(self, prefix: str, logger: logging.Logger) -> None:
super().__init__(logger, {})
self.prefix = prefix
def process(self, msg: str, kwargs: MutableMapping[str, Any]) -> tuple[str, MutableMapping[str, Any]]:
return f"{self.prefix}: {msg}", kwargs
def _get_logger(name: str) -> _LoggerAdapter:
logger = logging.getLogger(f"mkdocs.plugins.{name}")
return _LoggerAdapter(name.split(".", 1)[0], logger)
patch_loggers(_get_logger)
class MarkdownExecPluginConfig(Config):
"""Configuration of the plugin (for `mkdocs.yml`)."""
ansi = config_options.Choice(("auto", "off", "required", True, False), default="auto")
"""Whether the `ansi` extra is required when installing the package."""
languages = config_options.ListOfItems(
config_options.Choice(formatters.keys()),
default=list(formatters.keys()),
)
"""Which languages to enabled the extension for."""
class MarkdownExecPlugin(BasePlugin[MarkdownExecPluginConfig]):
"""MkDocs plugin to easily enable custom fences for code blocks execution."""
def on_config(self, config: MkDocsConfig) -> MkDocsConfig | None:
"""Configure the plugin.
Hook for the [`on_config` event](https://www.mkdocs.org/user-guide/plugins/#on_config).
In this hook, we add custom fences for all the supported languages.
We also save the Markdown extensions configuration
into [`markdown_config`][markdown_exec.rendering.markdown_config].
Arguments:
config: The MkDocs config object.
Returns:
The modified config.
"""
if "pymdownx.superfences" not in config["markdown_extensions"]:
message = "The 'markdown-exec' plugin requires the 'pymdownx.superfences' Markdown extension to work."
raise PluginError(message)
if self.config.ansi in ("required", True) and not ansi_ok:
raise PluginError(
"The configuration for the 'markdown-exec' plugin requires "
"that it is installed with the 'ansi' extra. "
"Install it with 'pip install markdown-exec[ansi]'.",
)
self.mkdocs_config_dir = os.getenv("MKDOCS_CONFIG_DIR")
os.environ["MKDOCS_CONFIG_DIR"] = os.path.dirname(config["config_file_path"])
self.languages = self.config.languages
mdx_configs = config.setdefault("mdx_configs", {})
superfences = mdx_configs.setdefault("pymdownx.superfences", {})
custom_fences = superfences.setdefault("custom_fences", [])
for language in self.languages:
custom_fences.append(
{
"name": language,
"class": language,
"validator": validator,
"format": formatter,
},
)
markdown_config.save(config.markdown_extensions, config.mdx_configs)
return config
def on_env( # noqa: D102
self,
env: Environment,
*,
config: MkDocsConfig,
files: Files, # noqa: ARG002
) -> Environment | None:
if self.config.ansi in ("required", True) or (self.config.ansi == "auto" and ansi_ok):
self._add_css(config, "ansi.css")
if "pyodide" in self.languages:
self._add_css(config, "pyodide.css")
self._add_js(config, "pyodide.js")
return env
def on_post_build(self, *, config: MkDocsConfig) -> None: # noqa: ARG002,D102
MarkdownConverter.counter = 0
markdown_config.reset()
if self.mkdocs_config_dir is None:
os.environ.pop("MKDOCS_CONFIG_DIR", None)
else:
os.environ["MKDOCS_CONFIG_DIR"] = self.mkdocs_config_dir
def _add_asset(self, config: MkDocsConfig, asset_file: str, asset_type: str) -> None:
asset_filename = f"assets/_markdown_exec_{asset_file}"
asset_content = Path(__file__).parent.joinpath(asset_file).read_text()
write_file(asset_content.encode("utf-8"), os.path.join(config.site_dir, asset_filename))
config[f"extra_{asset_type}"].insert(0, asset_filename)
def _add_css(self, config: MkDocsConfig, css_file: str) -> None:
self._add_asset(config, css_file, "css")
def _add_js(self, config: MkDocsConfig, js_file: str) -> None:
self._add_asset(config, js_file, "javascript")
markdown-exec-1.9.2/src/markdown_exec/processors.py 0000664 0000000 0000000 00000010473 14635002517 0022470 0 ustar 00root root 0000000 0000000 """This module contains a Markdown extension allowing to integrate generated headings into the ToC."""
from __future__ import annotations
import copy
import re
from typing import TYPE_CHECKING
from xml.etree.ElementTree import Element
from markdown.treeprocessors import Treeprocessor
from markdown.util import HTML_PLACEHOLDER_RE
if TYPE_CHECKING:
from markdown import Markdown
from markupsafe import Markup
# code taken from mkdocstrings, credits to @oprypin
class IdPrependingTreeprocessor(Treeprocessor):
"""Prepend the configured prefix to IDs of all HTML elements."""
name = "markdown_exec_ids"
def __init__(self, md: Markdown, id_prefix: str) -> None: # noqa: D107
super().__init__(md)
self.id_prefix = id_prefix
def run(self, root: Element) -> None: # noqa: D102
if not self.id_prefix:
return
for el in root.iter():
id_attr = el.get("id")
if id_attr:
el.set("id", self.id_prefix + id_attr)
href_attr = el.get("href")
if href_attr and href_attr.startswith("#"):
el.set("href", "#" + self.id_prefix + href_attr[1:])
name_attr = el.get("name")
if name_attr:
el.set("name", self.id_prefix + name_attr)
if el.tag == "label":
for_attr = el.get("for")
if for_attr:
el.set("for", self.id_prefix + for_attr)
# code taken from mkdocstrings, credits to @oprypin
class HeadingReportingTreeprocessor(Treeprocessor):
"""Records the heading elements encountered in the document."""
name = "markdown_exec_record_headings"
regex = re.compile("[Hh][1-6]")
def __init__(self, md: Markdown, headings: list[Element]): # noqa: D107
super().__init__(md)
self.headings = headings
def run(self, root: Element) -> None: # noqa: D102
for el in root.iter():
if self.regex.fullmatch(el.tag):
el = copy.copy(el) # noqa: PLW2901
# 'toc' extension's first pass (which we require to build heading stubs/ids) also edits the HTML.
# Undo the permalink edit so we can pass this heading to the outer pass of the 'toc' extension.
if len(el) > 0 and el[-1].get("class") == self.md.treeprocessors["toc"].permalink_class: # type: ignore[attr-defined]
del el[-1]
self.headings.append(el)
class InsertHeadings(Treeprocessor):
"""Our headings insertor."""
name = "markdown_exec_insert_headings"
def __init__(self, md: Markdown):
"""Initialize the object.
Arguments:
md: A `markdown.Markdown` instance.
"""
super().__init__(md)
self.headings: dict[Markup, list[Element]] = {}
def run(self, root: Element) -> None: # noqa: D102 (ignore missing docstring)
if not self.headings:
return
for el in root.iter():
match = HTML_PLACEHOLDER_RE.match(el.text or "")
if match:
counter = int(match.group(1))
markup: Markup = self.md.htmlStash.rawHtmlBlocks[counter] # type: ignore[assignment]
if headings := self.headings.get(markup):
div = Element("div", {"class": "markdown-exec"})
div.extend(headings)
el.append(div)
class RemoveHeadings(Treeprocessor):
"""Our headings remover."""
name = "markdown_exec_remove_headings"
def run(self, root: Element) -> None: # noqa: D102
self._remove_duplicated_headings(root)
def _remove_duplicated_headings(self, parent: Element) -> None:
carry_text = ""
for el in reversed(parent): # Reversed mainly for the ability to mutate during iteration.
if el.tag == "div" and el.get("class") == "markdown-exec":
# Delete the duplicated headings along with their container, but keep the text (i.e. the actual HTML).
carry_text = (el.text or "") + carry_text
parent.remove(el)
else:
if carry_text:
el.tail = (el.tail or "") + carry_text
carry_text = ""
self._remove_duplicated_headings(el)
if carry_text:
parent.text = (parent.text or "") + carry_text
markdown-exec-1.9.2/src/markdown_exec/py.typed 0000664 0000000 0000000 00000000000 14635002517 0021374 0 ustar 00root root 0000000 0000000 markdown-exec-1.9.2/src/markdown_exec/pyodide.css 0000664 0000000 0000000 00000001547 14635002517 0022065 0 ustar 00root root 0000000 0000000 html[data-theme="light"] {
@import "https://cdn.jsdelivr.net/npm/highlightjs-themes@1.0.0/tomorrow.css"
}
html[data-theme="dark"] {
@import "https://cdn.jsdelivr.net/npm/highlightjs-themes@1.0.0/tomorrow-night-blue.min.css"
}
.ace_gutter {
z-index: 1;
}
.pyodide-editor {
width: 100%;
min-height: 200px;
max-height: 400px;
font-size: .85em;
}
.pyodide-editor-bar {
color: var(--md-primary-bg-color);
background-color: var(--md-primary-fg-color);
width: 100%;
font: monospace;
font-size: 0.75em;
padding: 2px 0 2px;
}
.pyodide-bar-item {
padding: 0 18px 0;
display: inline-block;
width: 50%;
}
.pyodide pre {
margin: 0;
}
.pyodide-output {
width: 100%;
margin-bottom: -15px;
min-height: 46px;
max-height: 400px
}
.pyodide-clickable {
cursor: pointer;
text-align: right;
} markdown-exec-1.9.2/src/markdown_exec/pyodide.js 0000664 0000000 0000000 00000007405 14635002517 0021710 0 ustar 00root root 0000000 0000000 var _sessions = {};
function getSession(name, pyodide) {
if (!(name in _sessions)) {
_sessions[name] = pyodide.globals.get("dict")();
}
return _sessions[name];
}
function writeOutput(element, string) {
element.innerHTML += string + '\n';
}
function clearOutput(element) {
element.innerHTML = '';
}
async function evaluatePython(pyodide, editor, output, session) {
pyodide.setStdout({ batched: (string) => { writeOutput(output, string); } });
let result, code = editor.getValue();
clearOutput(output);
try {
result = await pyodide.runPythonAsync(code, { globals: getSession(session, pyodide) });
} catch (error) {
writeOutput(output, error);
}
if (result) writeOutput(output, result);
hljs.highlightElement(output);
}
async function initPyodide() {
try {
let pyodide = await loadPyodide();
await pyodide.loadPackage("micropip");
return pyodide;
} catch(error) {
return null;
}
}
function getTheme() {
return document.body.getAttribute('data-md-color-scheme');
}
function setTheme(editor, currentTheme, light, dark) {
// https://gist.github.com/RyanNutt/cb8d60997d97905f0b2aea6c3b5c8ee0
if (currentTheme === "default") {
editor.setTheme("ace/theme/" + light);
document.querySelector(`link[title="light"]`).removeAttribute("disabled");
document.querySelector(`link[title="dark"]`).setAttribute("disabled", "disabled");
} else if (currentTheme === "slate") {
editor.setTheme("ace/theme/" + dark);
document.querySelector(`link[title="dark"]`).removeAttribute("disabled");
document.querySelector(`link[title="light"]`).setAttribute("disabled", "disabled");
}
}
function updateTheme(editor, light, dark) {
// Create a new MutationObserver instance
const observer = new MutationObserver((mutations) => {
// Loop through the mutations that occurred
mutations.forEach((mutation) => {
// Check if the mutation was a change to the data-md-color-scheme attribute
if (mutation.attributeName === 'data-md-color-scheme') {
// Get the new value of the attribute
const newColorScheme = mutation.target.getAttribute('data-md-color-scheme');
// Update the editor theme
setTheme(editor, newColorScheme, light, dark);
}
});
});
// Configure the observer to watch for changes to the data-md-color-scheme attribute
observer.observe(document.body, {
attributes: true,
attributeFilter: ['data-md-color-scheme'],
});
}
async function setupPyodide(idPrefix, install = null, themeLight = 'tomorrow', themeDark = 'tomorrow_night', session = null) {
const editor = ace.edit(idPrefix + "editor");
const run = document.getElementById(idPrefix + "run");
const clear = document.getElementById(idPrefix + "clear");
const output = document.getElementById(idPrefix + "output");
updateTheme(editor, themeLight, themeDark);
editor.session.setMode("ace/mode/python");
setTheme(editor, getTheme(), themeLight, themeDark);
writeOutput(output, "Initializing...");
let pyodide = await pyodidePromise;
if (install && install.length) {
micropip = pyodide.pyimport("micropip");
for (const package of install)
await micropip.install(package);
}
clearOutput(output);
run.onclick = () => evaluatePython(pyodide, editor, output, session);
clear.onclick = () => clearOutput(output);
output.parentElement.parentElement.addEventListener("keydown", (event) => {
if (event.ctrlKey && event.key.toLowerCase() === 'enter') {
event.preventDefault();
run.click();
}
});
}
var pyodidePromise = initPyodide();
markdown-exec-1.9.2/src/markdown_exec/rendering.py 0000664 0000000 0000000 00000022363 14635002517 0022244 0 ustar 00root root 0000000 0000000 """Markdown extensions and helpers."""
from __future__ import annotations
from contextlib import contextmanager
from functools import lru_cache
from textwrap import indent
from typing import TYPE_CHECKING, Any, Iterator
from markdown import Markdown
from markupsafe import Markup
from markdown_exec.processors import (
HeadingReportingTreeprocessor,
IdPrependingTreeprocessor,
InsertHeadings,
RemoveHeadings,
)
if TYPE_CHECKING:
from xml.etree.ElementTree import Element
from markdown import Extension
def code_block(language: str, code: str, **options: str) -> str:
"""Format code as a code block.
Parameters:
language: The code block language.
code: The source code to format.
**options: Additional options passed from the source, to add back to the generated code block.
Returns:
The formatted code block.
"""
opts = " ".join(f'{opt_name}="{opt_value}"' for opt_name, opt_value in options.items())
return f"````````{language} {opts}\n{code}\n````````"
def tabbed(*tabs: tuple[str, str]) -> str:
"""Format tabs using `pymdownx.tabbed` extension.
Parameters:
*tabs: Tuples of strings: title and text.
Returns:
The formatted tabs.
"""
parts = []
for title, text in tabs:
title = title.replace(r"\|", "|").strip() # noqa: PLW2901
parts.append(f'=== "{title}"')
parts.append(indent(text, prefix=" " * 4))
parts.append("")
return "\n".join(parts)
def _hide_lines(source: str) -> str:
return "\n".join(line for line in source.split("\n") if "markdown-exec: hide" not in line).strip()
def add_source(
*,
source: str,
location: str,
output: str,
language: str,
tabs: tuple[str, str],
result: str = "",
**extra: str,
) -> str:
"""Add source code block to the output.
Parameters:
source: The source code block.
location: Where to add the source (above, below, tabbed-left, tabbed-right, console).
output: The current output.
language: The code language.
tabs: Tabs titles (if used).
result: Syntax to use when concatenating source and result with "console" location.
**extra: Extra options added back to source code block.
Raises:
ValueError: When the given location is not supported.
Returns:
The updated output.
"""
source = _hide_lines(source)
if location == "console":
return code_block(result or language, source + "\n" + output, **extra)
source_block = code_block(language, source, **extra)
if location == "above":
return source_block + "\n\n" + output
if location == "below":
return output + "\n\n" + source_block
if location == "material-block":
return source_block + f'\n\n
"
html = base_format(
language="whatever",
run=lambda code, **_: code,
code=code,
md=md,
html=True,
)
assert html == code
@pytest.mark.parametrize("html", [True, False])
def test_render_source(md: Markdown, html: bool) -> None:
"""Assert source is rendered.
Parameters:
md: A Markdown instance (fixture).
html: Whether output is HTML or not.
"""
markup = base_format(
language="python",
run=lambda code, **_: code,
code="hello",
md=md,
html=html,
source="tabbed-left",
)
assert "Source" in markup
def test_render_console_plus_ansi_result(md: Markdown) -> None:
"""Assert we can render source as console style with `ansi` highlight.
Parameters:
md: A Markdown instance (fixture).
"""
markup = base_format(
language="bash",
run=lambda code, **_: code,
code="echo -e '\033[31mhello'",
md=md,
html=False,
source="console",
result="ansi",
)
assert "hello
ansi" in markup
def test_dont_render_anything_if_output_is_empty(md: Markdown) -> None:
"""Assert nothing is rendered if output is empty.
Parameters:
md: A Markdown instance (fixture).
"""
markup = base_format(
language="bash",
run=lambda code, **_: "",
code="whatever",
md=md,
)
assert not markup
def test_render_source_even_if_output_is_empty(md: Markdown) -> None:
"""Assert source is rendered even if output is empty.
Parameters:
md: A Markdown instance (fixture).
"""
markup = base_format(
language="bash",
run=lambda code, **_: "",
code="whatever",
md=md,
source="tabbed-left",
)
assert "Source" in markup
def test_changing_working_directory(md: Markdown) -> None:
"""Assert we can change the working directory with `workdir`.
Parameters:
md: A Markdown instance (fixture).
"""
markup = base_format(
language="python",
run=lambda code, **_: subprocess.check_output(code, shell=True, text=True), # noqa: S602
code="pwd",
md=md,
workdir="/",
)
assert markup == "
Int
" not in html
assert re.search(r"class '_code_block_n\d+_\.Int'", html)
markdown-exec-1.9.2/tests/test_shell.py 0000664 0000000 0000000 00000003753 14635002517 0020164 0 ustar 00root root 0000000 0000000 """Tests for the shell formatters."""
from __future__ import annotations
from textwrap import dedent
from typing import TYPE_CHECKING
if TYPE_CHECKING:
import pytest
from markdown import Markdown
def test_output_markdown(md: Markdown) -> None:
"""Assert Markdown is converted to HTML.
Parameters:
md: A Markdown instance (fixture).
"""
html = md.convert(
dedent(
"""
```sh exec="yes"
echo "**Bold!**"
```
""",
),
)
assert html == " None:
"""Assert ToC is not updated with generated headings.
Parameters:
md: A Markdown instance (fixture).
"""
TocExtension().extendMarkdown(md)
html = md.convert(
dedent(
"""
```python exec="yes" updatetoc="no"
print("# big heading")
```
""",
),
)
assert "
None:
"""Assert ToC is not updated with generated headings.
Parameters:
md: A Markdown instance (fixture).
"""
TocExtension().extendMarkdown(md)
html = md.convert(
dedent(
"""
```python exec="yes" updatetoc="no"
print("# big heading")
```
```python exec="yes" updatetoc="yes"
print("## medium heading")
```
```python exec="yes" updatetoc="no"
print("### small heading")
```
```python exec="yes" updatetoc="yes"
print("#### tiny heading")
```
""",
),
)
assert "