From a5d9664a9264f45b088cc363331b391a40779b40 Mon Sep 17 00:00:00 2001 From: David Luevano Alvarado Date: Fri, 17 Feb 2023 01:06:26 -0600 Subject: finish testing and polishing, add readme --- README.md | 48 ++++++++++++++++++++++++++++++++++++-- pyproject.toml | 3 +++ requirements_dev.txt | 1 + setup.cfg | 24 +++++++++++++++---- src/pymdvar/__init__.py | 9 +++++++- src/pymdvar/pymdvar.py | 24 ++++++++----------- tests/conftest.py | 14 ++++++++++++ tests/test_pymdvar.py | 61 +++++++++++++++++++++++++++++++++++++++++-------- 8 files changed, 153 insertions(+), 31 deletions(-) create mode 100644 tests/conftest.py diff --git a/README.md b/README.md index e844e38..dcc978b 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,46 @@ -# pymdvar -Python's Markdown extension to insert variables +# pymdvar - Python-Markdown Variable extension + +Simple extension meant to be used to convert variables to their corresponding values. Works with environment variables too. + +It uses the `${variable}` syntax. For example, given `variable=value`, the following text: + +```md +Foo ${variable} bar +``` + +Becomes: + +```html +

Foo value bar

+``` + +## Install + +`pymdvar` can be installed via `pip`: + +```sh +python -m pip install pymdvar +``` + +## Usage + +The basic usage requires a dictionary with the variables to be passed to the `VariableExtension`: + +```py +>>> import markdown +>>> from pymdvar import VariableExtension +>>> markdown.markdown('foo *${test}* bar', extensions=[VariableExtension(variables={'test': 'value'})]) +'

foo value bar

' +``` + +if `enable_env=True` is passed, then it will read environment variables, too. Variables in `variables` take preference. + +Only `a-z`, `A-Z`, `_` and `0-9` characters are accepted. + +Passing the extension as a string is supported: + +```py +>>> import markdown +>>> markdown.markdown('foo *${test}* bar', extensions=['pymdvar'], extension_configs={'pymdvar': {'variables': {'test': 'value'}}}) +'

foo value bar

