Skip to content

Commit

Permalink
v4.3.0 (#131)
Browse files Browse the repository at this point in the history
  • Loading branch information
domvwt authored May 29, 2023
1 parent c0aa9f0 commit 80c5c10
Show file tree
Hide file tree
Showing 16 changed files with 77 additions and 69 deletions.
14 changes: 9 additions & 5 deletions .github/workflows/lint-and-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,19 +12,23 @@ on:
jobs:
build:

runs-on: ubuntu-latest
runs-on: ${{ matrix.os }}
strategy:
fail-fast: true
matrix:
python-version: ["3.6", "3.7", "3.8", "3.9", "3.10"]
os: [ubuntu-latest]
python-version: ["3.7", "3.8", "3.9", "3.10", "3.11"]
include:
- os: ubuntu-20.04
python-version: "3.6"

steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v2
uses: actions/setup-python@v4
with:
python-version: ${{ matrix.python-version }}
- uses: actions/cache@v2
- uses: actions/cache@v3
with:
path: ~/.cache/pip
key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }}
Expand Down
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ reqs: ## output requirements.txt
poetry export -f requirements.txt -o requirements.txt --without-hashes

release: dist ## package and upload a release
twine upload
twine upload dist/*

dist: clean ## builds source and wheel package
poetry build
Expand Down
6 changes: 6 additions & 0 deletions docs/04-about/release-notes.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
Release Notes
=============

4.3.0 (2023-05-29)
------------------

- Compatibility
- Python 3.11 support added

4.2.0 (2022-11-10)
------------------

Expand Down
28 changes: 14 additions & 14 deletions esparto/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,30 +9,30 @@
"""

import dataclasses as _dc
from importlib.util import find_spec as _find_spec
from pathlib import Path as _Path
from typing import Set as _Set

__author__ = """Dominic Thorn"""
__email__ = "[email protected]"
__version__ = "4.2.0"
__version__ = "4.3.0"

_MODULE_PATH: _Path = _Path(__file__).parent.absolute()


_OPTIONAL_DEPENDENCIES: _Set[str] = {
"PIL", # Only used for type checking and conversion
"IPython",
"matplotlib",
"pandas",
"bokeh",
"plotly",
"weasyprint",
}
@_dc.dataclass(frozen=True)
class _OptionalDependencies:
PIL: bool = _find_spec("PIL") is not None
IPython: bool = _find_spec("IPython") is not None
matplotlib: bool = _find_spec("matplotlib") is not None
pandas: bool = _find_spec("pandas") is not None
bokeh: bool = _find_spec("bokeh") is not None
plotly: bool = _find_spec("plotly") is not None
weasyprint: bool = _find_spec("weasyprint") is not None

def all_extras(self) -> bool:
return all(_dc.astuple(self))

_INSTALLED_MODULES: _Set[str] = {
x.name for x in [_find_spec(dep) for dep in _OPTIONAL_DEPENDENCIES] if x
}

from esparto._options import OutputOptions, options
from esparto.design.content import (
Expand Down
6 changes: 3 additions & 3 deletions esparto/_options.py
Original file line number Diff line number Diff line change
Expand Up @@ -134,9 +134,9 @@ class OutputOptions(yaml.YAMLObject, ConfigMixin):
esparto_js: str = str(_MODULE_PATH / "resources/js/esparto.js")
jinja_template: str = str(_MODULE_PATH / "resources/jinja/base.html.jinja")

matplotlib: MatplotlibOptions = MatplotlibOptions()
bokeh: BokehOptions = BokehOptions()
plotly: PlotlyOptions = PlotlyOptions()
matplotlib: MatplotlibOptions = field(default_factory=MatplotlibOptions)
bokeh: BokehOptions = field(default_factory=BokehOptions)
plotly: PlotlyOptions = field(default_factory=PlotlyOptions)

_pdf_temp_dir: str = TemporaryDirectory().name

Expand Down
10 changes: 5 additions & 5 deletions esparto/design/adaptors.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
from pathlib import Path
from typing import Any, Dict, Union

from esparto import _INSTALLED_MODULES
from esparto import _OptionalDependencies
from esparto.design.content import (
Content,
DataFramePd,
Expand Down Expand Up @@ -65,7 +65,7 @@ def content_adaptor_dict(content: Dict[str, Any]) -> Dict[str, Any]:


# Function only available if Pandas is installed.
if "pandas" in _INSTALLED_MODULES:
if _OptionalDependencies.pandas:
from pandas.core.frame import DataFrame # type: ignore

@content_adaptor.register(DataFrame)
Expand All @@ -75,7 +75,7 @@ def content_adaptor_df(content: DataFrame) -> DataFramePd:


# Function only available if Matplotlib is installed.
if "matplotlib" in _INSTALLED_MODULES:
if _OptionalDependencies.matplotlib:
from matplotlib.figure import Figure # type: ignore

@content_adaptor.register(Figure)
Expand All @@ -85,7 +85,7 @@ def content_adaptor_mpl(content: Figure) -> FigureMpl:


# Function only available if Bokeh is installed.
if "bokeh" in _INSTALLED_MODULES:
if _OptionalDependencies.bokeh:
from bokeh.layouts import LayoutDOM as BokehObject # type: ignore

@content_adaptor.register(BokehObject)
Expand All @@ -95,7 +95,7 @@ def content_adaptor_bokeh(content: BokehObject) -> FigureBokeh:


# Function only available if Plotly is installed.
if "plotly" in _INSTALLED_MODULES:
if _OptionalDependencies.plotly:
from plotly.graph_objs._figure import Figure as PlotlyFigure # type: ignore

@content_adaptor.register(PlotlyFigure)
Expand Down
26 changes: 8 additions & 18 deletions esparto/design/content.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,26 +11,26 @@

import markdown as md

from esparto import _INSTALLED_MODULES
from esparto import _OptionalDependencies
from esparto._options import options
from esparto.design.base import AbstractContent, AbstractLayout, Child
from esparto.design.layout import Row
from esparto.publish.output import nb_display

if "PIL" in _INSTALLED_MODULES:
if _OptionalDependencies.PIL:
from PIL.Image import Image as PILImage # type: ignore

if "pandas" in _INSTALLED_MODULES:
if _OptionalDependencies.pandas:
from pandas import DataFrame # type: ignore

if "matplotlib" in _INSTALLED_MODULES:
if _OptionalDependencies.matplotlib:
from matplotlib.figure import Figure as MplFigure # type: ignore

if "bokeh" in _INSTALLED_MODULES:
if _OptionalDependencies.bokeh:
from bokeh.embed import components # type: ignore
from bokeh.models.layouts import LayoutDOM as BokehObject # type: ignore

if "plotly" in _INSTALLED_MODULES:
if _OptionalDependencies.plotly:
from plotly.graph_objs._figure import Figure as PlotlyFigure # type: ignore
from plotly.io import to_html as plotly_to_html # type: ignore

Expand Down Expand Up @@ -103,7 +103,6 @@ class RawHTML(Content):
content: str

def __init__(self, html: str) -> None:

if not isinstance(html, str):
raise TypeError(r"HTML must be str")

Expand All @@ -124,7 +123,6 @@ class Markdown(Content):
_dependencies = {"bootstrap"}

def __init__(self, text: str) -> None:

if not isinstance(text, str):
raise TypeError(r"text must be str")

Expand Down Expand Up @@ -163,10 +161,9 @@ def __init__(
set_width: Optional[int] = None,
set_height: Optional[int] = None,
):

valid_types: Tuple[Any, ...]

if "PIL" in _INSTALLED_MODULES:
if _OptionalDependencies.PIL:
valid_types = (str, Path, PILImage, BytesIO)
else:
valid_types = (str, Path, BytesIO)
Expand Down Expand Up @@ -250,7 +247,6 @@ class DataFramePd(Content):
def __init__(
self, df: "DataFrame", index: bool = True, col_space: Union[int, str] = 0
):

if not isinstance(df, DataFrame):
raise TypeError(r"df must be Pandas DataFrame")

Expand Down Expand Up @@ -292,7 +288,6 @@ def __init__(
output_format: Optional[str] = None,
pdf_figsize: Optional[Union[Tuple[int, int], float]] = None,
) -> None:

if not isinstance(figure, MplFigure):
raise TypeError(r"figure must be a Matplotlib Figure")

Expand All @@ -303,7 +298,6 @@ def __init__(
self._original_figsize = figure.get_size_inches()

def to_html(self, **kwargs: bool) -> str:

if kwargs.get("notebook_mode"):
output_format = options.matplotlib.notebook_format
else:
Expand All @@ -317,7 +311,6 @@ def to_html(self, **kwargs: bool) -> str:
self.content.set_size_inches(*figsize)

if output_format == "svg":

string_buffer = StringIO()
self.content.savefig(string_buffer, format="svg")
string_buffer.seek(0)
Expand Down Expand Up @@ -382,7 +375,6 @@ def __init__(
self.layout_attributes = layout_attributes or options.bokeh.layout_attributes

def to_html(self, **kwargs: bool) -> str:

if self.layout_attributes:
for key, value in self.layout_attributes.items():
setattr(self.content, key, value)
Expand Down Expand Up @@ -426,7 +418,6 @@ def __init__(
figure: "PlotlyFigure",
layout_args: Optional[Dict[Any, Any]] = None,
):

if not isinstance(figure, PlotlyFigure):
raise TypeError(r"figure must be a Plotly Figure")

Expand All @@ -436,7 +427,6 @@ def __init__(
self._original_layout = figure.layout

def to_html(self, **kwargs: bool) -> str:

if self.layout_args:
self.content.update_layout(**self.layout_args)

Expand Down Expand Up @@ -485,7 +475,7 @@ def image_to_bytes(image: Union[str, Path, BytesIO, "PILImage"]) -> BytesIO:
"""
if isinstance(image, BytesIO):
return image
elif "PIL" in _INSTALLED_MODULES and isinstance(image, PILImage):
elif _OptionalDependencies.PIL and isinstance(image, PILImage):
return BytesIO(image.tobytes())
elif isinstance(image, (str, Path)):
return BytesIO(Path(image).read_bytes())
Expand Down
6 changes: 3 additions & 3 deletions esparto/publish/contentdeps.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
from pathlib import Path
from typing import List, Optional, Set

from esparto import _INSTALLED_MODULES
from esparto import _OptionalDependencies
from esparto._options import options


Expand Down Expand Up @@ -40,7 +40,7 @@ def lazy_content_dependency_dict() -> ContentDependencyDict:
"bootstrap", options.bootstrap_cdn, bootstrap_inline, "head"
)

if "bokeh" in _INSTALLED_MODULES:
if _OptionalDependencies.bokeh:
import bokeh.resources as bk_resources # type: ignore

bokeh_cdn = bk_resources.CDN.render_js()
Expand All @@ -50,7 +50,7 @@ def lazy_content_dependency_dict() -> ContentDependencyDict:
"bokeh", bokeh_cdn, bokeh_inline, "tail"
)

if "plotly" in _INSTALLED_MODULES:
if _OptionalDependencies.plotly:
from plotly import offline as plotly_offline # type: ignore

plotly_version = "latest"
Expand Down
4 changes: 2 additions & 2 deletions esparto/publish/output.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
from bs4 import BeautifulSoup, Tag # type: ignore
from jinja2 import Template

from esparto import _INSTALLED_MODULES
from esparto import _OptionalDependencies
from esparto._options import options, resolve_config_option
from esparto.design.base import AbstractContent, AbstractLayout
from esparto.publish.contentdeps import resolve_deps
Expand Down Expand Up @@ -88,7 +88,7 @@ def publish_pdf(
str: HTML string if return_html is True.
"""
if "weasyprint" not in _INSTALLED_MODULES:
if not _OptionalDependencies.weasyprint:
raise ModuleNotFoundError("Install weasyprint for PDF support")
import weasyprint as wp # type: ignore

Expand Down
3 changes: 2 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[tool.poetry]
name = "esparto"
version = "4.2.0"
version = "4.3.0"
description = "Data driven report builder for the PyData ecosystem."
authors = ["Dominic Thorn <[email protected]>"]
license = "MIT"
Expand All @@ -14,6 +14,7 @@ classifiers = [
"Programming Language :: Python :: 3.8",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Intended Audience :: Developers",
]

Expand Down
6 changes: 4 additions & 2 deletions setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,10 @@ multi_line_output = 3
max-line-length = 120
exclude = scratch.py, docs/
ignore =
W503, # line break before binary operator
E203, # whitespace before ':'
# line break before binary operator
W503,
# whitespace before ':'
E203,
per-file-ignores =
__init__.py:E402, F401
cdnlinks.py:E501
6 changes: 2 additions & 4 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,7 @@

import esparto.design.content as co
import esparto.design.layout as la
from esparto import _INSTALLED_MODULES, _OPTIONAL_DEPENDENCIES

_EXTRAS = _OPTIONAL_DEPENDENCIES <= _INSTALLED_MODULES
from esparto import _OptionalDependencies

_irises_path = str(Path("tests/resources/irises.jpg").absolute())
_markdown_path = str(Path("tests/resources/markdown.md").absolute())
Expand Down Expand Up @@ -43,7 +41,7 @@
(Path(_markdown_path), co.Markdown),
]

if _EXTRAS:
if _OptionalDependencies().all_extras():
import bokeh.layouts as bkl # type: ignore
import bokeh.plotting as bkp # type: ignore
import matplotlib.pyplot as plt # type: ignore
Expand Down
5 changes: 3 additions & 2 deletions tests/design/test_adaptors.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,10 @@
import pytest

import esparto.design.adaptors as ad
from esparto import _OptionalDependencies
from esparto.design.content import Content, Markdown
from esparto.design.layout import Column
from tests.conftest import _EXTRAS, adaptor_list
from tests.conftest import adaptor_list


def get_dispatch_type(fn):
Expand All @@ -20,7 +21,7 @@ def test_all_adaptors_covered(adaptor_list_fn):
module_functions = [x[1] for x in getmembers(ad, isfunction)]
adaptor_types = {get_dispatch_type(fn) for fn in module_functions}
adaptor_types.remove(Content) # Can't use abstract base class in a test
if _EXTRAS:
if _OptionalDependencies.bokeh:
adaptor_types.remove(ad.BokehObject) # Can't use abstract base class in a test
if PosixPath in test_classes:
test_classes.remove(PosixPath)
Expand Down
Loading

0 comments on commit 80c5c10

Please sign in to comment.