Skip to content

Commit 9c00f7b

Browse files
committed
Uncap dependencies
Fix #18
1 parent b476b07 commit 9c00f7b

File tree

8 files changed

+119
-95
lines changed

8 files changed

+119
-95
lines changed

.github/workflows/ci.yml

Lines changed: 29 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
name: CI
22

3-
on:
3+
"on":
44
push:
55
branches: [master]
66
tags:
@@ -13,27 +13,34 @@ jobs:
1313
runs-on: ubuntu-latest
1414

1515
steps:
16-
- uses: actions/checkout@v3
16+
- uses: actions/checkout@v5
1717
- name: Set up Python
18-
uses: actions/setup-python@v4
18+
uses: actions/setup-python@v6
1919
with:
20-
python-version: 3.13
20+
python-version: "3.14"
2121
- name: Installation (deps and package)
2222
run: pip install .
23-
- uses: pre-commit/action@v2.0.0
23+
- uses: pre-commit/action@v3.0.1
2424

2525
tests:
2626
runs-on: ${{ matrix.os }}
2727
strategy:
2828
matrix:
29-
python-version: [3.9, '3.10', 3.11, 3.12, 3.13]
30-
os: [ubuntu-latest, windows-latest]
29+
python-version:
30+
- "3.10"
31+
- "3.11"
32+
- "3.12"
33+
- "3.13"
34+
- "3.14"
35+
os:
36+
- ubuntu-latest
37+
- windows-latest
3138

3239
steps:
33-
- uses: actions/checkout@v3
40+
- uses: actions/checkout@v5
3441

3542
- name: Set up Python ${{ matrix.python-version }}
36-
uses: actions/setup-python@v4
43+
uses: actions/setup-python@v6
3744
with:
3845
python-version: ${{ matrix.python-version }}
3946

@@ -49,7 +56,7 @@ jobs:
4956
pytest --cov=mdformat_pyproject --cov-report=xml --cov-report=term-missing
5057
5158
- name: Store PR number and commit SHA
52-
if: matrix.os == 'ubuntu-latest' && matrix.python-version == 3.13
59+
if: matrix.os == 'ubuntu-latest' && matrix.python-version == 3.14
5360
run: |
5461
echo "Storing PR number ${{ github.event.number }}"
5562
echo "${{ github.event.number }}" > pr_number.txt
@@ -58,19 +65,19 @@ jobs:
5865
echo "${{ github.event.pull_request.head.sha }}" > commit_sha.txt
5966
6067
# Workaround for codecov tokenless upload errors on external PRs
61-
# Copied and ajusted from the workarounds suggested in the link below:
68+
# Copied and adjusted from the workarounds suggested in the link below:
6269
# https://github.com/codecov/feedback/issues/301#issuecomment-2009355183
6370
# Triggered sub-workflow is not able to detect the original commit/PR which is available
6471
# in this workflow.
6572
- name: Store PR number
66-
if: matrix.os == 'ubuntu-latest' && matrix.python-version == 3.13
73+
if: matrix.os == 'ubuntu-latest' && matrix.python-version == 3.14
6774
uses: actions/upload-artifact@v4
6875
with:
6976
name: pr_number
7077
path: pr_number.txt
7178

7279
- name: Store commit SHA
73-
if: matrix.os == 'ubuntu-latest' && matrix.python-version == 3.13
80+
if: matrix.os == 'ubuntu-latest' && matrix.python-version == 3.14
7481
uses: actions/upload-artifact@v4
7582
with:
7683
name: commit_sha
@@ -80,7 +87,7 @@ jobs:
8087
# is executed by a different workflow `coverage-report.yml`. The reason for this
8188
# split is because `on.pull_request` workflows don't have access to secrets.
8289
- name: Store coverage report in artifacts
83-
if: matrix.os == 'ubuntu-latest' && matrix.python-version == 3.13
90+
if: matrix.os == 'ubuntu-latest' && matrix.python-version == 3.14
8491
uses: actions/upload-artifact@v4
8592
with:
8693
name: codecov_report
@@ -89,17 +96,17 @@ jobs:
8996
- run: |
9097
echo "The coverage report was stored in Github artifacts."
9198
echo "It will be uploaded to Codecov using [codecov.yml] workflow shortly."
92-
if: matrix.os == 'ubuntu-latest' && matrix.python-version == 3.13
99+
if: matrix.os == 'ubuntu-latest' && matrix.python-version == 3.14
93100
94101
pre-commit-hook:
95102
runs-on: ubuntu-latest
96103