' +``` \ No newline at end of file diff --git a/pyproject.toml b/pyproject.toml index dcaca35..7744d62 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -7,6 +7,9 @@ addopts = "--cov-report term-missing --cov=pymdvar" testpaths = [ "tests", ] +env = [ + "PYMDVAR_TEST_1=1" +] [tool.mypy] mypy_path = "src" diff --git a/requirements_dev.txt b/requirements_dev.txt index 9979866..87baa83 100644 --- a/requirements_dev.txt +++ b/requirements_dev.txt @@ -1,5 +1,6 @@ pytest>=7.2.1 pytest-cov>=4.0.0 +pytest-env>=0.8.1 mypy>=1.0.0 flake8>=6.0.0 types-Markdown>=3.4.2.4 \ No newline at end of file diff --git a/setup.cfg b/setup.cfg index 13f4adc..24c970c 100644 --- a/setup.cfg +++ b/setup.cfg @@ -2,19 +2,35 @@ name = pymdvar author = David Luevano Alvarado author_email = david@luevano.xyz -summary = Python-Markdown extension to insert variables +summary = Python-Markdown extension for key-value pair conversion description_file = README.md license = GPLv3 home_page = https://github.com/luevano/pymdvar classifiers = - Programming Language :: Python :: 3 License :: OSI Approved :: GNU General Public License v3 (GPLv3) - Operating System :: Unix - Topic :: Text Processing :: Markup :: HTML + Operating System :: OS Independent, + Programming Language :: Python, + Programming Language :: Python :: 3, + Programming Language :: Python :: 3.7, + Programming Language :: Python :: 3.8, + Programming Language :: Python :: 3.9, + Programming Language :: Python :: 3.10, + Programming Language :: Python :: 3.11, + Programming Language :: Python :: 3 :: Only, + Topic :: Communications :: Email :: Filters, + Topic :: Internet :: WWW/HTTP :: Dynamic Content :: CGI Tools/Libraries, + Topic :: Internet :: WWW/HTTP :: Site Management, + Topic :: Software Development :: Documentation, + Topic :: Software Development :: Libraries :: Python Modules, + Topic :: Text Processing :: Filters, + Topic :: Text Processing :: Markup :: HTML, Topic :: Text Processing :: Markup :: Markdown keywords = python + extension + plugin markdown + website [files] packages = diff --git a/src/pymdvar/__init__.py b/src/pymdvar/__init__.py index b64a3b6..d8d4d4e 100644 --- a/src/pymdvar/__init__.py +++ b/src/pymdvar/__init__.py @@ -1,3 +1,10 @@ +from typing import Any from .pymdvar import VariableExtension -__all__ = ['VariableExtension'] \ No newline at end of file +__all__ = ['VariableExtension'] + + +# this should be in pymdvar.py, but since there is only one extension, +# it is fine in here +def makeExtension(*args: Any, **kwargs: Any): + return VariableExtension(*args, **kwargs) diff --git a/src/pymdvar/pymdvar.py b/src/pymdvar/pymdvar.py index d81f785..2dcdf96 100644 --- a/src/pymdvar/pymdvar.py +++ b/src/pymdvar/pymdvar.py @@ -1,4 +1,4 @@ -from os import getenv +import os from re import Match from typing import Any from xml.etree.ElementTree import Element @@ -6,7 +6,7 @@ from markdown import Markdown from markdown.extensions import Extension from markdown.inlinepatterns import Pattern -VAR_RE: str = r'(\$\{)([a-zA-Z_]*)(\})' +VAR_RE: str = r'(\$\{)([a-zA-Z_0-9]*)(\})' class VarPattern(Pattern): @@ -22,14 +22,12 @@ class VarPattern(Pattern): def handleMatch(self, m: Match[str]) -> str | Element | None: # for some reason the group is offest by 1 var: str | Any = m.group(3) - value: str = '' - if var in self.vars: - value = self.vars[var] - else: - if self.enable_env: - value = getenv(var, '') - return value + return self.vars[var] + if self.enable_env: + if var in os.environ: + return os.environ[var] + return '' class VariableExtension(Extension): @@ -41,11 +39,7 @@ class VariableExtension(Extension): super().__init__(**kwargs) def extendMarkdown(self, md: Markdown) -> None: - vars: dict[str, str] | Any = self.getConfig('variables', dict()) - enable_env: bool = self.getConfig('enable_env', False) + vars: dict[str, str] | Any = self.getConfig('variables') + enable_env: bool = self.getConfig('enable_env') var_pattern: VarPattern = VarPattern(VAR_RE, vars, enable_env) md.inlinePatterns.register(var_pattern, 'variable', 175) - - -def makeExtension(*args: Any, **kwargs: Any): - return VariableExtension(*args, **kwargs) diff --git a/tests/conftest.py b/tests/conftest.py new file mode 100644 index 0000000..df33848 --- /dev/null +++ b/tests/conftest.py @@ -0,0 +1,14 @@ +import pytest + + +@pytest.fixture +def single_var_dict(): + return {'test': 'value'} + + +@pytest.fixture +def multi_var_dict(): + return {'ext': 'jpg', + 'test': 'value', + 'TEST': 'VALUE', + 'SOMETHING_ELSE': 'something_else'} diff --git a/tests/test_pymdvar.py b/tests/test_pymdvar.py index 91a97d0..a4c4439 100644 --- a/tests/test_pymdvar.py +++ b/tests/test_pymdvar.py @@ -1,3 +1,4 @@ +import os import pytest from markdown import markdown from pymdvar import VariableExtension @@ -5,31 +6,73 @@ from pymdvar import VariableExtension def test_empty_input(): in_str: str = '' + exp_str: str = markdown(in_str) out_str: str = markdown(in_str, extensions=[VariableExtension()]) - assert in_str == out_str + assert out_str == exp_str @pytest.mark.parametrize('in_str, exp_str', [ ('foo bar', '

foo bar

'), ('foo *test* bar', '

foo test bar

'), - ('foo **test** bar', '

foo test bar

'), + ('foo *PYMDVAR_TEST_1* bar', '

