python-frontmatter 1.1.0__py3-none-any.whl → 1.2.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- frontmatter/__init__.py +35 -23
- frontmatter/default_handlers.py +9 -8
- frontmatter/py.typed +1 -0
- frontmatter/util.py +16 -3
- {python_frontmatter-1.1.0.dist-info → python_frontmatter-1.2.0.dist-info}/METADATA +26 -14
- python_frontmatter-1.2.0.dist-info/RECORD +10 -0
- {python_frontmatter-1.1.0.dist-info → python_frontmatter-1.2.0.dist-info}/WHEEL +1 -1
- python_frontmatter-1.1.0.dist-info/RECORD +0 -9
- {python_frontmatter-1.1.0.dist-info → python_frontmatter-1.2.0.dist-info/licenses}/LICENSE +0 -0
- {python_frontmatter-1.1.0.dist-info → python_frontmatter-1.2.0.dist-info}/top_level.txt +0 -0
frontmatter/__init__.py
CHANGED
|
@@ -4,12 +4,13 @@ Python Frontmatter: Parse and manage posts with YAML frontmatter
|
|
|
4
4
|
"""
|
|
5
5
|
from __future__ import annotations
|
|
6
6
|
|
|
7
|
-
import codecs
|
|
8
7
|
import io
|
|
9
|
-
|
|
8
|
+
import pathlib
|
|
9
|
+
from os import PathLike
|
|
10
|
+
from typing import TYPE_CHECKING, Iterable, TextIO
|
|
10
11
|
|
|
11
|
-
from .
|
|
12
|
-
from .
|
|
12
|
+
from .default_handlers import JSONHandler, TOMLHandler, YAMLHandler
|
|
13
|
+
from .util import can_open, is_readable, is_writable, u
|
|
13
14
|
|
|
14
15
|
|
|
15
16
|
if TYPE_CHECKING:
|
|
@@ -96,7 +97,7 @@ def parse(
|
|
|
96
97
|
return metadata, content.strip()
|
|
97
98
|
|
|
98
99
|
|
|
99
|
-
def check(fd: str |
|
|
100
|
+
def check(fd: TextIO | PathLike[str] | str, encoding: str = "utf-8") -> bool:
|
|
100
101
|
"""
|
|
101
102
|
Check if a file-like object or filename has a frontmatter,
|
|
102
103
|
return True if exists, False otherwise.
|
|
@@ -109,13 +110,17 @@ def check(fd: str | io.IOBase, encoding: str = "utf-8") -> bool:
|
|
|
109
110
|
True
|
|
110
111
|
|
|
111
112
|
"""
|
|
112
|
-
if
|
|
113
|
+
if is_readable(fd):
|
|
113
114
|
text = fd.read()
|
|
114
115
|
|
|
115
|
-
|
|
116
|
-
with
|
|
116
|
+
elif can_open(fd):
|
|
117
|
+
with open(fd, "r", encoding=encoding) as f:
|
|
117
118
|
text = f.read()
|
|
118
119
|
|
|
120
|
+
else:
|
|
121
|
+
# no idea what we're dealing with
|
|
122
|
+
return False
|
|
123
|
+
|
|
119
124
|
return checks(text, encoding)
|
|
120
125
|
|
|
121
126
|
|
|
@@ -138,7 +143,7 @@ def checks(text: str, encoding: str = "utf-8") -> bool:
|
|
|
138
143
|
|
|
139
144
|
|
|
140
145
|
def load(
|
|
141
|
-
fd: str | io.IOBase,
|
|
146
|
+
fd: str | io.IOBase | pathlib.Path,
|
|
142
147
|
encoding: str = "utf-8",
|
|
143
148
|
handler: BaseHandler | None = None,
|
|
144
149
|
**defaults: object,
|
|
@@ -154,13 +159,16 @@ def load(
|
|
|
154
159
|
... post = frontmatter.load(f)
|
|
155
160
|
|
|
156
161
|
"""
|
|
157
|
-
if
|
|
162
|
+
if is_readable(fd):
|
|
158
163
|
text = fd.read()
|
|
159
164
|
|
|
160
|
-
|
|
161
|
-
with
|
|
165
|
+
elif can_open(fd):
|
|
166
|
+
with open(fd, "r", encoding=encoding) as f:
|
|
162
167
|
text = f.read()
|
|
163
168
|
|
|
169
|
+
else:
|
|
170
|
+
raise ValueError(f"Cannot open filename using type {type(fd)}")
|
|
171
|
+
|
|
164
172
|
handler = handler or detect_format(text, handlers)
|
|
165
173
|
return loads(text, encoding, handler, **defaults)
|
|
166
174
|
|
|
@@ -188,7 +196,7 @@ def loads(
|
|
|
188
196
|
|
|
189
197
|
def dump(
|
|
190
198
|
post: Post,
|
|
191
|
-
fd: str |
|
|
199
|
+
fd: str | PathLike[str] | TextIO,
|
|
192
200
|
encoding: str = "utf-8",
|
|
193
201
|
handler: BaseHandler | None = None,
|
|
194
202
|
**kwargs: object,
|
|
@@ -199,11 +207,11 @@ def dump(
|
|
|
199
207
|
|
|
200
208
|
::
|
|
201
209
|
|
|
202
|
-
>>> from io import
|
|
210
|
+
>>> from io import StringIO
|
|
203
211
|
>>> post = frontmatter.load('tests/yaml/hello-world.txt')
|
|
204
|
-
>>> f =
|
|
212
|
+
>>> f = StringIO()
|
|
205
213
|
>>> frontmatter.dump(post, f)
|
|
206
|
-
>>> print(f.getvalue()
|
|
214
|
+
>>> print(f.getvalue())
|
|
207
215
|
---
|
|
208
216
|
layout: post
|
|
209
217
|
title: Hello, world!
|
|
@@ -214,11 +222,11 @@ def dump(
|
|
|
214
222
|
|
|
215
223
|
.. testcode::
|
|
216
224
|
|
|
217
|
-
from io import
|
|
225
|
+
from io import StringIO
|
|
218
226
|
post = frontmatter.load('tests/yaml/hello-world.txt')
|
|
219
|
-
f =
|
|
227
|
+
f = StringIO()
|
|
220
228
|
frontmatter.dump(post, f)
|
|
221
|
-
print(f.getvalue()
|
|
229
|
+
print(f.getvalue())
|
|
222
230
|
|
|
223
231
|
.. testoutput::
|
|
224
232
|
|
|
@@ -231,13 +239,16 @@ def dump(
|
|
|
231
239
|
|
|
232
240
|
"""
|
|
233
241
|
content = dumps(post, handler, **kwargs)
|
|
234
|
-
if
|
|
235
|
-
fd.write(content
|
|
242
|
+
if is_writable(fd):
|
|
243
|
+
fd.write(content)
|
|
236
244
|
|
|
237
|
-
|
|
238
|
-
with
|
|
245
|
+
elif can_open(fd):
|
|
246
|
+
with open(fd, "w", encoding=encoding) as f:
|
|
239
247
|
f.write(content)
|
|
240
248
|
|
|
249
|
+
else:
|
|
250
|
+
raise ValueError(f"Cannot open filename using type {type(fd)}")
|
|
251
|
+
|
|
241
252
|
|
|
242
253
|
def dumps(post: Post, handler: BaseHandler | None = None, **kwargs: object) -> str:
|
|
243
254
|
"""
|
|
@@ -278,6 +289,7 @@ def dumps(post: Post, handler: BaseHandler | None = None, **kwargs: object) -> s
|
|
|
278
289
|
if handler is None:
|
|
279
290
|
handler = getattr(post, "handler", None) or YAMLHandler()
|
|
280
291
|
|
|
292
|
+
assert handler is not None
|
|
281
293
|
return handler.format(post, **kwargs)
|
|
282
294
|
|
|
283
295
|
|
frontmatter/default_handlers.py
CHANGED
|
@@ -8,8 +8,8 @@ By default, ``frontmatter`` reads and writes YAML metadata. But maybe
|
|
|
8
8
|
you don't like YAML. Maybe enjoy writing metadata in JSON, or TOML, or
|
|
9
9
|
some other exotic markup not yet invented. For this, there are handlers.
|
|
10
10
|
|
|
11
|
-
This module includes handlers for YAML, JSON and TOML, as well as a
|
|
12
|
-
:py:class:`BaseHandler <frontmatter.default_handlers.BaseHandler>` that
|
|
11
|
+
This module includes handlers for YAML, JSON and TOML, as well as a
|
|
12
|
+
:py:class:`BaseHandler <frontmatter.default_handlers.BaseHandler>` that
|
|
13
13
|
outlines the basic API and can be subclassed to deal with new formats.
|
|
14
14
|
|
|
15
15
|
**Note**: The TOML handler is only available if the `toml <https://pypi.org/project/toml/>`_
|
|
@@ -32,10 +32,10 @@ A handler needs to do four things:
|
|
|
32
32
|
|
|
33
33
|
An example:
|
|
34
34
|
|
|
35
|
-
Calling :py:func:`frontmatter.load <frontmatter.load>` (or :py:func:`loads <frontmatter.loads>`)
|
|
36
|
-
with the ``handler`` argument tells frontmatter which handler to use.
|
|
37
|
-
The handler instance gets saved as an attribute on the returned post
|
|
38
|
-
object. By default, calling :py:func:`frontmatter.dumps <frontmatter.dumps>`
|
|
35
|
+
Calling :py:func:`frontmatter.load <frontmatter.load>` (or :py:func:`loads <frontmatter.loads>`)
|
|
36
|
+
with the ``handler`` argument tells frontmatter which handler to use.
|
|
37
|
+
The handler instance gets saved as an attribute on the returned post
|
|
38
|
+
object. By default, calling :py:func:`frontmatter.dumps <frontmatter.dumps>`
|
|
39
39
|
on the post will use the attached handler.
|
|
40
40
|
|
|
41
41
|
|
|
@@ -67,7 +67,7 @@ on the post will use the attached handler.
|
|
|
67
67
|
<BLANKLINE>
|
|
68
68
|
And this shouldn't break.
|
|
69
69
|
|
|
70
|
-
Passing a new handler to :py:func:`frontmatter.dumps <frontmatter.dumps>`
|
|
70
|
+
Passing a new handler to :py:func:`frontmatter.dumps <frontmatter.dumps>`
|
|
71
71
|
(or :py:func:`dump <frontmatter.dump>`) changes the export format:
|
|
72
72
|
|
|
73
73
|
::
|
|
@@ -283,6 +283,7 @@ class JSONHandler(BaseHandler):
|
|
|
283
283
|
END_DELIMITER = ""
|
|
284
284
|
|
|
285
285
|
def split(self, text: str) -> tuple[str, str]:
|
|
286
|
+
assert self.FM_BOUNDARY is not None
|
|
286
287
|
_, fm, content = self.FM_BOUNDARY.split(text, 2)
|
|
287
288
|
return "{" + fm + "}", content
|
|
288
289
|
|
|
@@ -298,7 +299,7 @@ class JSONHandler(BaseHandler):
|
|
|
298
299
|
|
|
299
300
|
if toml:
|
|
300
301
|
|
|
301
|
-
class TOMLHandler(BaseHandler):
|
|
302
|
+
class TOMLHandler(BaseHandler): # pyright: ignore
|
|
302
303
|
"""
|
|
303
304
|
Load and export TOML metadata.
|
|
304
305
|
|
frontmatter/py.typed
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
# Marker file for PEP 561. This package uses inline types.
|
frontmatter/util.py
CHANGED
|
@@ -2,16 +2,29 @@
|
|
|
2
2
|
"""
|
|
3
3
|
Utilities for handling unicode and other repetitive bits
|
|
4
4
|
"""
|
|
5
|
-
from
|
|
5
|
+
from os import PathLike
|
|
6
|
+
from typing import TypeGuard, TextIO
|
|
6
7
|
|
|
7
8
|
|
|
8
|
-
def
|
|
9
|
+
def is_readable(fd: object) -> TypeGuard[TextIO]:
|
|
10
|
+
return callable(getattr(fd, "read", None))
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def is_writable(fd: object) -> TypeGuard[TextIO]:
|
|
14
|
+
return callable(getattr(fd, "write", None))
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def can_open(fd: object) -> TypeGuard[str | PathLike[str]]:
|
|
18
|
+
return isinstance(fd, str) or isinstance(fd, PathLike)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def u(text: str | bytes, encoding: str = "utf-8") -> str:
|
|
9
22
|
"Return unicode text, no matter what"
|
|
10
23
|
|
|
11
24
|
if isinstance(text, bytes):
|
|
12
25
|
text_str: str = text.decode(encoding)
|
|
13
26
|
else:
|
|
14
|
-
text_str = text
|
|
27
|
+
text_str = str(text)
|
|
15
28
|
|
|
16
29
|
# it's already unicode
|
|
17
30
|
text_str = text_str.replace("\r\n", "\n")
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: python-frontmatter
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.2.0
|
|
4
4
|
Summary: Parse and manage posts with YAML (or other) frontmatter
|
|
5
5
|
Home-page: https://github.com/eyeseast/python-frontmatter
|
|
6
6
|
Author: Chris Amico
|
|
@@ -12,23 +12,35 @@ Classifier: Intended Audience :: Developers
|
|
|
12
12
|
Classifier: License :: OSI Approved :: MIT License
|
|
13
13
|
Classifier: Natural Language :: English
|
|
14
14
|
Classifier: Programming Language :: Python :: 3
|
|
15
|
-
Classifier: Programming Language :: Python :: 3.8
|
|
16
15
|
Classifier: Programming Language :: Python :: 3.9
|
|
17
16
|
Classifier: Programming Language :: Python :: 3.10
|
|
18
17
|
Classifier: Programming Language :: Python :: 3.11
|
|
19
18
|
Classifier: Programming Language :: Python :: 3.12
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
20
20
|
Description-Content-Type: text/markdown
|
|
21
21
|
License-File: LICENSE
|
|
22
22
|
Requires-Dist: PyYAML
|
|
23
|
-
Provides-Extra: docs
|
|
24
|
-
Requires-Dist: sphinx ; extra == 'docs'
|
|
25
23
|
Provides-Extra: test
|
|
26
|
-
Requires-Dist: pytest
|
|
27
|
-
Requires-Dist: toml
|
|
28
|
-
Requires-Dist: pyaml
|
|
29
|
-
Requires-Dist: mypy
|
|
30
|
-
Requires-Dist: types-PyYAML
|
|
31
|
-
Requires-Dist: types-toml
|
|
24
|
+
Requires-Dist: pytest; extra == "test"
|
|
25
|
+
Requires-Dist: toml; extra == "test"
|
|
26
|
+
Requires-Dist: pyaml; extra == "test"
|
|
27
|
+
Requires-Dist: mypy; extra == "test"
|
|
28
|
+
Requires-Dist: types-PyYAML; extra == "test"
|
|
29
|
+
Requires-Dist: types-toml; extra == "test"
|
|
30
|
+
Provides-Extra: docs
|
|
31
|
+
Requires-Dist: sphinx; extra == "docs"
|
|
32
|
+
Dynamic: author
|
|
33
|
+
Dynamic: author-email
|
|
34
|
+
Dynamic: classifier
|
|
35
|
+
Dynamic: description
|
|
36
|
+
Dynamic: description-content-type
|
|
37
|
+
Dynamic: home-page
|
|
38
|
+
Dynamic: keywords
|
|
39
|
+
Dynamic: license
|
|
40
|
+
Dynamic: license-file
|
|
41
|
+
Dynamic: provides-extra
|
|
42
|
+
Dynamic: requires-dist
|
|
43
|
+
Dynamic: summary
|
|
32
44
|
|
|
33
45
|
# Python Frontmatter
|
|
34
46
|
|
|
@@ -142,10 +154,10 @@ Well, hello there, world.
|
|
|
142
154
|
Or write to a file (or file-like object):
|
|
143
155
|
|
|
144
156
|
```python
|
|
145
|
-
>>> from io import
|
|
146
|
-
>>> f =
|
|
157
|
+
>>> from io import StringIO
|
|
158
|
+
>>> f = StringIO()
|
|
147
159
|
>>> frontmatter.dump(post, f)
|
|
148
|
-
>>> print(f.getvalue()
|
|
160
|
+
>>> print(f.getvalue()) # doctest: +NORMALIZE_WHITESPACE
|
|
149
161
|
---
|
|
150
162
|
excerpt: tl;dr
|
|
151
163
|
layout: post
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
frontmatter/__init__.py,sha256=PtzuMdiQeiEq3r6FLgzDjT1pxkphlSt40VKtL-jUokY,9177
|
|
2
|
+
frontmatter/conftest.py,sha256=LxRFalFdwQA2RtSYqCSB7V7THG7rHt5zZmMEzJlf0DA,220
|
|
3
|
+
frontmatter/default_handlers.py,sha256=ucN_cv4nnPfRevZDZYbtio-r1aITcUZI4qBCKXWOAxA,9717
|
|
4
|
+
frontmatter/py.typed,sha256=DtCsIDq6KOv2NOEdQjTbeMWJKRh6ZEL2E-6Mf1RLeMA,59
|
|
5
|
+
frontmatter/util.py,sha256=utw8plpS0Ld6CJkY02k_VpT1vfiVm5ai1npsKR5Hius,784
|
|
6
|
+
python_frontmatter-1.2.0.dist-info/licenses/LICENSE,sha256=LmiF34zbpRujrv40WY5ohW8bJGjR5YxxlhQAS4b7Q9U,1077
|
|
7
|
+
python_frontmatter-1.2.0.dist-info/METADATA,sha256=Rn5Q4VXKA6eZx-lhGd8eeklpUBMoqjTFpknGs0mkD5k,4370
|
|
8
|
+
python_frontmatter-1.2.0.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
|
|
9
|
+
python_frontmatter-1.2.0.dist-info/top_level.txt,sha256=o5ywgaMiFjjXFwNlYulDy2RAulwnLsZCmYQn0jy7w7M,12
|
|
10
|
+
python_frontmatter-1.2.0.dist-info/RECORD,,
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
frontmatter/__init__.py,sha256=wL0nd60OKonncekh0qpxqX7PjquQscdF7ADyQurygJc,8809
|
|
2
|
-
frontmatter/conftest.py,sha256=LxRFalFdwQA2RtSYqCSB7V7THG7rHt5zZmMEzJlf0DA,220
|
|
3
|
-
frontmatter/default_handlers.py,sha256=kO4QMSqvUWAUOcKC2sCmVA0SX2aZRXrhlckFCqZttkg,9661
|
|
4
|
-
frontmatter/util.py,sha256=hlyw6r54QvGdsln0EcXUHh51eQqYRnONy4P6fuemo6M,419
|
|
5
|
-
python_frontmatter-1.1.0.dist-info/LICENSE,sha256=LmiF34zbpRujrv40WY5ohW8bJGjR5YxxlhQAS4b7Q9U,1077
|
|
6
|
-
python_frontmatter-1.1.0.dist-info/METADATA,sha256=FKyXVYaz4nPtlhZxEDx0WcDqFlcajLbGLVCZ-jzHOZA,4137
|
|
7
|
-
python_frontmatter-1.1.0.dist-info/WHEEL,sha256=oiQVh_5PnQM0E3gPdiz09WCNmwiHDMaGer_elqB3coM,92
|
|
8
|
-
python_frontmatter-1.1.0.dist-info/top_level.txt,sha256=o5ywgaMiFjjXFwNlYulDy2RAulwnLsZCmYQn0jy7w7M,12
|
|
9
|
-
python_frontmatter-1.1.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|