Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .copier-answers.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
# Answer file maintained by Copier for: https://github.com/KyleKing/mdformat-plugin-template
# DO NOT MODIFY THIS FILE. Edit by re-running copier and changing responses to the questions
# Check into version control.
_commit: 2.1.2
_commit: 2.4.3
_src_path: gh:KyleKing/mdformat-plugin-template
author_email: [email protected]
author_name: Kyle King
Expand Down
68 changes: 30 additions & 38 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,74 +15,66 @@ jobs:
- name: Set up Python
uses: actions/setup-python@v6
with:
python-version: 3.12
python-version: 3.14
- uses: j178/prek-action@v1

tests:
runs-on: ${{ matrix.os }}
strategy:
matrix:
python-version: ["3.10", "3.12"]
python-version: ["3.10", "3.14"]
os: [ubuntu-latest, windows-latest]
steps:
- uses: actions/checkout@v5
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v6
- name: Install uv and Python
uses: astral-sh/setup-uv@v7
with:
python-version: ${{ matrix.python-version }}
- name: Installation (deps and package)
# We install with flit --pth-file, so that coverage will be recorded for the module
# Flit could be installed with pipx and use '--python=$(which python)', but
# there were issues with the Windows Runner
run: |
pip install flit~=3.10.1
flit install --deps=production --extras=test --pth-file
activate-environment: true
- name: Install Package
run: uv pip install ".[test]"
- name: Run pytest
run: |
pytest --cov
# # Not currently configured
# - name: Report coverage
# if: matrix.os == 'ubuntu-latest' && matrix.python-version == '3.12'
# uses: codecov/codecov-action@v4
# with:
# token: ${{ secrets.CODECOV_TOKEN }}
run: pytest --cov

prek-hook:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- name: Set up Python
uses: actions/setup-python@v6
- name: Install uv and Python
uses: astral-sh/setup-uv@v7
with:
python-version: 3.12
- name: Installation (deps and package)
python-version: 3.14
activate-environment: true
- name: Install prek
uses: j178/prek-action@v1
with:
install-only: true
- name: Install Package
run: uv pip install ".[test]"
- name: run prek with plugin
run: |
prek run --config .prek-test.yaml --all-files --verbose --show-diff-on-failure
run: prek run --config .pre-commit-test.yaml --all-files --verbose --show-diff-on-failure

publish:
name: Publish to PyPi
needs: [prek, tests, prek-hook]
if: github.event_name == 'push' && startsWith(github.event.ref, 'refs/tags')
runs-on: ubuntu-latest
# Fix 403 error (https://github.com/softprops/action-gh-release/issues/400)
environment:
name: pypi
url: https://pypi.org/p/mdformat-obsidian
permissions:
contents: write
contents: write # For GitHub release creation
id-token: write # IMPORTANT: mandatory for PyPI trusted publishing
steps:
- name: Checkout source
uses: actions/checkout@v5
- name: install flit
run: |
pipx install flit~=3.10.1
- name: Build and publish
run: |
flit publish
env:
FLIT_USERNAME: __token__
FLIT_PASSWORD: ${{ secrets.PYPI_KEY }}
- uses: actions/checkout@v5
- name: Install uv and Python
uses: astral-sh/setup-uv@v7
with:
python-version: 3.14
- name: Build Package
run: uv build
- name: Publish to PyPI
uses: pypa/gh-action-pypi-publish@release/v1
- name: Generate GitHub Release Notes
uses: softprops/action-gh-release@v2
with:
Expand Down
2 changes: 1 addition & 1 deletion .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ repos:
- id: yamllint
stages: ["pre-commit"]
- repo: https://github.com/python-jsonschema/check-jsonschema
rev: 0.30.0
rev: 0.35.0
hooks:
- id: check-github-workflows
args: ["--verbose"]
Expand Down
1 change: 0 additions & 1 deletion .tool-versions

This file was deleted.

24 changes: 12 additions & 12 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,42 +6,42 @@
# Run all tests using tox
tox

# Run tests with coverage (Python 3.10)
tox -e py310-test
# Run tests with coverage (Python 3.14 - current version)
tox -e test

# Run tests with coverage (Python 3.12)
tox -e py312-test
# Run tests with coverage (Python 3.10 - minimum version)
tox -e test-min

# Run specific tests with pytest flags
tox -e py312-test -- --exitfirst --failed-first --new-first -vv --snapshot-update
tox -e test -- --exitfirst --failed-first --new-first -vv --snapshot-update
```

## Linting and Formatting

```bash
# Run all pre-commit hooks (using prek)
tox -e py312-prek
tox -e prek
# Or run directly with prek
prek run --all

