clld-markdown-plugin 0.4.0__tar.gz → 1.0.0__tar.gz

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.
@@ -1,29 +1,43 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: clld_markdown_plugin
3
- Version: 0.4.0
3
+ Version: 1.0.0
4
4
  Summary: Render CLDF markdown in clld apps.
5
5
  Home-page: https://github.com/clld/clld-markdown-plugin
6
6
  Author: Robert Forkel, Florian Matter
7
7
  Author-email: robert_forkel@eva.mpg.de, florianmatter@gmail.com
8
8
  Project-URL: Bug Tracker, https://github.com/clld/clld-markdown-plugin/issues
9
- Classifier: Development Status :: 2 - Pre-Alpha
9
+ Classifier: Development Status :: 5 - Production/Stable
10
10
  Classifier: Intended Audience :: Science/Research
11
11
  Classifier: License :: OSI Approved :: Apache Software License
12
12
  Classifier: Natural Language :: English
13
13
  Classifier: Programming Language :: Python :: 3
14
- Classifier: Programming Language :: Python :: 3.8
15
14
  Classifier: Programming Language :: Python :: 3.9
16
15
  Classifier: Programming Language :: Python :: 3.10
17
16
  Classifier: Programming Language :: Python :: 3.11
18
17
  Classifier: Programming Language :: Python :: 3.12
18
+ Classifier: Programming Language :: Python :: 3.13
19
+ Classifier: Programming Language :: Python :: 3.14
19
20
  Description-Content-Type: text/markdown
21
+ License-File: LICENSE
22
+ Requires-Dist: frontmatter<1.2; python_version < "3.10"
23
+ Requires-Dist: clldutils
24
+ Requires-Dist: pycldf
25
+ Requires-Dist: clld
26
+ Requires-Dist: markdown
20
27
  Provides-Extra: dev
28
+ Requires-Dist: flake8; extra == "dev"
29
+ Requires-Dist: twine; extra == "dev"
30
+ Requires-Dist: wheel; extra == "dev"
31
+ Requires-Dist: build; extra == "dev"
21
32
  Provides-Extra: test
22
- License-File: LICENSE
33
+ Requires-Dist: pytest; extra == "test"
34
+ Requires-Dist: pytest-mock; extra == "test"
35
+ Requires-Dist: pytest-cov; extra == "test"
36
+ Requires-Dist: tox; extra == "test"
23
37
 
24
38
  # clld-markdown-plugin
25
39
 