97104
steps:
98-
- uses: actions/checkout@v3
105+
- uses: actions/checkout@v5
99106
- name: Set up Python
100-
uses: actions/setup-python@v4
107+
uses: actions/setup-python@v6
101108
with:
102-
python-version: 3.13
109+
python-version: 3.14
103110

104111
- name: Installation (deps and package)
105112
run: |
@@ -117,11 +124,11 @@ jobs:
117124
runs-on: ubuntu-latest
118125
steps:
119126
- name: Checkout source
120-
uses: actions/checkout@v3
121-
- name: Set up Python 3.13
122-
uses: actions/setup-python@v4
127+
uses: actions/checkout@v5
128+
- name: Set up Python 3.14
129+
uses: actions/setup-python@v6
123130
with:
124-
python-version: 3.13
131+
python-version: 3.14
125132
- name: install flit
126133
run: |
127134
pip install flit~=3.0

.github/workflows/codecov.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
name: CodeCov Report Upload
22

33
on:
4-
# This workflow is triggered after every successfull execution
4+
# This workflow is triggered after every successful execution
55
# of `ci` workflow.
66
workflow_run:
77
workflows: ["CI"]
@@ -16,7 +16,7 @@ jobs:
1616

1717
- name: 'Download existing coverage report'
1818
id: prepare_report
19-
uses: actions/github-script@v7
19+
uses: actions/github-script@v8
2020
with:
2121
script: |
2222
var fs = require('fs');
@@ -90,7 +90,7 @@ jobs:
9090
echo "override_commit=$(<commit_sha.txt)" >> "$GITHUB_OUTPUT"
9191
9292
- name: Checkout repository
93-
uses: actions/checkout@v4
93+
uses: actions/checkout@v5
9494
with:
9595
ref: ${{ steps.parse_previous_artifacts.outputs.override_commit || '' }}
9696
path: repo_root

.pre-commit-config.yaml

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,26 @@
11
repos:
22
- repo: https://github.com/pre-commit/pre-commit-hooks
3-
rev: v4.4.0
3+
rev: v6.0.0
44
hooks:
55
- id: end-of-file-fixer
66
- id: mixed-line-ending
77
- id: trailing-whitespace
88
- id: check-yaml
99
- id: check-toml
1010
- repo: https://github.com/pre-commit/pygrep-hooks
11-
rev: v1.9.0
11+
rev: v1.10.0
1212
hooks:
1313
- id: python-check-blanket-noqa
1414
- repo: https://github.com/timothycrosley/isort
15-
rev: 5.13.2
15+
rev: 7.0.0
1616
hooks:
1717
- id: isort
1818
- repo: https://github.com/psf/black
19-
rev: 22.12.0
19+
rev: 25.9.0
2020
hooks:
2121
- id: black
2222
- repo: https://github.com/pycqa/flake8
23-
rev: 6.0.0
23+
rev: 7.3.0
2424
hooks:
2525
- id: flake8
2626
additional_dependencies:
@@ -29,7 +29,7 @@ repos:
2929
- flake8-builtins
3030
- flake8-comprehensions
3131
- repo: https://github.com/hukkin/mdformat
32-
rev: 0.7.21
32+
rev: 1.0.0
3333
hooks:
3434
- id: mdformat
3535
additional_dependencies:

README.md

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,6 @@
55