# Run ruff for linting and formatting
tox -e py312-ruff
tox -e ruff
# With unsafe fixes
tox -e py312-ruff -- --unsafe-fixes
tox -e ruff -- --unsafe-fixes
```

## Type Checking

```bash
# Run mypy type checking
tox -e py312-type
tox -e type
```

## Pre-commit Hook Testing

```bash
# Test the plugin as a pre-commit hook
tox -e py310-hook
tox -e hook-min
```

## Architecture
Expand Down Expand Up @@ -87,8 +87,8 @@ Configuration can be passed via:

## Development Notes

- This project uses `flit` as the build backend
- Uses `tox` for test automation with multiple Python versions (3.10, 3.12)
- This project uses `uv-build` as the build backend
- Uses `tox` for test automation with multiple Python versions (3.10, 3.14)
- Pre-commit is configured but the project now uses `prek` (faster alternative)
- Python 3.10+ is required (see `requires-python` in `pyproject.toml`)
- Version is defined in `mdformat_obsidian/__init__.py` as `__version__`
107 changes: 61 additions & 46 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,71 +6,64 @@ A collection of useful resources to reference when developing new features:

- [`markdown-it-py` documentation](https://markdown-it-py.readthedocs.io/en/latest/using.html)
- [`markdown-it` (JS) documentation](https://markdown-it.github.io/markdown-it)
- [`mdformat` documentation](https://mdformat.readthedocs.io/en/stable)

## Local Development

This package utilizes [flit](https://flit.readthedocs.io) as the build engine, and [tox](https://tox.readthedocs.io) for test automation.
This package utilizes [mise](https://mise.jdx.dev) ([installation guide](https://github.com/jdx/mise/blob/79367a4d382d8ab4cb76afef357d0db4afa33866/docs/installing-mise.md)) for dependency management, [prek](https://github.com/j178/prek) for fast pre-commit hooks, [uv](https://docs.astral.sh/uv) as the build engine, and [tox](https://tox.readthedocs.io) for test automation.

To install these development dependencies:
To install the development dependencies:

```bash
uv tool install tox --with tox-uv
# or: pipx install tox
```
brew install mise # or see the installation alternatives above

To run the tests:
# Install dependencies from mist.toml
mise trust
mise install

```bash
tox
```

and with test coverage:

```bash
tox -e py310-test
# Configure prek
prek install -f
```

The easiest way to write tests, is to edit `tests/fixtures.md`

To run the code formatting and style checks:
To run all tox environments:

```bash
tox -e py312-pre-commit
tox
```

or directly with [prek](https://github.com/j178/prek) (or pre-commit)
or to run specific commands:

```bash
uv tool install prek
# or: pipx install prek, brew install prek, etc.
tox -e test
tox -e prek
tox -e hook-min

prek install -f
prek run --all
tox list
```

To run the pre-commit hook test:
To run all pre-commit steps:

```bash
tox -e py310-hook
```sh
prek run --all
```

## `ptw` testing

See configuration in `pyproject.toml` for `[tool.pytest-watcher]`
`pytest-watcher` is configured in `pyproject.toml` for `[tool.pytest-watcher]` to continuously run tests

```sh
uv tool install pytest-watcher
# or: pipx install pytest-watcher

ptw .
```

## Local uv/pipx testing
## Local uv/pipx integration testing

Run the latest local code anywhere with uv tool.
Run the local code with `uv tool` (requires `uv` installed globally and first in `$PATH`, e.g. `brew install uv` or `mise use uv --global`)

```sh
uv tool install . --editable --force --with="mdformat>=0.7.19"
uv tool install 'mdformat>=0.7.19' --force --with=.

# Then navigate to a different directory and check that the editable version was installed
cd ~
mdformat --version
which mdformat
```

Or with pipx:
Expand All @@ -79,21 +72,43 @@ Or with pipx:
pipx install . --include-deps --force --editable
```

## Publish to PyPi
## Publish to PyPI

First, update the version in `mdformat_obsidian/__init__.py`
This project uses [PyPI Trusted Publishers](https://docs.pypi.org/trusted-publishers) for secure, token-free publishing from GitHub Actions, with [uv](https://docs.astral.sh/uv) for building packages.

Then, either use the Github Action by committing the new version in `__init__.py` and pushing an associated tag in format: `v#.#.#` (e.g. `v1.3.2` for `__version__ = '1.3.2'`)
### Initial Setup (One-time)

Or run flit locally:
Before publishing for the first time, you need to configure Trusted Publishing on PyPI:

```bash
# envchain --set FLIT FLIT_PASSWORD
export FLIT_USERNAME=__token__
export eval $(envchain FLIT env | grep FLIT_PASSWORD=)
1. Go to your project's page on PyPI: `https://pypi.org/manage/project/mdformat_obsidian/settings/publishing/`
- If the project doesn't exist yet, go to [PyPI's publishing page](https://pypi.org/manage/account/publishing) to add a "pending" publisher
1. Add a new Trusted Publisher with these settings:
- **PyPI Project Name**: `mdformat_obsidian`
- **Owner**: `kyleking`
- **Repository name**: `mdformat-obsidian`
- **Workflow name**: `tests.yml` (`.github/workflows/tests.yml`)
- **Environment name**: `pypi`
1. Configure the GitHub Environment:
- Go to your repository's `Settings` → `Environments`
- Create an environment named `pypi`
- (Recommended) Enable "Required reviewers" for production safety

### Publishing a Release

Use `commitizen` to automatically bump versions (in `pyproject.toml` and `mdformat_obsidian/__init__.py`) and create a commit with tag:

```sh
# Dry run to preview the version bump
tox -e cz -- --dry-run

# Automatically bump version based on conventional commits
tox -e cz

# Or manually specify the increment type
tox -e cz -- --increment PATCH # or MINOR or MAJOR

flit publish
# Push the commit and tag
git push origin main --tags
```

> [!NOTE]
> The Github Action requires generating an API key on PyPi and adding it to the repository `Settings/Secrets`, under the name `PYPI_KEY`
The GitHub Action will automatically build and publish to PyPI using Trusted Publishers (no API tokens needed!).
15 changes: 10 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,7 @@
[cov-link]: https://codecov.io/gh/executablebooks/mdformat-obsidian
-->

An [mdformat](https://github.com/executablebooks/mdformat) plugin for [Obsidian Flavored Markdown](https://help.obsidian.md/Editing+and+formatting/Obsidian+Flavored+Markdown). This plugin directly supports [Callouts](https://help.obsidian.md/Editing+and+formatting/Callouts) and a few other features. More documentation will be forthcoming, but in the interim, see the test directory for supported formats.

<!-- TODO: Update documentation with recent features (and known caveats) -->
An [mdformat](https://github.com/executablebooks/mdformat) plugin for [Obsidian Flavored Markdown](https://help.obsidian.md/Editing+and+formatting/Obsidian+Flavored+Markdown). This plugin directly supports [Callouts](https://help.obsidian.md/Editing+and+formatting/Callouts), inline footnotes, task lists with custom markers, and dollar math. See the test directory for supported formats.

> [!NOTE]
> The format for [GitHub Alerts](https://github.com/kyleking/mdformat-gfm-alerts) differs slightly from Obsidian, so they are not fully compatible. Obsidian supports folding, custom titles, and is case insensitive. To improve interoperability, this package makes the stylistic choice of capitalizing the text within `[!...]`.
Expand Down Expand Up @@ -66,12 +64,19 @@ md.use(obsidian_plugin)
text = "> [!tip] Callouts can have custom titles\n> Like this one."
md.render(text)
# <blockquote>

# <div data-callout-metadata="" data-callout-fold="" data-callout="tip" class="callout">
# <div class="callout-title">
# <div class="callout-title-inner">Callouts can have custom titles</div>
# </div>
# <div class="callout-content">
# <p>Like this one.</p>
# </div>
# </div>
# </blockquote>
```

> [!WARNING]
> This package does not properly handle replacing the `blockquote` outer `div` with a `div` for accessibility. This should be possible with `markdown-it`, but I haven't yet found a way.
> The outer `<blockquote>` tag is preserved to maintain compatibility with standard Markdown parsers. For full accessibility, you may want to replace this with a `<div>` in post-processing, as the `>` blockquote syntax is being repurposed for callouts.

## Contributing

Expand Down
2 changes: 1 addition & 1 deletion mdformat_obsidian/__init__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
"""An mdformat plugin for `obsidian`."""

__version__ = "0.1.0"
__version__ = "0.2.0"

# FYI see source code for available interfaces:
# https://github.com/executablebooks/mdformat/blob/5d9b573ce33bae219087984dd148894c774f41d4/src/mdformat/plugins.py
Expand Down
4 changes: 2 additions & 2 deletions mdformat_obsidian/factories/_obsidian_blockquote_factories.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@
from __future__ import annotations

import re
from collections.abc import Generator
from collections.abc import Callable, Generator
from contextlib import contextmanager, suppress
from typing import TYPE_CHECKING, Callable, NamedTuple
from typing import TYPE_CHECKING, NamedTuple

from markdown_it import MarkdownIt
from markdown_it.rules_block import StateBlock
Expand Down
Loading