26
- Render CLDF markdown in clld apps
40
+ Render [CLDF markdown](https://github.com/cldf/cldf/blob/master/extensions/markdown.md) in clld apps
27
41
 
28
42
  ## Usage
29
43
 
@@ -47,8 +61,25 @@ Then you can use `clld_markdown_plugin.markup` as follows in your templates:
47
61
  ${markdown(req, '[x](LanguageTable#cldf:abad1241)')|n}
48
62
  ```
49
63
 
64
+ By default, links to objects in the CLDF dataset will be rendered as HTML links to the corresponding
65
+ object's details page in the clld app.
66
+
67
+
68
+ ### Configuration
69
+
70
+ The plugin can be configured via the following four configuration options:
71
+
72
+ - `model_map`: A `dict` mapping CLDF component names to DB model classes defined for the app. This
73
+ allows for a flexible mapping between CLDF components and the clld DB classes.
74
+ - `renderer_map`: See below for details.
75
+ - `extensions`: A list of [markdown extensions](https://python-markdown.github.io/extensions/#officially-supported-extensions)
76
+ in dot notation, to be activated when calling the `markdown` function.
77
+ - `keep_link_labels`: A `boolean` indicating whether to keep link labels as they appear in the
78
+ CLDF Markdown text. By default (`False`), labels will be substituted using the linked object's
79
+ name.
80
+
50
81
 
51
- ### Renderer callables
82
+ #### Renderer callables
52
83
 
53
84
  The `renderer_map` configuration option for `clld_markdown_plugin` accepts a `dict` mapping
54
85
  CLDF component names to Python callables with the following signature:
@@ -1,6 +1,6 @@
1
1
  # clld-markdown-plugin
2
2
 
3
- Render CLDF markdown in clld apps
3
+ Render [CLDF markdown](https://github.com/cldf/cldf/blob/master/extensions/markdown.md) in clld apps
4
4
 
5
5
  ## Usage
6
6
 
@@ -24,8 +24,25 @@ Then you can use `clld_markdown_plugin.markup` as follows in your templates:
24
24
  ${markdown(req, '[x](LanguageTable#cldf:abad1241)')|n}
25
25
  ```
26
26
 
27
+ By default, links to objects in the CLDF dataset will be rendered as HTML links to the corresponding
28
+ object's details page in the clld app.
27
29
 
28
- ### Renderer callables
30
+
31
+ ### Configuration
32
+
33
+ The plugin can be configured via the following four configuration options:
34
+
35
+ - `model_map`: A `dict` mapping CLDF component names to DB model classes defined for the app. This
36
+ allows for a flexible mapping between CLDF components and the clld DB classes.
37
+ - `renderer_map`: See below for details.
38
+ - `extensions`: A list of [markdown extensions](https://python-markdown.github.io/extensions/#officially-supported-extensions)
39
+ in dot notation, to be activated when calling the `markdown` function.
40
+ - `keep_link_labels`: A `boolean` indicating whether to keep link labels as they appear in the
41
+ CLDF Markdown text. By default (`False`), labels will be substituted using the linked object's
42
+ name.
43
+
44
+
45
+ #### Renderer callables
29
46
 
30
47
  The `renderer_map` configuration option for `clld_markdown_plugin` accepts a `dict` mapping
31
48
  CLDF component names to Python callables with the following signature:
@@ -1,18 +1,19 @@
1
1
  [metadata]
2
- version = 0.4.0
2
+ version = 1.0.0
3
3
  author = Robert Forkel, Florian Matter
4
4
  author_email = robert_forkel@eva.mpg.de, florianmatter@gmail.com
5
5
  classifiers =
6
- Development Status :: 2 - Pre-Alpha
6
+ Development Status :: 5 - Production/Stable
7
7
  Intended Audience :: Science/Research
8
8
  License :: OSI Approved :: Apache Software License
9
9
  Natural Language :: English
10
10
  Programming Language :: Python :: 3
11
- Programming Language :: Python :: 3.8
12
11
  Programming Language :: Python :: 3.9
13
12
  Programming Language :: Python :: 3.10
14
13
  Programming Language :: Python :: 3.11
15
14
  Programming Language :: Python :: 3.12
15
+ Programming Language :: Python :: 3.13
16
+ Programming Language :: Python :: 3.14
16
17
  description = Render CLDF markdown in clld apps.
17
18
  long_description = file: README.md
18
19
  long_description_content_type = text/markdown
@@ -28,6 +29,7 @@ packages = find:
28
29
  package_dir =
29
30
  =src
30
31
  install_requires =
32
+ frontmatter<1.2;python_version<"3.10"
31
33
  clldutils
32
34
  pycldf
33
35
  clld
@@ -67,7 +69,7 @@ source =
67
69
  show_missing = true
68
70
 
69
71
  [tox:tox]
70
- envlist = py38, py39, py310, py311, py312
72
+ envlist = py39, py310, py311, py312, py313, py314
71
73
  isolated_build = true
72
74
  skip_missing_interpreter = true
73
75
 
@@ -1,10 +1,12 @@
1
1
  """Top-level package for clld-markdown-plugin."""
2
- import typing
3
2
  import logging
3
+ from collections.abc import Sequence
4
+ from typing import Optional, Callable, Any
4
5
 
5
6
  from markdown import Markdown
6
7
  from markdown import markdown as base_markdown
7
8
  from pycldf.ext.markdown import CLDFMarkdownLink
9
+ from clld.web.app import ClldRequest
8
10
  from clld.db.meta import DBSession
9
11
  from clld.db.models import common
10
12
  from clld.web.util.helpers import rendered_sentence
@@ -16,11 +18,12 @@ log = logging.getLogger(__name__)
16
18
 
17
19
  __author__ = "Robert Forkel, Florian Matter"
18
20
  __email__ = "robert_forkel@eva.mpg.de, florianmatter@gmail.com"
19
- __version__ = "0.4.0"
21
+ __version__ = "1.0.0"
20
22
  __all__ = ['markdown', 'includeme']
21
23
 
22
24
 
23
- def settings(custom: typing.Optional[dict] = None) -> dict:
25
+ def settings(custom: Optional[dict[str, Any]] = None) -> dict[str, Any]:
26
+ """Settings relevant for rendering CLDF Markdown."""
24
27
  def full_spec(spec):
25
28
  return spec if isinstance(spec, dict) else {
26
29
  'route': spec.__name__.split('.')[-1].lower() if spec else '', 'model': spec}
@@ -43,10 +46,11 @@ def settings(custom: typing.Optional[dict] = None) -> dict:
43
46
  "extensions": [
44
47
  "markdown.extensions.fenced_code",
45
48
  "markdown.extensions.tables",
46
- ]
49
+ ],
50
+ "keep_link_labels": False,
47
51
  }
