Skip to content

Commit 80c5c10

Browse files
authored
v4.3.0 (#131)
1 parent c0aa9f0 commit 80c5c10

File tree

16 files changed

+77
-69
lines changed

16 files changed

+77
-69
lines changed

‎.github/workflows/lint-and-test.yml‎

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,19 +12,23 @@ on:
1212
jobs:
1313
build:
1414

15-
runs-on: ubuntu-latest
15+
runs-on: ${{ matrix.os }}
1616
strategy:
1717
fail-fast: true
1818
matrix:
19-
python-version: ["3.6", "3.7", "3.8", "3.9", "3.10"]
19+
os: [ubuntu-latest]
20+
python-version: ["3.7", "3.8", "3.9", "3.10", "3.11"]
21+
include:
22+
- os: ubuntu-20.04
23+
python-version: "3.6"
2024

2125
steps:
22-
- uses: actions/checkout@v2
26+
- uses: actions/checkout@v3
2327
- name: Set up Python ${{ matrix.python-version }}
24-
uses: actions/setup-python@v2
28+
uses: actions/setup-python@v4
2529
with:
2630
python-version: ${{ matrix.python-version }}
27-
- uses: actions/cache@v2
31+
- uses: actions/cache@v3
2832
with:
2933
path: ~/.cache/pip
3034
key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }}

‎Makefile‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ reqs: ## output requirements.txt
9898
poetry export -f requirements.txt -o requirements.txt --without-hashes
9999

