diff --git a/.gitignore b/.gitignore
index 717d41c..1a4195c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -10,4 +10,5 @@ mf2py.egg-info/
nbproject/
venv/
*~
-poetry.lock
\ No newline at end of file
+poetry.lock
+site/
diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644
index 0000000..993fea9
--- /dev/null
+++ b/CHANGELOG.md
@@ -0,0 +1,167 @@
+# Change Log
+All notable changes to this project will be documented in this file.
+
+## 2.0.0 - 2023-12-07
+The mf2py library is excited to transition into 2.0. This version increase incorporates months of work from contributors, informed by active discussions among implementers and users.
+
+This release officially deprecates support for versions of Python lower than 3.8.
+
+Below are the changes we have made in this release.
+
+### New Features
+- Enable `img_with_alt` by default (#184)
+- Add timezone offset normalisation (#206)
+- Add option for exposing DOM for embedded properties (#208)
+- Add srcset support (#209)
+- Add language support (#210)
+- Add option for metaformats support (#213)
+
+### Changes
+- Remove `img_with_alt` option entirely (#200)
+- Resolve implied photo relative paths (#205)
+- Make relative URLs in embedded properties absolute (#201)
+- Fix whitespace in plaintext conversion (#207)
+- Replace `dict_class` with standard `dict` (#196)
+
+### Tests, Library and Documentation Maintenance
+- Update tests to include alt texts by default (#190)
+- Add Windows and macOS tests (#198)
+- Use poetry for dependency management (#189)
+- Deprecate Python 2 support (#179)
+- Lint code with `black` and `isort`
+- Add linting CI actions (#193)
+- Move from `nosetests` to `pytest` (#186)
+- Add 3.11, 3.12 and drop pypy from test matrix; upgrade poetry action (#204)
+- Prepare tests to test options (#214)
+- Bring README doctests up-to-date (#215)
+
+## 1.1.3 - 2022-06-28
+- reduce instances where photo is implied (#135)
+- always do relative URL resolution (#138)
+- VCP now handles tz offsets without leading zeros (#142)
+- implement id parsing (#143)
+- fix outdated syntax causing SyntaxWarning (#157)
+
+## 1.1.2 - 2018-08-08
+- add parsing for iframe.u-*[src] (#116)
+- bug fix: reduced implied urls (#117)
+- bug fix: don't collapse whitespace between tags
+- specify explicit versions for dependencies
+- revert BeautifulSoup copying added in 1.1.1 due to bugs (eg #108)
+- misc performance improvements
+
+## 1.1.1 - 2018-06-15
+- streamline backcompat to use JSON only.
+- fix multiple mf1 root rel-tag parsing
+- correct url and photo for hreview.
+- add rules for nested hreview. update backcompat to use multiple matches in old properties.
+- fix `rel-tag` to `p-category` conversion so that other classes are not lost.
+- use original authored html for `e-*` parsing in backcompat
+- make classes and rels into unordered (alphabetically ordered) deduped arrays.
+- only use class names for mf2 which follow the naming rules
+- fix `parse` method to use default html parser.
+- always use the first value for attributes for rels.
+- correct AM/PM conversion in datetime value class pattern.
+- add ordinal date parsing to datetimes value class pattern. ordinal date is normalised to YYYY-MM-DD
+- remove hack for html tag classes since that is fixed in new BS
+- better whitespace algorithm for `name` and `html.value` parsing
+- experimental flag for including `alt` in `u-photo` parsing
+- make a copy of the BeautifulSoup given by user to work on for parsing to prevent changes to original doc
+- bump version to 1.1.1
+
+## 1.1.0 - 2018-03-16
+- bump version to 1.1.0 since it is a "major" change
+- added tests for new implied name rules
+- modified earlier tests to accommodate new rules
+- use space separator instead of "T"
+- Don't add "00" seconds unless authored
+- use TZ authored in separate `value` element
+- only use first found `value` of a particular type `date`, `time`, or `timezone`.
+- move backcompat rules into JSON files
+- reorganise value class pattern parsing into new files
+- add datetime_helpers to organise datetime parsing rules
+- reorganise tests
+- remove Heroku frontend, point to mf2py-web and python.microformats.io instead in README.
+- remove Flask and gunicorn requirements
+- add debug info with description, version, url and the html parser used
+
+## 1.0.6 - 2018-03-04
+- strip leading/trailing white space for `e-*[html]`. update the corresponding tests
+- blank values explicitly authored are allowed as property values
+- include `alt` or `src` from ` ` in parsing for `p-*` and `e-*[value]`
+- parse `title` from ` ` for `p-*` resolves #84
+- and `poster` from `` for `u-*` resolves #76
+- use `html5lib` as default parser
+- use the final redirect URL resolves #62
+- update requirements to use BS4 v4.6.0 and html5lib v1.0.1
+- drop support for Python 2.6 as html5lib dropped support
+
+## 1.0.5 - 2016-05-09
+- Implied property checks now ignore alt="", treating it the same as
+ if no alt value is defined.
+- Support for using a custom dict implementation by setting
+ mf2py.Parser.dict_class. collections.OrderedDict yields much nicer
+ output for hosted parsers.
+
+## 1.0.4 - 2016-03-21
+- Performance improvement changing simple calls to soup.find_all to
+ a manual iteration over .contents.
+
+## 1.0.3 - 2016-02-05
+- Performance improvement by limiting number of calls to soup.find_all
+ in backcompat module. Should not be any functional changes.
+
+## 1.0.2 - 2016-01-26
+- Backward compatibility parsing for rel=tag properties. These are now converted
+ to p-category based on the last path segment of the tag URI as spec'd in
+ http://microformats.org/wiki/h-entry#Parser_Compatibility
+- Optional property html_parser to specify the html parser that BeautifulSoup
+ should use (e.g., "lxml" or "html5lib")
+
+## 1.0.1 - 2015-12-11
+- `u-*` properties are now parsed from ` ` elements per the updated spec
+ http://microformats.org/wiki/microformats2-parsing-issues#link_elements_and_u-_parsing
+
+## 1.0.0 - 2015-10-05
+- Version number bumped to 1.0.0 following community discussion.
+
+## 0.2.8 - 2015-09-21
+- Stricter checks that Parser.__init__ params are actually None before
+ ignoring them.
+
+## 0.2.7 - 2015-08-03
+- Now produces unicode strings for every key and value, no more byte
+ strings anywhere.
+- Do not add 'T' between date and time when normalizing dates
+- Unit tests for running the microformats test suite
+
+## 0.2.6 - 2015-05-06
+- New top-level "rel-urls" entry, contains rich data parsed from rel
+ links, organized by URL.
+
+## 0.2.5 - 2015-03-01
+- convenience method `mf2py.parse` that takes the same arguments as Parser
+ and returns a dict.
+- nested h-* classes now parse their "value" based on the property
+ they represent (p-*, u-*, dt-*), so for example "p-in-reply-to
+ h-cite" would have a name as its value and "u-in-reply-to h-cite"
+ will have a URL.
+
+## 0.2.4 - 2015-02-13
+- Add rel=bookmark to backward compat parsing rules based (translated
+ to u-url in mf2)
+- Parser constructor now takes explicit named arguments instead of
+ **kwargs, for saner behavior when called with unnamed arguments.
+- Bugfix: Empty href="" attributes are now properly interpreted as
+ the current document's URL.
+
+## 0.2.3 - 2015-02-07
+- Minor Py3 compatibility fix
+- Correct typo `test_requires` -> `tests_require` in setup.py
+
+## 0.2.2 - 2015-02-05
+- Started keeping a changelog!
+- Use a better method for extracting HTML for an e-* property
+- Correct BeautifulSoup4 dependency in setup.py to fix error with
+ installation from PyPI.
+- Buffed up docstrings for public methods.
diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md
index 2dafe1d..e9c1d39 100644
--- a/CONTRIBUTORS.md
+++ b/CONTRIBUTORS.md
@@ -1,11 +1,11 @@
# Contributors
-- Tom Morris http://tommorris.org/
-- Barnaby Walters http://waterpigs.co.uk
+- Tom Morris https://tommorris.org
+- Barnaby Walters https://waterpigs.co.uk
- Kartik Prabhu https://kartikprabhu.com
-- Kyle Mahan https://kylewm.com
-- Kevin Marks http://www.kevinmarks.com/
+- Kyle Mahan https://github.com/kylewm
+- Kevin Marks https://www.kevinmarks.com
- James https://jamesg.blog
- Angelo Gladding https://ragt.ag
-- Paweล Miech https://pawelmhm.github.io/
-- Sven Knebel https://www.svenknebel.de
\ No newline at end of file
+- Paweล Miech https://pawelmhm.github.io
+- Sven Knebel https://www.svenknebel.de
diff --git a/Makefile b/Makefile
index 326c37e..e3b90f4 100644
--- a/Makefile
+++ b/Makefile
@@ -2,8 +2,12 @@ install:
poetry install
tests:
poetry run pytest -s -vv --doctest-modules --doctest-glob README*
-publish:
- poetry publish --build
lint:
poetry run black .
poetry run isort .
+docs_dev:
+ poetry run mkdocs serve
+docs_deploy:
+ poetry run mkdocs gh-deploy
+publish:
+ poetry publish --build
diff --git a/README.md b/README.md
index 2b9587e..c2f4459 100644
--- a/README.md
+++ b/README.md
@@ -7,19 +7,20 @@
## Welcome ๐
-`mf2py` is a Python [microformats](https://microformats.org/wiki/microformats) parser with full support for `microformats2` and `microformats1`.
+`mf2py` is a Python [microformats](https://microformats.org/wiki/microformats) parser with full support for `microformats2`, backwards-compatible support for `microformats1` and experimental support for `metaformats`.
## Installation ๐ป
-To install `mf2py`, run the following command:
+To install `mf2py` run the following command:
```bash
-pip install mf2py
+$ pip install mf2py
+
```
## Quickstart ๐
-Import the parser using:
+Import the library:
```pycon
>>> import mf2py
@@ -77,9 +78,9 @@ Import the parser using:
```
-## Extensions
+## Experimental Options
-The following extensions can be invoked via keyword arguments to `parse()` and `Parser()`.
+The following options can be invoked via keyword arguments to `parse()` and `Parser()`.
### `expose_dom`
diff --git a/docs/changelog.md b/docs/changelog.md
deleted file mode 100644
index 5577c5a..0000000
--- a/docs/changelog.md
+++ /dev/null
@@ -1,196 +0,0 @@
-# Change Log
-All notable changes to this project will be documented in this file.
-
-## v2.0.0 - 2023-12-04
-
-The mf2py library is excited to transition into 2.0. This version increase incorporates months of work from contributors, informed by active discussions among implementers and users.
-
-This release officially deprecates support for versions of Python lower than 3.8.
-
-Below are the changes we have made in this release.
-
-## New Features
-
-* Enable img_with_alt by default by @capjamesg in https://github.com/microformats/mf2py/pull/184
-* Add timezone offset normalisation by @angelogladding in https://github.com/microformats/mf2py/pull/206
-* Add extension to expose DOM for embedded properties by @angelogladding in https://github.com/microformats/mf2py/pull/208
-* Add srcset support by @angelogladding in https://github.com/microformats/mf2py/pull/209
-* Add language support by @angelogladding in https://github.com/microformats/mf2py/pull/210
-* Add extension to support metaformats by @snarfed in https://github.com/microformats/mf2py/pull/213
-
-## Changes
-
-* Remove `img_with_alt` option entirely by @angelogladding in https://github.com/microformats/mf2py/pull/200
-* Resolve implied photo relative paths by @angelogladding in https://github.com/microformats/mf2py/pull/205
-* Make relative URLs in `e-` properties absolute by @angelogladding in https://github.com/microformats/mf2py/pull/201
-* Fix whitespace in plaintext conversion by @angelogladding in https://github.com/microformats/mf2py/pull/207
-* Replace `dict_class` with standard `dict` by @angelogladding in https://github.com/microformats/mf2py/pull/196
-
-## Tests, Library and Documentation Maintenance
-
-* Update tests to include alt texts by default by @angelogladding in https://github.com/microformats/mf2py/pull/190
-* Add Windows and macOS tests by @capjamesg in https://github.com/microformats/mf2py/pull/198
-* Use poetry for dependency management by @angelogladding in https://github.com/microformats/mf2py/pull/189
-* Deprecate Python 2 support by @angelogladding in https://github.com/microformats/mf2py/pull/179
-* Code linted with `black` and `isort` by @capjamesg
-* Bump requests from 2.21.0 to 2.31.0 by @dependabot in https://github.com/microformats/mf2py/pull/185
-* Add linting CI actions by @capjamesg in https://github.com/microformats/mf2py/pull/193
-* Move from nose2 to pytest by @capjamesg in https://github.com/microformats/mf2py/pull/186
-* Switch from nosetests to pytest by @angelogladding in https://github.com/microformats/mf2py/pull/178
-* Add 3.11, 3.12 and drop pypy from test matrix; upgrade poetry action by @angelogladding in https://github.com/microformats/mf2py/pull/204
-* Prepare tests to test extensions by @angelogladding in https://github.com/microformats/mf2py/pull/214
-* Bring README doctests up-to-date by @angelogladding in https://github.com/microformats/mf2py/pull/215
-* Update README by @angelogladding in https://github.com/microformats/mf2py/pull/216
-* Fix tests/doctests by @angelogladding in https://github.com/microformats/mf2py/pull/217
-
-**Full Changelog**: https://github.com/microformats/mf2py/compare/v1.1.3...v2.0.0
-
-## 1.1.3 - 2022-06-28
-- reduce instances where photo is implied (#135)
-- always do relative URL resolution (#138)
-- VCP now handles tz offsets without leading zeros (#142)
-- implement id parsing (#143)
-- fix outdated syntax causing SyntaxWarning (#157)
-
-## 1.1.2 - 2018-08-08
-- add parsing for iframe.u-*[src] (#116)
-- bug fix: reduced implied urls (#117)
-- bug fix: don't collapse whitespace between tags
-- specify explicit versions for dependencies
-- revert BeautifulSoup copying added in 1.1.1 due to bugs (eg #108)
-- misc performance improvements
-
-## 1.1.1 - 2018-06-15
-
-- streamline backcompat to use JSON only.
-- fix multiple mf1 root rel-tag parsing
-- correct url and photo for hreview.
-- add rules for nested hreview. update backcompat to use multiple matches in old properties.
-- fix `rel-tag` to `p-category` conversion so that other classes are not lost.
-- use original authored html for `e-*` parsing in backcompat
-- make classes and rels into unordered (alphabetically ordered) deduped arrays.
-- only use class names for mf2 which follow the naming rules
-- fix `parse` method to use default html parser.
-- always use the first value for attributes for rels.
-- correct AM/PM conversion in datetime value class pattern.
- - add ordinal date parsing to datetimes value class pattern. ordinal date is normalised to YYYY-MM-DD
-- remove hack for html tag classes since that is fixed in new BS
-- better whitespace algorithm for `name` and `html.value` parsing
-- experimental flag for including `alt` in `u-photo` parsing
-- make a copy of the BeautifulSoup given by user to work on for parsing to prevent changes to original doc
-- bump version to 1.1.1
-
-## 1.1.0 - 2018-03-16
-
-- bump version to 1.1.0 since it is a "major" change
-- added tests for new implied name rules
-- modified earlier tests to accommodate new rules
-- use space separator instead of "T"
-- Don't add "00" seconds unless authored
-- use TZ authored in separate `value` element
-- only use first found `value` of a particular type `date`, `time`, or `timezone`.
-- move backcompat rules into JSON files
-- reorganise value class pattern parsing into new files
-- add datetime_helpers to organise datetime parsing rules
-- reorganise tests
-- remove Heroku frontend, point to mf2py-web and python.microformats.io instead in README.
-- remove Flask and gunicorn requirements
-- add debug info with description, version, url and the html parser used
-
-## 1.0.6 - 2018-03-04
-
-- strip leading/trailing white space for `e-*[html]`. update the corresponding tests
-- blank values explicitly authored are allowed as property values
-- include `alt` or `src` from ` ` in parsing for `p-*` and `e-*[value]`
-- parse `title` from ` ` for `p-*` resolves #84
-- and `poster` from `` for `u-*` resolves #76
-- use `html5lib` as default parser
-- use the final redirect URL resolves #62
-- update requirements to use BS4 v4.6.0 and html5lib v1.0.1
-- drop support for Python 2.6 as html5lib dropped support
-
-## 1.0.5 - 2016-05-09
-
-- Implied property checks now ignore alt="", treating it the same as
- if no alt value is defined.
-- Support for using a custom dict implementation by setting
- mf2py.Parser.dict_class. collections.OrderedDict yields much nicer
- output for hosted parsers.
-
-## 1.0.4 - 2016-03-21
-### Changed
-- Performance improvement changing simple calls to soup.find_all to
- a manual iteration over .contents.
-
-## 1.0.3 - 2016-02-05
-### Changed
-- Performance improvement by limiting number of calls to soup.find_all
- in backcompat module. Should not be any functional changes.
-
-## 1.0.2 - 2016-01-26
-### Added
-- Backward compatibility parsing for rel=tag properties. These are now converted
- to p-category based on the last path segment of the tag URI as spec'd in
- http://microformats.org/wiki/h-entry#Parser_Compatibility
-- Optional property html_parser to specify the html parser that BeautifulSoup
- should use (e.g., "lxml" or "html5lib")
-
-## 1.0.1 - 2015-12-11
-### Changed
-- `u-*` properties are now parsed from ` ` elements per the updated spec
- http://microformats.org/wiki/microformats2-parsing-issues#link_elements_and_u-_parsing
-
-## 1.0.0 - 2015-10-05
-### Changed
-- Version number bumped to 1.0.0 following community discussion.
-
-## 0.2.8 - 2015-09-21
-### Changed
-- Stricter checks that Parser.__init__ params are actually None before
- ignoring them.
-
-## 0.2.7 - 2015-08-03
-### Changed
-- Now produces unicode strings for every key and value, no more byte
- strings anywhere.
-- Do not add 'T' between date and time when normalizing dates
-### Added
-- Unit tests for running the microformats test suite
-
-## 0.2.6 - 2015-05-06
-### Added
-- New top-level "rel-urls" entry, contains rich data parsed from rel
- links, organized by URL.
-
-## 0.2.5 - 2015-03-01
-### Added
-- convenience method `mf2py.parse` that takes the same arguments as Parser
- and returns a dict.
-### Changed
-- nested h-* classes now parse their "value" based on the property
- they represent (p-*, u-*, dt-*), so for example "p-in-reply-to
- h-cite" would have a name as its value and "u-in-reply-to h-cite"
- will have a URL.
-
-## 0.2.4 - 2015-02-13
-### Added
-- Add rel=bookmark to backward compat parsing rules based (translated
- to u-url in mf2)
-### Changed
-- Parser constructor now takes explicit named arguments instead of
- **kwargs, for saner behavior when called with unnamed arguments.
-- Bugfix: Empty href="" attributes are now properly interpreted as
- the current document's URL.
-
-## 0.2.3 - 2015-02-07
-### Changed
-- Minor Py3 compatibility fix
-- Correct typo `test_requires` -> `tests_require` in setup.py
-
-## 0.2.2 - 2015-02-05
-### Changed
-- Started keeping a changelog!
-- Use a better method for extracting HTML for an e-* property
-- Correct BeautifulSoup4 dependency in setup.py to fix error with
- installation from PyPI.
-- Buffed up docstrings for public methods.
diff --git a/docs/changelog.md b/docs/changelog.md
new file mode 120000
index 0000000..04c99a5
--- /dev/null
+++ b/docs/changelog.md
@@ -0,0 +1 @@
+../CHANGELOG.md
\ No newline at end of file
diff --git a/docs/index.md b/docs/index.md
deleted file mode 100644
index 63b7b65..0000000
--- a/docs/index.md
+++ /dev/null
@@ -1,98 +0,0 @@
-# Home
-
-![mf2py banner](banner.png)
-
-## Welcome ๐
-
-`mf2py` is a full-featured microformats2 (mf2) parser implemented in Python.
-
-mf2py implements the full mf2 specification, including backward compatibility with microformats1.
-
-## Installation ๐ป
-
-To install `mf2py`, run the following command:
-
-```bash
-pip install mf2py
-```
-
-## Quickstart ๐
-
-Import the parser using:
-
-```python
-import mf2py
-```
-
-### Parse a File
-
-Parse a file containing HTML:
-
-```python
-with open('file/content.html','r') as file:
- obj = mf2py.parse(doc=file)
-```
-
-### Parse a String
-
-Parse string containing HTML content:
-
-```python
-content = 'Hello '
-obj = mf2py.parse(doc=content)
-```
-
-### Parse a HTML Document Retrieved from a URL
-
-Parse content from a URL:
-
-```python
-obj = mf2py.parse(url="http://tommorris.org/")
-```
-
-`parse` is a convenience method that actually delegates to
-`mf2py.Parser` to do the real work. More sophisticated behaviors are
-available by invoking the object directly.
-
-### Format Options
-
-Retrieve parsed microformats as a Python dictionary or JSON string:
-
-```python
-p = mf2py.Parser(...)
-p.to_dict() # returns a python dictionary
-p.to_json() # returns a JSON string
-```
-
-### Filter by Microformat Type
-
-Filter by microformat type:
-
-```python
-p.to_dict(filter_by_type="h-entry")
-p.to_json(filter_by_type="h-entry")
-```
-
-## Experimental Features ๐งช
-
-- Pass the optional argument `img_with_alt=True` to either the `Parser` object or to the `parse` method to enable parsing of the `alt` attribute of ` ` tags according to [issue: image alt text is lost during parsing](https://github.com/microformats/microformats2-parsing/issues/2). By default this is `False` to be backwards compatible.
-
-## FAQs โ
-
-* I passed `mf2py.parse()` a BeautifulSoup document, and it got modified!
-
-Yes, mf2py currently does that. We're working on preventing it! Hopefully soon.
-
-## Testing Environments ๐
-
-A hosted live version of mf2py can be found at [python.microformats.io](https://python.microformats.io).
-
-## Contributing ๐ ๏ธ
-
-We welcome contributions and bug reports via Github, and on the microformats wiki.
-
-We to follow the [IndieWebCamp code of conduct](http://indiewebcamp.com/code-of-conduct). Please be respectful of other contributors, and forge a spirit of positive co-operation without discrimination or disrespect.
-
-## License ๐งโโ๏ธ
-
-`mf2py` is licensed under an MIT License.
\ No newline at end of file
diff --git a/docs/index.md b/docs/index.md
new file mode 120000
index 0000000..32d46ee
--- /dev/null
+++ b/docs/index.md
@@ -0,0 +1 @@
+../README.md
\ No newline at end of file
diff --git a/docs/parser.md b/docs/parser.md
index 51e78df..8386e9f 100644
--- a/docs/parser.md
+++ b/docs/parser.md
@@ -1,5 +1,3 @@
-# Parse a Document
+# Parser Object
-## Parser
-
-:::mf2py.Parser
\ No newline at end of file
+:::mf2py.Parser
diff --git a/mf2py/parser.py b/mf2py/parser.py
index 0c1bee3..23accba 100644
--- a/mf2py/parser.py
+++ b/mf2py/parser.py
@@ -160,9 +160,9 @@ def __init__(
if document := self.__doc__.find("html"):
self.lang = document.attrs.get("lang")
# parse!
- self.parse()
+ self._parse()
- def parse(self):
+ def _parse(self):
"""Does the work of actually parsing the document. Done automatically
on initialization.
"""
diff --git a/mkdocs.yml b/mkdocs.yml
index 55e4c54..e45b5e8 100644
--- a/mkdocs.yml
+++ b/mkdocs.yml
@@ -12,8 +12,8 @@ extra_css:
nav:
- Home: index.md
- - Parse a Document: parser.md
- - Changelog: changelog.md
+ - Parser Object: parser.md
+ - Change Log: changelog.md
theme:
name: 'material'
@@ -43,4 +43,4 @@ markdown_extensions:
- pymdownx.tabbed:
alternate_style: true
- toc:
- permalink: true
\ No newline at end of file
+ permalink: true
diff --git a/pyproject.toml b/pyproject.toml
index 9a595fe..f347bfa 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,6 +1,6 @@
[tool.poetry]
name = "mf2py"
-version = "1.1.3"
+version = "2.0.0"
description = "Microformats parser"
authors = ["Tom Morris "]
license = "MIT"
@@ -23,6 +23,9 @@ mock = "^5.0.1"
pytest = "^7.2.1"
black = "^23.3.0"
isort = "^5.12.0"
+mkdocs = "^1.5.3"
+mkdocs-material = "^9.5.0"
+mkdocstrings = {extras = ["python"], version = "^0.24.0"}
[tool.pytest.ini_options]
doctest_optionflags = "NORMALIZE_WHITESPACE IGNORE_EXCEPTION_DETAIL"