48
52
  custom = custom or {}
49
- for key in res:
53
+ for key in res: # pylint: disable=consider-using-dict-items
50
54
  if key == 'model_map':
51
55
  for k, v in custom.get(key, {}).items():
52
56
  res[key][k] = full_spec(v)
@@ -54,6 +58,8 @@ def settings(custom: typing.Optional[dict] = None) -> dict:
54
58
  res[key].update(custom.get(key, {}))
55
59
  elif key == "extensions":
56
60
  res[key].extend(custom.get(key, []))
61
+ elif key in custom:
62
+ res[key] = custom[key]
57
63
  return res
58
64
 
59
65
 
@@ -75,41 +81,48 @@ def includeme(config):
75
81
  return config
76
82
 
77
83
 
78
- def comma_and_list(entries, sep1=", ", sep2=" and "):
84
+ def _comma_and_list(entries: Sequence[str], sep1: str = ", ", sep2: str = " and ") -> str:
79
85
  output = entries[0]
80
86
  for entry in entries[1:-1]:
81
87
  output += sep1 + entry
82
88
  return output + sep2 + entries[-1]
83
89
 
84
90
 
85
- def link_entity(req, objid, route, model, session, decorate=None, ids=None, **kwargs):
91
+ def link_entity( # pylint: disable=R0913,R0917
92
+ req: ClldRequest,
93
+ objid: str,
94
+ route: str,
95
+ model: type,
96
+ session,
97
+ decorate: Optional[Callable[[str], str]] = None,
98
+ ids: Optional[Sequence[str]] = None,
99
+ **kwargs,
100
+ ) -> str:
101
+ """Render a CLDF Markdown link as HTML."""
86
102
  if objid == "__all__":
87
103
  if ids:
88
- md_strs = [
104
+ return _comma_and_list([
89
105
  link_entity(req, mid, route, model, session, decorate=decorate, **kwargs)
90
106
  for mid in ids[0].split(",")
91
- ]
92
- return comma_and_list(md_strs)
107
+ ])
93
108
  raise NotImplementedError("Table not yet implemented") # pragma: no cover
94
- else:
95
- try:
96
- entity = session.query(model).filter(model.id == objid)[0]
97
- except IndexError:
98
- raise ValueError(objid) # pragma: no cover
99
- label = kwargs.pop("label", [None])[0]
100
- anchor = kwargs.pop("_anchor", [None])[0]
101
- url = req.route_url(route, id=objid, _anchor=anchor, **kwargs)
102
- md_str = '<a class="{}" href="{}">{}</a>'.format(
103
- model.__tablename__.capitalize(), url, label or entity.name)
104
- return decorate(md_str) if decorate else md_str
105
-
106
-
107
- def render_ex(req, objid, table, session, ids=None, **kw):
109
+ try:
110
+ entity = session.query(model).filter(model.id == objid)[0]
111
+ except IndexError as e:
112
+ raise ValueError(objid) from e # pragma: no cover
113
+ label = kwargs.pop("label", [None])[0] or entity.name
114
+ anchor = kwargs.pop("_anchor", [None])[0]
115
+ url = req.route_url(route, id=objid, _anchor=anchor, **kwargs)
116
+ md_str = f'<a class="{model.__tablename__.capitalize()}" href="{url}">{label}</a>'
117
+ return decorate(md_str) if decorate else md_str
118
+
119
+
120
+ def render_ex(req: ClldRequest, objid: str, table: str, session, ids=None, **_) -> str:
121
+ """Render an IGT example."""
108
122
  if objid == "__all__":