foo PYMDVAR_TEST_1 bar

'), ('foo $test bar', '

foo $test bar

'), - ('foo *${test* bar', '

foo ${test bar

'), ('foo **$test}** bar', '

foo $test} bar

'), + ('foo **$PYMDVAR_TEST_2}** bar', '

foo $PYMDVAR_TEST_2} bar

'), + ('foo [link](${test/a.html) bar', '

foo link bar

'), + ('foo ![image]($test}/a.jpg) bar', '

foo image bar

') +]) +def test_no_replacements_config(in_str: str, exp_str: str, single_var_dict: dict[str, str]): + out_str: str = markdown(in_str, extensions=[VariableExtension(variables=single_var_dict, enable_env=True)]) + assert out_str == exp_str + + +@pytest.mark.parametrize('in_str, exp_str', [ + ('foo *${test}* bar', '

foo bar

'), + ('foo *${PYMDVAR_TEST_1}* bar', '

foo bar

'), + ('foo [link](${test}/a.html) bar', '

foo link bar

'), ]) -def test_non_replacements(in_str, exp_str): +def test_replacements_no_config(in_str: str, exp_str: str): out_str: str = markdown(in_str, extensions=[VariableExtension()]) assert out_str == exp_str @pytest.mark.parametrize('in_str, exp_str', [ - ('foo ${test} bar', '

foo value bar

'), ('foo *${test}* bar', '

foo value bar

'), - ('foo **${test}** bar', '

foo value bar

'), + ('foo *${PYMDVAR_TEST_1}* bar', '

foo 1 bar

'), + ('foo ${value} bar', '

foo bar

'), + ('foo **${PYMDVAR_TEST_2}** bar', '

foo bar

'), ('foo [link](${test}/a.html) bar', '

foo link bar

'), - ('foo ![image](${test}/a.jpg) bar', '

foo image bar

'), + ('foo ![image](${PYMDVAR_TEST_1}/a.jpg) bar', '

foo image bar

'), + ('foo [link](${PYMDVAR_TEST_2}/a.html) bar', '

foo link bar

') ]) -def test_simple_replacements(in_str, exp_str): - out_str: str = markdown(in_str, extensions=[VariableExtension(variables={'test':'value'})]) +def test_simple_replacements(in_str: str, exp_str: str, single_var_dict: dict[str, str]): + out_str: str = markdown(in_str, extensions=[VariableExtension(variables=single_var_dict, enable_env=True)]) assert out_str == exp_str + +@pytest.mark.parametrize('in_str, exp_str', [ + ('foo *${test}* bar', '

foo value bar

'), + ('foo *${TEST}* bar', '

foo VALUE bar

'), + ('foo **${SOMETHING_ELSE}** bar', '

foo something_else bar

') +]) +def test_multivar_replacements(in_str: str, exp_str: str, multi_var_dict: dict[str, str]): + out_str: str = markdown(in_str, extensions=[VariableExtension(variables=multi_var_dict)]) + assert out_str == exp_str + + +@pytest.mark.parametrize('in_str, exp_str', [ + ('foo *${test}* and **${TEST}** bar', '

foo value and VALUE bar

'), + ('foo ![image](${PYMDVAR_TEST_1}/a.${ext}) bar', '

foo image bar

') +]) +def test_text_multivar_replacements(in_str: str, exp_str: str, multi_var_dict: dict[str, str]): + out_str: str = markdown(in_str, extensions=[VariableExtension(variables=multi_var_dict)]) + assert out_str == exp_str + + +@pytest.mark.parametrize('in_str, exp_str', [ + ('foo *${test}* and **${TEST}** bar', '

foo value and VALUE bar

'), + ('foo ![image](${PYMDVAR_TEST_1}/a.${ext}) bar', '

foo image bar

') +]) +def test_extension_text_mode(in_str: str, exp_str: str, multi_var_dict: dict[str, str]): + out_str: str = markdown(in_str, extensions=['pymdvar'], extension_configs={'pymdvar': {'variables': multi_var_dict}}) + assert out_str == exp_str -- cgit v1.2.3-70-g09d2