66
An [mdformat] plugin to read configuration from `pyproject.toml`.
77

8-
> ⚠️ WARNING: it has been detected that some native `mdformat` options like `end_of_line` or
9-
> `exclude` are currently being ignored when included in the `pyproject.toml` file. The issue is
10-
> being worked on right now. You can read more here in
11-
> [issue #4](https://github.com/csala/mdformat-pyproject/issues/4)
12-
138
## Install
149

1510
Install with:
@@ -36,7 +31,7 @@ Add the following to your `.pre-commit-config.yaml`:
3631

3732
```yaml
3833
- repo: https://github.com/executablebooks/mdformat
39-
rev: 0.7.13 # Use the ref you want to point at
34+
rev: 1.0.0 # Use the ref you want to point at
4035
hooks:
4136
- id: mdformat
4237
additional_dependencies:

mdformat_pyproject/__init__.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
"""An mdformat plugin for..."""
1+
"""An mdformat plugin for reading configuration from ``pyproject.toml`` files."""
22

3-
__version__ = "0.0.2"
3+
__version__ = "1.0.0"
44

55
from .plugin import RENDERERS, update_mdit # noqa: F401

mdformat_pyproject/plugin.py

Lines changed: 71 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,88 +1,121 @@
11
"""Main plugin module."""
22

3-
import pathlib
3+
from __future__ import annotations
4+
45
import sys
5-
from typing import TYPE_CHECKING, MutableMapping, Optional, Sequence, Tuple, Union
6+
from functools import cache
7+
from pathlib import Path
68

79
import markdown_it
810
import mdformat
911

12+
TYPE_CHECKING = False
1013
if TYPE_CHECKING:
14+
from collections.abc import MutableMapping, Sequence
15+
1116
from mdformat.renderer.typing import Render
1217

18+
_ConfigOptions = MutableMapping[str, int | str | Sequence[str]]
19+
20+
1321
if sys.version_info >= (3, 11):
1422
import tomllib
1523
else:
1624
import tomli as tomllib
1725

18-
if sys.version_info >= (3, 9):
19-
from functools import cache
20-
else:
21-
from functools import lru_cache
22-
23-
cache = lru_cache()
2426

27+
@cache
28+
def _search_config_file(search_path: Path) -> Path | None:
29+
"""Search the first ``.mdformat.toml`` or ``pyproject.toml`` file in the provided
30+
``search_path`` folder or its parents.
2531
26-
_ConfigOptions = MutableMapping[str, Union[int, str, Sequence[str]]]
32+
The search is done ascending through the folders tree until a ``.mdformat.toml`` or a
33+
``pyproject.toml`` file is found. If the root ``/`` is reached, ``None`` is returned.
2734
35+
``.mdformat.toml`` takes precedence over ``pyproject.toml`` if both are present in the
36+
same folder.
2837
29-
@cache
30-
def _find_pyproject_toml_path(search_path: pathlib.Path) -> Optional[pathlib.Path]:
31-
"""Find the pyproject.toml file that applies to the search path.
38+
``pyproject.toml`` files without a ``[tool.mdformat]`` section are ignored.
3239
33-
The search is done ascending through the folders tree until a pyproject.toml
34-
file is found in the same folder. If the root '/' is reached, None is returned.
40+
This behavior mimics the one from Ruff, as described in `issues#17
41+
<https://github.com/csala/mdformat-pyproject/issues/17>`_.
3542
"""
3643
if search_path.is_file():
3744
search_path = search_path.parent
3845

3946
for parent in (search_path, *search_path.parents):
40-
candidate = parent / "pyproject.toml"
41-
if candidate.is_file():
42-
return candidate
47+
for filename in (".mdformat.toml", "pyproject.toml"):
48+
candidate = parent / filename
49+
if candidate.is_file():
50+
# If we found a pyproject.toml, only return it if it contains
51+
# a [tool.mdformat] section.
52+
if candidate.name == "pyproject.toml":
53+
options = _parse_pyproject(candidate)
54+
if options is None:
55+
continue
56+
57+
return candidate
4358

4459
return None
4560

4661

4762
@cache
48-
def _parse_pyproject(pyproject_path: pathlib.Path) -> Optional[_ConfigOptions]:
49-
"""Extract and validate the mdformat options from the pyproject.toml file.
63+
def _parse_pyproject(pyproject_path: Path) -> _ConfigOptions | None:
64+
"""Extract and validate the mdformat options from the ``pyproject.toml`` file.
65+
66+
The options are searched inside a ``[tool.mdformat]`` section within the TOML file,
67+
and they are validated using the default functions from ``mdformat._conf``.
5068
51-
The options are searched inside a [tool.mdformat] key within the toml file,
52-
and they are validated using the default functions from `mdformat._conf`.
69+
If no ``[tool.mdformat]`` section is found, ``None`` is returned.
5370
"""
5471
with pyproject_path.open(mode="rb") as pyproject_file:
55-
content = tomllib.load(pyproject_file)
72+
try:
73+
content = tomllib.load(pyproject_file)
74+
except tomllib.TOMLDecodeError as e:
75+
raise mdformat._conf.InvalidConfError(f"Invalid TOML syntax: {e}")
5676

5777
options = content.get("tool", {}).get("mdformat")
58-
if options is not None:
59-
mdformat._conf._validate_keys(options, pyproject_path)
60-
mdformat._conf._validate_values(options, pyproject_path)
78+
if options is None:
79+
return None
80+
81+
mdformat._conf._validate_keys(options, pyproject_path)
82+
mdformat._conf._validate_values(options, pyproject_path)
6183

6284
return options
6385

6486

87+
_orig_read_toml_opts = mdformat._conf.read_toml_opts
88+
89+
6590
@cache
66-
def read_toml_opts(conf_dir: pathlib.Path) -> Tuple[MutableMapping, Optional[pathlib.Path]]:
67-
"""Alternative read_toml_opts that reads from pyproject.toml instead of .mdformat.toml.
91+
def patched_read_toml_opts(conf_dir: Path) -> tuple[MutableMapping, Path | None]:
92+
"""Patched version of ``mdformat._conf.read_toml_opts``.
6893
69-
Notice that if `.mdformat.toml` exists it is ignored.
94+
Tries to read options from ``pyproject.toml`` first before falling back to
95+
``.mdformat.toml``.
7096
"""
71-
pyproject_path = _find_pyproject_toml_path(conf_dir)
72-
if pyproject_path:
73-
pyproject_opts = _parse_pyproject(pyproject_path)
74-
else:
75-
pyproject_opts = {}
97+
config_file = _search_config_file(conf_dir)
98+
99+
if config_file:
100+
# We found a .mdformat.toml, use the original function directly.
101+
if config_file.name == ".mdformat.toml":
102+
return _orig_read_toml_opts(config_file.parent)
103+
104+
# Otherwise, we found a pyproject.toml, try to parse it.
105+
options = _parse_pyproject(config_file)
106+
if options:
107+
return options, config_file
76108

77-
return pyproject_opts, pyproject_path
109+
# No config file found, return empty options.
110+
return {}, None
78111

79112

80113
def update_mdit(mdit: markdown_it.MarkdownIt) -> None:
81-
"""No-op, since this plugin only monkey patches and does not modify mdit."""
114+
"""No-op, since this plugin only monkey patches and does not modify ``mdit``."""
82115
pass
83116

84117

85-
RENDERERS: MutableMapping[str, "Render"] = {}
118+
RENDERERS: MutableMapping[str, Render] = {}
86119

87-
# Monkey patch mdformat._conf to use our own read_toml_opts version
88-
mdformat._conf.read_toml_opts = read_toml_opts
120+
# Monkey patch mdformat._conf to use our own read_toml_opts version.
121+
mdformat._conf.read_toml_opts = patched_read_toml_opts

0 commit comments

Comments
 (0)