109
123
  if ids:
110
124
  ex_strs = [
111
- render_ex(req, mid, table, session, subexample=True) for mid in ids[0].split(",")
112
- ]
125
+ render_ex(req, mid, table, session, subexample=True) for mid in ids[0].split(",")]
113
126
  return '\n\n'.join(ex_strs)
114
127
  return rendered_sentence(session.query(common.Sentence).filter(common.Sentence.id == objid)[0])
115
128
 
@@ -124,9 +137,8 @@ def markdown(req, s: str, session=None) -> str:
124
137
  """
125
138
  if __name__ not in req.registry.settings: # pragma: no cover
126
139
  raise KeyError(
127
- '{} must be included in the app config to use the "markdown" function.'.format(
128
- __name__))
129
- settings = req.registry.settings[__name__]
140
+ f'{__name__} must be included in the app config to use the "markdown" function.')
141
+ settings_ = req.registry.settings[__name__]
130
142
  source_ids = set()
131
143
 
132
144
  def repl(ml):
@@ -138,17 +150,19 @@ def markdown(req, s: str, session=None) -> str:
138
150
  if ml.is_cldf_link:
139
151
  try:
140
152
  table = ml.table_or_fname
141
- if table in settings['renderer_map'] and "as_link" not in ml.parsed_url_query:
142
- return settings['renderer_map'][table](
153
+ if table in settings_['renderer_map'] and "as_link" not in ml.parsed_url_query:
154
+ return settings_['renderer_map'][table](
143
155
  req, ml.objid, table, session or DBSession, **ml.parsed_url_query)
144
- elif table in settings['model_map']:
145
- decorate = settings['model_map'][table].get("decorate", None)
146
- kw = {k: v for k, v in ml.parsed_url_query.items()}
156
+ if table in settings_['model_map']:
157
+ decorate = settings_['model_map'][table].get("decorate", None)
158
+ kw = dict(ml.parsed_url_query.items())
159
+ if ml.label and settings_['keep_link_labels']:
160
+ kw.setdefault('label', [ml.label])
147
161
  if table == 'Source':
148
162
  if ml.objid != '__all__':
149
163
  source_ids.add(ml.objid)
150
164
  elif 'cited_only' in ml.parsed_url.query:
151
- model = settings['model_map'][table]["model"]
165
+ model = settings_['model_map'][table]["model"]
152
166
  return HTML.ul(*[
153
167
  HTML.li(literal(ref(
154
168
  (session or DBSession).query(model).filter(model.id == sid)[0]
@@ -157,16 +171,16 @@ def markdown(req, s: str, session=None) -> str:
157
171
  return link_entity(
158
172
  req,
159
173
  ml.objid,
160
- settings['model_map'][table]["route"],
161
- settings['model_map'][table]["model"],
174
+ settings_['model_map'][table]["route"],
175
+ settings_['model_map'][table]["model"],
162
176
  session or DBSession,
163
177
  decorate=decorate,
164
178
  **kw,
165
179
  )
166
- log.error(f"Can't handle [{ml.objid}] ({table}).")
180
+ log.error("Can't handle [%s] (%s).", ml.objid, table)
167
181
  return f"{table}:{ml.objid}"
168
- except: # noqa: E722
182
+ except: # noqa: E722 # pylint: disable=W0702
169
183
  return ml.label
170
184
  return ml
171
185
 
172
- return Markdown(extensions=settings["extensions"]).convert(CLDFMarkdownLink.replace(s, repl))
186
+ return Markdown(extensions=settings_["extensions"]).convert(CLDFMarkdownLink.replace(s, repl))
@@ -1,29 +1,43 @@
1
1
  Metadata-Version: 2.1
2
- Name: clld-markdown-plugin
3
- Version: 0.4.0
2
+ Name: clld_markdown_plugin
3
+ Version: 1.0.0
4
4
  Summary: Render CLDF markdown in clld apps.
5
5
  Home-page: https://github.com/clld/clld-markdown-plugin
6
6
  Author: Robert Forkel, Florian Matter
7
7
  Author-email: robert_forkel@eva.mpg.de, florianmatter@gmail.com
8
8
  Project-URL: Bug Tracker, https://github.com/clld/clld-markdown-plugin/issues
9
- Classifier: Development Status :: 2 - Pre-Alpha
9
+ Classifier: Development Status :: 5 - Production/Stable
10
10
  Classifier: Intended Audience :: Science/Research
11
11
  Classifier: License :: OSI Approved :: Apache Software License
12
12
  Classifier: Natural Language :: English
13
13
  Classifier: Programming Language :: Python :: 3
14
- Classifier: Programming Language :: Python :: 3.8
15
14
  Classifier: Programming Language :: Python :: 3.9
16
15
  Classifier: Programming Language :: Python :: 3.10
17
16
  Classifier: Programming Language :: Python :: 3.11
18
17
  Classifier: Programming Language :: Python :: 3.12
18
+ Classifier: Programming Language :: Python :: 3.13
19
+ Classifier: Programming Language :: Python :: 3.14
19
20
  Description-Content-Type: text/markdown
21
+ License-File: LICENSE
22
+ Requires-Dist: frontmatter<1.2; python_version < "3.10"
23
+ Requires-Dist: clldutils
24
+ Requires-Dist: pycldf
25
+ Requires-Dist: clld
26
+ Requires-Dist: markdown
20
27
  Provides-Extra: dev
28
+ Requires-Dist: flake8; extra == "dev"
29
+ Requires-Dist: twine; extra == "dev"
30
+ Requires-Dist: wheel; extra == "dev"
31
+ Requires-Dist: build; extra == "dev"
21
32
  Provides-Extra: test
22
- License-File: LICENSE
33
+ Requires-Dist: pytest; extra == "test"
34
+ Requires-Dist: pytest-mock; extra == "test"
35
+ Requires-Dist: pytest-cov; extra == "test"
36
+ Requires-Dist: tox; extra == "test"
23
37
 
24
38
  # clld-markdown-plugin
25
39
 
26
- Render CLDF markdown in clld apps
40
+ Render [CLDF markdown](https://github.com/cldf/cldf/blob/master/extensions/markdown.md) in clld apps
27
41
 
28
42
  ## Usage
29
43
 
@@ -47,8 +61,25 @@ Then you can use `clld_markdown_plugin.markup` as follows in your templates:
47
61
  ${markdown(req, '[x](LanguageTable#cldf:abad1241)')|n}
48
62
  ```
49
63
 
64
+ By default, links to objects in the CLDF dataset will be rendered as HTML links to the corresponding
65
+ object's details page in the clld app.
66
+
67
+
68
+ ### Configuration
69
+
70
+ The plugin can be configured via the following four configuration options:
71
+
72
+ - `model_map`: A `dict` mapping CLDF component names to DB model classes defined for the app. This
73
+ allows for a flexible mapping between CLDF components and the clld DB classes.
74
+ - `renderer_map`: See below for details.
75
+ - `extensions`: A list of [markdown extensions](https://python-markdown.github.io/extensions/#officially-supported-extensions)
76
+ in dot notation, to be activated when calling the `markdown` function.
77
+ - `keep_link_labels`: A `boolean` indicating whether to keep link labels as they appear in the
78
+ CLDF Markdown text. By default (`False`), labels will be substituted using the linked object's
79
+ name.
80
+
50
81
 
51
- ### Renderer callables
82
+ #### Renderer callables
52
83
 
53
84
  The `renderer_map` configuration option for `clld_markdown_plugin` accepts a `dict` mapping
54
85
  CLDF component names to Python callables with the following signature:
@@ -3,6 +3,9 @@ pycldf
3
3
  clld
4
4
  markdown
5
5
 
6
+ [:python_version < "3.10"]
7
+ frontmatter<1.2
8
+
6
9
  [dev]
7
10
  flake8
8
11
  twine
@@ -29,3 +29,10 @@ def test_markdown(model_map, renderer_map, md, substring, notsubstring, dbsessio
29
29
  assert substring in res
30
30
  if notsubstring:
31
31
  assert notsubstring not in res
32
+
33
+
34
+ def test_markdown_keep_labels(dbsession, req_factory):
35
+ res = markdown(req_factory(), '[xyz](LanguageTable#cldf:l1)')
36
+ assert 'xyz' not in res
37
+ res = markdown(req_factory(dict(keep_link_labels=True)), '[xyz](LanguageTable#cldf:l1)')
38
+ assert 'xyz' in res