New Research: Supply Chain Attack on Axios Pulls Malicious Dependency from npm.Details →
Socket
Book a DemoSign in
Socket

mkdocs-table-reader-plugin

Package Overview
Dependencies
Maintainers
1
Versions
27
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

mkdocs-table-reader-plugin - pypi Package Compare versions

Comparing version
2.2.2
to
3.0.0
+4
-3
mkdocs_table_reader_plugin.egg-info/PKG-INFO
Metadata-Version: 2.1
Name: mkdocs-table-reader-plugin
Version: 2.2.2
Version: 3.0.0
Summary: MkDocs plugin to directly insert tables from files into markdown.

@@ -66,5 +66,6 @@ Home-page: https://github.com/timvink/mkdocs-table-reader-plugin

Where the path is relative to the location of your project's `mkdocs.yml` file (although you can [change that](https://timvink.github.io/mkdocs-table-reader-plugin/options) to be relative to your `docs/` directory).
Where the path is relative to the location of your project's `mkdocs.yml` file, _or_ your project's `docs/` directory, _or_ the location of your markdown source file (all 3 possible locations will be searched, in that order).
- There are [readers](https://timvink.github.io/mkdocs-table-reader-plugin/readers/) for `.csv`, `.fwf`, `.json`, `.xlsx`, `.yaml` and `.tsv` files. There is also the `read_raw()` reader that will allow you to insert tables (or other content) already in markdown format.
- There are [readers](https://timvink.github.io/mkdocs-table-reader-plugin/readers/) for `.csv`, `.fwf`, `.json`, `.xls`, `.xlsx`, `.yaml`, `.feather` and `.tsv` files. There is also the `read_raw()` reader that will allow you to insert tables (or other content) already in markdown format.
- `table-reader` is compatible with [`mkdocs-macros-plugin`](https://mkdocs-macros-plugin.readthedocs.io/en/latest/), which means you can [dynamically insert tables using jinja2 syntax](https://timvink.github.io/mkdocs-table-reader-plugin/howto/use_jinja2/).

@@ -71,0 +72,0 @@ ## Documentation and how-to guides

@@ -6,6 +6,7 @@ import re

def replace_unescaped_pipes(text: str) -> str:
"""
Replace unescaped pipes.
For regex explanation, see https://regex101.com/r/s8H588/1

@@ -28,3 +29,5 @@

# See https://github.com/astanin/python-tabulate/issues/241
df.columns = [replace_unescaped_pipes(c) if isinstance(c, str) else c for c in df.columns]
df.columns = [
replace_unescaped_pipes(c) if isinstance(c, str) else c for c in df.columns
]

@@ -36,3 +39,5 @@ # Avoid deprecated applymap warning on pandas>=2.0

else:
df = df.applymap(lambda s: replace_unescaped_pipes(s) if isinstance(s, str) else s)
df = df.applymap(
lambda s: replace_unescaped_pipes(s) if isinstance(s, str) else s
)

@@ -43,3 +48,3 @@ if "index" not in markdown_kwargs:

markdown_kwargs["tablefmt"] = "pipe"
return df.to_markdown(**markdown_kwargs)

@@ -63,5 +68,5 @@

fixed_lines = []
for line in text.split('\n'):
for line in text.split("\n"):
fixed_lines.append(textwrap.indent(line, leading_spaces))
text = "\n".join(fixed_lines)
return text

@@ -1,6 +0,4 @@

import os
import re
import logging
from mkdocs.plugins import BasePlugin
from mkdocs.plugins import BasePlugin, get_plugin_logger
from mkdocs.config import config_options

@@ -13,12 +11,16 @@ from mkdocs.exceptions import ConfigurationError

logger = logging.getLogger("mkdocs.plugins")
logger = get_plugin_logger("table-reader")
class TableReaderPlugin(BasePlugin):
config_scheme = (
("base_path", config_options.Choice(['docs_dir','config_dir'], default="config_dir")),
("data_path", config_options.Type(str, default=".")),
("search_page_directory", config_options.Type(bool, default=True)),
("allow_missing_files", config_options.Type(bool, default=False)),
("select_readers", config_options.ListOfItems(config_options.Choice(list(READERS.keys())), default = list(READERS.keys()))),
(
"select_readers",
config_options.ListOfItems(
config_options.Choice(list(READERS.keys())),
default=list(READERS.keys()),
),
),
)

@@ -36,10 +38,62 @@

"""
if "search_page_directory" in self.config:
logger.warning(
"[table-reader]: The 'search_page_directory' configuration option is deprecated, it will always be searched. Please remove it from your mkdocs.yml."
)
if "base_path" in self.config:
logger.warning(
"[table-reader]: The 'base_path' configuration option is deprecated. Both the config_dir and docs_dir will be searched. Please remove it from your mkdocs.yml."
)
self.readers = {
reader: READERS[reader].set_config_context(
mkdocs_config=config, plugin_config=self.config
)
for reader in self.config.get("select_readers")
if reader in self.config.get("select_readers", [])
}
plugins = [p for p in config.get("plugins")]
for post_load_plugin in ["macros", "markdownextradata"]:
# Plugins required before table-reader
for post_load_plugin in ["markdownextradata"]:
if post_load_plugin in plugins:
if plugins.index("table-reader") > plugins.index(post_load_plugin):
raise ConfigurationError(f"[table-reader]: Incompatible plugin order: Define 'table-reader' before '{post_load_plugin}' in your mkdocs.yml.")
raise ConfigurationError(
f"[table-reader]: Incompatible plugin order: Define 'table-reader' before '{post_load_plugin}' in your mkdocs.yml."
)
# Plugins required after table-reader
for post_load_plugin in ["macros"]:
if post_load_plugin in plugins:
if plugins.index("table-reader") < plugins.index(post_load_plugin):
raise ConfigurationError(
f"[table-reader]: Incompatible plugin order: Define 'table-reader' after '{post_load_plugin}' in your mkdocs.yml."
)
if "macros" in config.plugins:
config.plugins["macros"].macros.update(self.readers)
config.plugins["macros"].variables["macros"].update(self.readers)
config.plugins["macros"].env.globals.update(self.readers)
self.external_jinja_engine = True
else:
self.external_jinja_engine = False
def on_pre_page(self, page, config, **kwargs):
"""
See https://www.mkdocs.org/dev-guide/plugins/#on_pre_page.
Args:
page: mkdocs.nav.Page instance
config: global configuration object
Returns:
Page
"""
# store the current page in the plugin config
# because the readers have access to the plugin config, they can know where the current page is
# this way, they can check that directory too
self.config._current_page = page.file.abs_src_path
return page
def on_page_markdown(self, markdown, page, config, files, **kwargs):

@@ -65,19 +119,9 @@ """

"""
# Determine the mkdocs directory
# We do this during the on_page_markdown() event because other plugins
# might have changed the directory.
if self.config.get("base_path") == "config_dir":
mkdocs_dir = os.path.dirname(os.path.abspath(config["config_file_path"]))
if self.config.get("base_path") == "docs_dir":
mkdocs_dir = os.path.abspath(config["docs_dir"])
# Define directories to search for tables
search_directories = [os.path.join(mkdocs_dir, self.config.get("data_path"))]
if self.config.get("search_page_directory"):
search_directories.append(os.path.dirname(page.file.abs_src_path))
if self.external_jinja_engine:
return markdown
for reader in self.config.get('select_readers'):
function = READERS[reader]
for reader in self.readers:
function = self.readers[reader]
# Regex pattern for tags like {{ read_csv(..) }}
# match group 0: to extract any leading whitespace
# match group 0: to extract any leading whitespace
# match group 1: to extract the arguments (positional and keywords)

@@ -88,5 +132,4 @@ tag_pattern = re.compile(

matches = re.findall(tag_pattern, markdown)
for result in matches:
# Deal with indentation

@@ -100,32 +143,4 @@ # So we can fix inserting tables.

# Extract the filepath,
# which is the first positional argument
# or a named argument when there are no positional arguments
if len(pd_args) > 0:
input_file_path = pd_args.pop(0)
else:
input_file_path = pd_kwargs.pop("filepath_or_buffer")
# Validate if file exists
search_file_paths = [os.path.join(search_dir, input_file_path) for search_dir in search_directories]
valid_file_paths = [p for p in search_file_paths if os.path.exists(p)]
if len(valid_file_paths) == 0:
msg = f"[table-reader-plugin]: Cannot find table file '{input_file_path}'. The following directories were searched: {*search_directories,}"
if self.config.get("allow_missing_files"):
logger.warning(msg)
# Add message in markdown
updated_tag = fix_indentation(leading_spaces, f"{{{{ Cannot find '{input_file_path}' }}}}")
markdown = tag_pattern.sub(updated_tag, markdown, count=1)
continue
else:
raise FileNotFoundError(msg)
# Load the table
# note we use the first valid file paths,
# where we first search the 'data_path' and then the page's directory.
markdown_table = function(valid_file_paths[0], *pd_args, **pd_kwargs)
markdown_table = fix_indentation(leading_spaces, markdown_table)
markdown_table = function(*pd_args, **pd_kwargs)

@@ -137,6 +152,5 @@ # Insert markdown table

# This is always why when allow_missing_files=True we replaced the input tag.
markdown_table = fix_indentation(leading_spaces, markdown_table)
markdown = tag_pattern.sub(markdown_table, markdown, count=1)
return markdown
import pandas as pd
import yaml
import os
from pathlib import Path
import logging
from mkdocs_table_reader_plugin.utils import kwargs_in_func, kwargs_not_in_func
import functools
from mkdocs_table_reader_plugin.utils import kwargs_in_func, kwargs_not_in_func
from mkdocs_table_reader_plugin.markdown import convert_to_md_table
def read_csv(*args, **kwargs):
logger = logging.getLogger("mkdocs.plugins")
class ParseArgs:
def __init__(self, func):
functools.update_wrapper(self, func)
self.func = func
self.mkdocs_config = None
self.plugin_config = None
def set_config_context(self, mkdocs_config, plugin_config):
self.mkdocs_config = mkdocs_config
self.plugin_config = plugin_config
return self
def __call__(self, *args, **kwargs):
assert self.mkdocs_config is not None, "mkdocs_config is not set"
assert self.plugin_config is not None, "plugin_config is not set"
# Extract the filepath,
# which is the first positional argument
# or a named argument when there are no positional arguments
args = list(args)
if len(args) > 0:
input_file_name = args.pop(0)
else:
input_file_name = kwargs.pop("filepath_or_buffer")
possible_file_paths = [
Path(
os.path.dirname(os.path.abspath(self.mkdocs_config["config_file_path"]))
)
/ Path(self.plugin_config.get("data_path"))
/ input_file_name,
Path(os.path.abspath(self.mkdocs_config["docs_dir"]))
/ Path(self.plugin_config.get("data_path"))
/ input_file_name,
Path(self.plugin_config._current_page).parent / input_file_name,
]
valid_file_paths = [path for path in possible_file_paths if path.exists()]
if len(valid_file_paths) == 0:
msg = f"[table-reader-plugin]: Cannot find table file '{input_file_name}'. The following directories were searched: {*possible_file_paths,}"
if self.plugin_config.get("allow_missing_files"):
logger.warning(msg)
return f"{{{{ Cannot find '{input_file_name}' }}}}"
else:
raise FileNotFoundError(msg)
return self.func(valid_file_paths[0], *args, **kwargs)
@ParseArgs
def read_csv(*args, **kwargs) -> str:
read_kwargs = kwargs_in_func(kwargs, pd.read_csv)

@@ -16,4 +72,4 @@ df = pd.read_csv(*args, **read_kwargs)

def read_table(*args, **kwargs):
@ParseArgs
def read_table(*args, **kwargs) -> str:
read_kwargs = kwargs_in_func(kwargs, pd.read_table)

@@ -26,3 +82,4 @@ df = pd.read_table(*args, **read_kwargs)

def read_fwf(*args, **kwargs):
@ParseArgs
def read_fwf(*args, **kwargs) -> str:
read_kwargs = kwargs_in_func(kwargs, pd.read_fwf)

@@ -34,3 +91,5 @@ df = pd.read_fwf(*args, **read_kwargs)

def read_json(*args, **kwargs):
@ParseArgs
def read_json(*args, **kwargs) -> str:
read_kwargs = kwargs_in_func(kwargs, pd.read_json)

@@ -43,3 +102,4 @@ df = pd.read_json(*args, **read_kwargs)

def read_excel(*args, **kwargs):
@ParseArgs
def read_excel(*args, **kwargs) -> str:
read_kwargs = kwargs_in_func(kwargs, pd.read_excel)

@@ -52,4 +112,4 @@ df = pd.read_excel(*args, **read_kwargs)

def read_yaml(*args, **kwargs):
@ParseArgs
def read_yaml(*args, **kwargs) -> str:
json_kwargs = kwargs_in_func(kwargs, pd.json_normalize)

@@ -62,3 +122,5 @@ with open(args[0], "r") as f:

def read_feather(*args, **kwargs):
@ParseArgs
def read_feather(*args, **kwargs) -> str:
read_kwargs = kwargs_in_func(kwargs, pd.read_feather)

@@ -70,3 +132,5 @@ df = pd.read_feather(*args, **read_kwargs)

def read_raw(*args, **kwargs):
@ParseArgs
def read_raw(*args, **kwargs) -> str:
"""Read a file as-is.

@@ -91,2 +155,1 @@

}

@@ -7,3 +7,3 @@ """

A downside of literal_eval() is that is cannot parse
special characters like newlines (\r\t or \n). We need those kind of characters because pandas.read_csv() accepts
special characters like newlines (\r\t or \n). We need those kind of characters because pandas.read_csv() accepts
a parameter 'sep' that could contain all sorts of regex.

@@ -40,4 +40,4 @@

special characters like newlines (\r\t or \n).
We need this because pandas.read_csv() accepts
We need this because pandas.read_csv() accepts
a parameter 'sep' that could contain all sorts of regex.

@@ -49,3 +49,3 @@

Returns:
str: The parsed literal python structure
str: The parsed literal python structure
"""

@@ -64,4 +64,4 @@ if "\n" in string or "\\" in string or "\r" in string:

Parses a string to detect both args and kwargs.
Adapted code from
Adapted code from
https://stackoverflow.com/questions/9305387/string-of-kwargs-to-kwargs

@@ -71,3 +71,3 @@

input_str (str): string with positional and keyword arguments
Returns:

@@ -78,8 +78,8 @@ args[List], kwargs[Dict]

segments = []
current_segment = ''
current_segment = ""
in_quotes = False
quote_char = ''
quote_char = ""
bracket_count = 0
tuple_count = 0
for char in input_str:

@@ -91,18 +91,18 @@ if char in "\"'" and not in_quotes:

in_quotes = False
quote_char = ''
elif char == '[':
quote_char = ""
elif char == "[":
bracket_count += 1
elif char == ']':
elif char == "]":
bracket_count -= 1
elif char == '(':
elif char == "(":
tuple_count += 1
elif char == ')':
elif char == ")":
tuple_count -= 1
elif char == ',' and not in_quotes and bracket_count == 0 and tuple_count == 0:
elif char == "," and not in_quotes and bracket_count == 0 and tuple_count == 0:
segments.append(current_segment.strip())
current_segment = ''
current_segment = ""
continue
current_segment += char
segments.append(current_segment.strip()) # Add the last segment

@@ -109,0 +109,0 @@ # end code generated by copilot, validated by unit tests

import os
from inspect import signature
from inspect import signature
def get_keywords(func):
return [p.name for p in signature(func).parameters.values() if p.kind == p.POSITIONAL_OR_KEYWORD or p.kind == p.KEYWORD_ONLY]
return [
p.name
for p in signature(func).parameters.values()
if p.kind == p.POSITIONAL_OR_KEYWORD or p.kind == p.KEYWORD_ONLY
]
def kwargs_in_func(keywordargs, func):
return {k:v for k, v in keywordargs.items() if k in get_keywords(func)}
return {k: v for k, v in keywordargs.items() if k in get_keywords(func)}
def kwargs_not_in_func(keywordargs, func):
return {k:v for k, v in keywordargs.items() if k not in get_keywords(func)}
return {k: v for k, v in keywordargs.items() if k not in get_keywords(func)}

@@ -29,2 +36,1 @@

os.chdir(self.savedPath)
Metadata-Version: 2.1
Name: mkdocs-table-reader-plugin
Version: 2.2.2
Version: 3.0.0
Summary: MkDocs plugin to directly insert tables from files into markdown.

@@ -66,5 +66,6 @@ Home-page: https://github.com/timvink/mkdocs-table-reader-plugin

Where the path is relative to the location of your project's `mkdocs.yml` file (although you can [change that](https://timvink.github.io/mkdocs-table-reader-plugin/options) to be relative to your `docs/` directory).
Where the path is relative to the location of your project's `mkdocs.yml` file, _or_ your project's `docs/` directory, _or_ the location of your markdown source file (all 3 possible locations will be searched, in that order).
- There are [readers](https://timvink.github.io/mkdocs-table-reader-plugin/readers/) for `.csv`, `.fwf`, `.json`, `.xlsx`, `.yaml` and `.tsv` files. There is also the `read_raw()` reader that will allow you to insert tables (or other content) already in markdown format.
- There are [readers](https://timvink.github.io/mkdocs-table-reader-plugin/readers/) for `.csv`, `.fwf`, `.json`, `.xls`, `.xlsx`, `.yaml`, `.feather` and `.tsv` files. There is also the `read_raw()` reader that will allow you to insert tables (or other content) already in markdown format.
- `table-reader` is compatible with [`mkdocs-macros-plugin`](https://mkdocs-macros-plugin.readthedocs.io/en/latest/), which means you can [dynamically insert tables using jinja2 syntax](https://timvink.github.io/mkdocs-table-reader-plugin/howto/use_jinja2/).

@@ -71,0 +72,0 @@ ## Documentation and how-to guides

@@ -41,5 +41,6 @@ [![Actions Status](https://github.com/timvink/mkdocs-table-reader-plugin/workflows/pytest/badge.svg)](https://github.com/timvink/mkdocs-table-reader-plugin/actions)

Where the path is relative to the location of your project's `mkdocs.yml` file (although you can [change that](https://timvink.github.io/mkdocs-table-reader-plugin/options) to be relative to your `docs/` directory).
Where the path is relative to the location of your project's `mkdocs.yml` file, _or_ your project's `docs/` directory, _or_ the location of your markdown source file (all 3 possible locations will be searched, in that order).
- There are [readers](https://timvink.github.io/mkdocs-table-reader-plugin/readers/) for `.csv`, `.fwf`, `.json`, `.xlsx`, `.yaml` and `.tsv` files. There is also the `read_raw()` reader that will allow you to insert tables (or other content) already in markdown format.
- There are [readers](https://timvink.github.io/mkdocs-table-reader-plugin/readers/) for `.csv`, `.fwf`, `.json`, `.xls`, `.xlsx`, `.yaml`, `.feather` and `.tsv` files. There is also the `read_raw()` reader that will allow you to insert tables (or other content) already in markdown format.
- `table-reader` is compatible with [`mkdocs-macros-plugin`](https://mkdocs-macros-plugin.readthedocs.io/en/latest/), which means you can [dynamically insert tables using jinja2 syntax](https://timvink.github.io/mkdocs-table-reader-plugin/howto/use_jinja2/).

@@ -46,0 +47,0 @@ ## Documentation and how-to guides

@@ -8,3 +8,3 @@ from setuptools import setup, find_packages

name="mkdocs-table-reader-plugin",
version="2.2.2",
version="3.0.0",
description="MkDocs plugin to directly insert tables from files into markdown.",

@@ -11,0 +11,0 @@ long_description=long_description,

@@ -377,1 +377,14 @@ """

assert re.search(r"4242", contents)
def test_macros_jinja2_syntax(tmp_path):
tmp_proj = setup_clean_mkdocs_folder(
"tests/fixtures/jinja/mkdocs.yml", tmp_path
)
result = build_docs_setup(tmp_proj)
assert result.exit_code == 0, "'mkdocs build' command failed"
# Make sure the file.csv is inserted
page_with_tag = tmp_proj / "site/index.html"
contents = page_with_tag.read_text()
assert re.search(r"531456", contents)