100100
release: dist ## package and upload a release
101-
twine upload
101+
twine upload dist/*
102102

103103
dist: clean ## builds source and wheel package
104104
poetry build

‎docs/04-about/release-notes.md‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,12 @@
11
Release Notes
22
=============
33

4+
4.3.0 (2023-05-29)
5+
------------------
6+
7+
- Compatibility
8+
- Python 3.11 support added
9+
410
4.2.0 (2022-11-10)
511
------------------
612

‎esparto/__init__.py‎

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -9,30 +9,30 @@
99
1010
"""
1111

12+
import dataclasses as _dc
1213
from importlib.util import find_spec as _find_spec
1314
from pathlib import Path as _Path
14-
from typing import Set as _Set
1515

1616
__author__ = """Dominic Thorn"""
1717
__email__ = "dominic.thorn@gmail.com"
18-
__version__ = "4.2.0"
18+
__version__ = "4.3.0"
1919

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

2222

23-
_OPTIONAL_DEPENDENCIES: _Set[str] = {
24-
"PIL", # Only used for type checking and conversion
25-
"IPython",
26-
"matplotlib",
27-
"pandas",
28-
"bokeh",
29-
"plotly",
30-
"weasyprint",
31-
}
23+
@_dc.dataclass(frozen=True)
24+
class _OptionalDependencies:
25+
PIL: bool = _find_spec("PIL") is not None
26+
IPython: bool = _find_spec("IPython") is not None
27+
matplotlib: bool = _find_spec("matplotlib") is not None
28+
pandas: bool = _find_spec("pandas") is not None
29+
bokeh: bool = _find_spec("bokeh") is not None
30+
plotly: bool = _find_spec("plotly") is not None
31+
weasyprint: bool = _find_spec("weasyprint") is not None
32+
33+
def all_extras(self) -> bool:
34+
return all(_dc.astuple(self))
3235

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

3737
from esparto._options import OutputOptions, options
3838
from esparto.design.content import (

‎esparto/_options.py‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -134,9 +134,9 @@ class OutputOptions(yaml.YAMLObject, ConfigMixin):
134134
esparto_js: str = str(_MODULE_PATH / "resources/js/esparto.js")
135135
jinja_template: str = str(_MODULE_PATH / "resources/jinja/base.html.jinja")
136136

137-
matplotlib: MatplotlibOptions = MatplotlibOptions()
138-
bokeh: BokehOptions = BokehOptions()
139-
plotly: PlotlyOptions = PlotlyOptions()
137+
matplotlib: MatplotlibOptions = field(default_factory=MatplotlibOptions)
138+
bokeh: BokehOptions = field(default_factory=BokehOptions)
139+
plotly: PlotlyOptions = field(default_factory=PlotlyOptions)
140140

141141
_pdf_temp_dir: str = TemporaryDirectory().name
142142

‎esparto/design/adaptors.py‎

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
from pathlib import Path
44
from typing import Any, Dict, Union
55

6-
from esparto import _INSTALLED_MODULES
6+
from esparto import _OptionalDependencies
77
from esparto.design.content import (
88
Content,
99
DataFramePd,
@@ -65,7 +65,7 @@ def content_adaptor_dict(content: Dict[str, Any]) -> Dict[str, Any]:
6565

6666

6767
# Function only available if Pandas is installed.
68-
if "pandas" in _INSTALLED_MODULES:
68+
if _OptionalDependencies.pandas:
6969
from pandas.core.frame import DataFrame # type: ignore
7070

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

7676

7777
# Function only available if Matplotlib is installed.
78-
if "matplotlib" in _INSTALLED_MODULES:
78+
if _OptionalDependencies.matplotlib:
7979
from matplotlib.figure import Figure # type: ignore
8080

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

8686

8787
# Function only available if Bokeh is installed.
88-
if "bokeh" in _INSTALLED_MODULES:
88+
if _OptionalDependencies.bokeh:
8989
from bokeh.layouts import LayoutDOM as BokehObject # type: ignore
9090

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

9696

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

101101
@content_adaptor.register(PlotlyFigure)

‎esparto/design/content.py‎

Lines changed: 8 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -11,26 +11,26 @@
1111

1212
import markdown as md
1313

14-
from esparto import _INSTALLED_MODULES
14+
from esparto import _OptionalDependencies
1515
from esparto._options import options
1616
from esparto.design.base import AbstractContent, AbstractLayout, Child
1717
from esparto.design.layout import Row
1818
from esparto.publish.output import nb_display
1919

20-
if "PIL" in _INSTALLED_MODULES:
20+
if _OptionalDependencies.PIL:
2121
from PIL.Image import Image as PILImage # type: ignore
2222

23-
if "pandas" in _INSTALLED_MODULES:
23+
if _OptionalDependencies.pandas:
2424
from pandas import DataFrame # type: ignore
2525

26-
if "matplotlib" in _INSTALLED_MODULES:
26+
if _OptionalDependencies.matplotlib:
2727
from matplotlib.figure import Figure as MplFigure # type: ignore
2828

29-
if "bokeh" in _INSTALLED_MODULES:
29+
if _OptionalDependencies.bokeh:
3030
from bokeh.embed import components # type: ignore
3131
from bokeh.models.layouts import LayoutDOM as BokehObject # type: ignore
3232

33-
if "plotly" in _INSTALLED_MODULES:
33+
if _OptionalDependencies.plotly:
3434
from plotly.graph_objs._figure import Figure as PlotlyFigure # type: ignore
3535
from plotly.io import to_html as plotly_to_html # type: ignore
3636

@@ -103,7 +103,6 @@ class RawHTML(Content):
103103
content: str
104104

105105
def __init__(self, html: str) -> None:
106-
107106
if not isinstance(html, str):
108107
raise TypeError(r"HTML must be str")
109108

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

126125
def __init__(self, text: str) -> None:
127-
128126
if not isinstance(text, str):
129127
raise TypeError(r"text must be str")
130128

@@ -163,10 +161,9 @@ def __init__(
163161
set_width: Optional[int] = None,
164162
set_height: Optional[int] = None,
165163
):
166-
167164
valid_types: Tuple[Any, ...]
168165

169-
if "PIL" in _INSTALLED_MODULES:
166+
if _OptionalDependencies.PIL:
170167
valid_types = (str, Path, PILImage, BytesIO)
171168
else:
172169
valid_types = (str, Path, BytesIO)
@@ -250,7 +247,6 @@ class DataFramePd(Content):
250247
def __init__(
251248
self, df: "DataFrame", index: bool = True, col_space: Union[int, str] = 0
252249
):
253-
254250
if not isinstance(df, DataFrame):
255251
raise TypeError(r"df must be Pandas DataFrame")
256252

@@ -292,7 +288,6 @@ def __init__(
292288
output_format: Optional[str] = None,
293289
pdf_figsize: Optional[Union[Tuple[int, int], float]] = None,
294290
) -> None:
295-
296291
if not isinstance(figure, MplFigure):
297292
raise TypeError(r"figure must be a Matplotlib Figure")
298293

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

305300
def to_html(self, **kwargs: bool) -> str:
306-
307301
if kwargs.get("notebook_mode"):
308302
output_format = options.matplotlib.notebook_format
309303
else:
@@ -317,7 +311,6 @@ def to_html(self, **kwargs: bool) -> str:
317311
self.content.set_size_inches(*figsize)
318312

319313
if output_format == "svg":
320-
321314
string_buffer = StringIO()
322315
self.content.savefig(string_buffer, format="svg")
323316
string_buffer.seek(0)
@@ -382,7 +375,6 @@ def __init__(
382375
self.layout_attributes = layout_attributes or options.bokeh.layout_attributes
383376

384377
def to_html(self, **kwargs: bool) -> str:
385-
386378
if self.layout_attributes:
387379
for key, value in self.layout_attributes.items():
388380
setattr(self.content, key, value)
@@ -426,7 +418,6 @@ def __init__(
426418
figure: "PlotlyFigure",
427419
layout_args: Optional[Dict[Any, Any]] = None,
428420
):
429-
430421
if not isinstance(figure, PlotlyFigure):
431422
raise TypeError(r"figure must be a Plotly Figure")
432423

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

438429
def to_html(self, **kwargs: bool) -> str:
439-
440430
if self.layout_args:
441431
self.content.update_layout(**self.layout_args)
442432

@@ -485,7 +475,7 @@ def image_to_bytes(image: Union[str, Path, BytesIO, "PILImage"]) -> BytesIO:
485475
"""
486476
if isinstance(image, BytesIO):
487477
return image
488-
elif "PIL" in _INSTALLED_MODULES and isinstance(image, PILImage):
478+
elif _OptionalDependencies.PIL and isinstance(image, PILImage):
489479
return BytesIO(image.tobytes())
490480
elif isinstance(image, (str, Path)):
491481
return BytesIO(Path(image).read_bytes())

‎esparto/publish/contentdeps.py‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
from pathlib import Path
55
from typing import List, Optional, Set
66

7-
from esparto import _INSTALLED_MODULES
7+
from esparto import _OptionalDependencies
88
from esparto._options import options
99

1010

@@ -40,7 +40,7 @@ def lazy_content_dependency_dict() -> ContentDependencyDict:
4040
"bootstrap", options.bootstrap_cdn, bootstrap_inline, "head"
4141
)
4242

43-
if "bokeh" in _INSTALLED_MODULES:
43+
if _OptionalDependencies.bokeh:
4444
import bokeh.resources as bk_resources # type: ignore
4545

4646
bokeh_cdn = bk_resources.CDN.render_js()
@@ -50,7 +50,7 @@ def lazy_content_dependency_dict() -> ContentDependencyDict:
5050
"bokeh", bokeh_cdn, bokeh_inline, "tail"
5151
)
5252

53-
if "plotly" in _INSTALLED_MODULES:
53+
if _OptionalDependencies.plotly:
5454
from plotly import offline as plotly_offline # type: ignore
5555

5656
plotly_version = "latest"

‎esparto/publish/output.py‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
from bs4 import BeautifulSoup, Tag # type: ignore
88
from jinja2 import Template
99

10-
from esparto import _INSTALLED_MODULES
10+
from esparto import _OptionalDependencies
1111
from esparto._options import options, resolve_config_option
1212
from esparto.design.base import AbstractContent, AbstractLayout
1313
from esparto.publish.contentdeps import resolve_deps
@@ -88,7 +88,7 @@ def publish_pdf(
8888
str: HTML string if return_html is True.
8989
9090
"""
91-
if "weasyprint" not in _INSTALLED_MODULES:
91+
if not _OptionalDependencies.weasyprint:
9292
raise ModuleNotFoundError("Install weasyprint for PDF support")
9393
import weasyprint as wp # type: ignore
9494

‎pyproject.toml‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[tool.poetry]
22
name = "esparto"
3-
version = "4.2.0"
3+
version = "4.3.0"
44
description = "Data driven report builder for the PyData ecosystem."
55
authors = ["Dominic Thorn <dominic.thorn@gmail.com>"]
66
license = "MIT"
@@ -14,6 +14,7 @@ classifiers = [
1414
"Programming Language :: Python :: 3.8",
1515
"Programming Language :: Python :: 3.9",
1616
"Programming Language :: Python :: 3.10",
17+
"Programming Language :: Python :: 3.11",
1718
"Intended Audience :: Developers",
1819
]
1920

0 commit comments

Comments
 (0)