Skip to content

Commit dbd0458

Browse files
authored
[Major] Add support for Python 3.12, drop support for Python 3.8 (#1544)
* update poetry dependencies to py3.9 - py3.12 * make plotly-resampler optional * fix register plotly imports * Update ci.yml * Update metrics.yml to use poetry for install
1 parent 7756a08 commit dbd0458

File tree

8 files changed

+383
-590
lines changed

8 files changed

+383
-590
lines changed

.github/workflows/ci.yml

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ jobs:
1919
strategy:
2020
matrix:
2121
os: [ubuntu-latest]
22-
python-version: ["3.8", "3.11"]
22+
python-version: ["3.9", "3.12"]
2323
env:
2424
POETRY_VIRTUALENVS_CREATE: false
2525
steps:
@@ -32,9 +32,11 @@ jobs:
3232
- name: Install Poetry
3333
uses: snok/install-poetry@v1
3434
- name: Install dependencies
35-
run: poetry install
35+
run: poetry install --no-root --no-interaction --without docs
36+
- name: Install Project
37+
run: poetry install --no-interaction --without docs
3638
- name: Pytest
37-
run: poetry run pytest tests -v --cov=./ --cov-report=xml
39+
run: poetry run pytest tests -v -n auto --durations=0 --cov=./ --cov-report=xml
3840
- name: Upload coverage to codecov
3941
uses: codecov/codecov-action@v3
4042
with:
@@ -51,12 +53,12 @@ jobs:
5153
- name: Install Python
5254
uses: actions/setup-python@v4
5355
with:
54-
python-version: "3.11"
56+
python-version: "3.12"
5557
- name: Install Poetry
5658
uses: abatilo/actions-poetry@v2
5759
- name: Setup Pandoc
5860
uses: r-lib/actions/setup-pandoc@v2
5961
- name: Setup Requirements
60-
run: poetry install --with=docs
62+
run: poetry install --no-interaction --with docs
6163
- name: Build with Sphinx
6264
run: poetry run sphinx-build docs/source _site

.github/workflows/linters.yml

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,9 @@ jobs:
2020
- name: Checkout
2121
uses: actions/checkout@v3
2222
- name: Set up Python
23-
uses: actions/setup-python@v4
23+
uses: actions/setup-python@v5
2424
with:
25-
python-version: "3.10"
25+
python-version: "3.12"
2626
- run: python -m pip install flake8
2727
- name: flake8
2828
uses: liskin/gh-problem-matcher-wrap@v2
@@ -44,9 +44,9 @@ jobs:
4444
- name: Checkout
4545
uses: actions/checkout@v3
4646
- name: Set up Python
47-
uses: actions/setup-python@v4
47+
uses: actions/setup-python@v5
4848
with:
49-
python-version: "3.10"
49+
python-version: "3.12"
5050
- run: python -m pip install isort
5151
- name: isort
5252
uses: liskin/gh-problem-matcher-wrap@v2
@@ -72,9 +72,9 @@ jobs:
7272
- name: Checkout
7373
uses: actions/checkout@v3
7474
- name: Set up Python
75-
uses: actions/setup-python@v4
75+
uses: actions/setup-python@v5
7676
with:
77-
python-version: "3.10"
77+
python-version: "3.12"
7878
- name: Cache poetry
7979
id: poetry-cache
8080
uses: actions/cache@v3
@@ -85,6 +85,6 @@ jobs:
8585
if: steps.poetry-cache.outputs.cache-hit != 'true'
8686
uses: snok/install-poetry@v1
8787
- name: Install dependencies
88-
run: poetry install --with=docs,pyright
88+
run: poetry install --no-interaction --with=docs,pyright
8989
- name: pyright
9090
uses: jakebailey/pyright-action@v1

.github/workflows/metrics.yml

Lines changed: 24 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -13,24 +13,30 @@ on:
1313
workflow_dispatch:
1414
jobs:
1515
metrics:
16-
runs-on: ubuntu-latest
17-
container: docker://ghcr.io/iterative/cml:0-dvc2-base1
18-
env:
19-
POETRY_VIRTUALENVS_CREATE: false
16+
runs-on: ubuntu-latest # container: docker://ghcr.io/iterative/cml:0-dvc2-base1
2017
steps:
2118
- name: Checkout
2219
uses: actions/checkout@v3
2320
with:
2421
ref: ${{ github.event.pull_request.head.sha }}
25-
- name: Install dependencies
26-
run: |
27-
python3 -m pip install --upgrade pip
28-
pip3 install .
29-
pip3 install pytest
30-
pip3 install tabulate # required to md export
31-
pip3 install kaleido # required for plotly export
22+
- name: Install Python 3.12
23+
uses: actions/setup-python@v5
24+
with:
25+
python-version: "3.12"
26+
- name: Setup NodeJS (for CML)
27+
uses: actions/setup-node@v3 # For CML
28+
with:
29+
node-version: '16'
30+
- name: Setup CML
31+
uses: iterative/setup-cml@v1
32+
- name: Install Poetry
33+
uses: snok/install-poetry@v1
34+
- name: Install Dependencies
35+
run: poetry install --no-interaction --no-root --without docs
36+
- name: Install Project
37+
run: poetry install --no-interaction --without docs
3238
- name: Train model
33-
run: pytest tests/test_model_performance.py
39+
run: poetry run pytest tests/test_model_performance.py -n 1 --durations=0
3440
- name: Download metrics from main
3541
uses: dawidd6/action-download-artifact@v2
3642
with:
@@ -39,11 +45,11 @@ jobs:
3945
name: metrics
4046
path: tests/metrics-main/
4147
if_no_artifact_found: warn
42-
- name: Compare performance
43-
run: |
44-
echo "## Model Benchmark" >> report.md
45-
python tests/metrics/compareMetrics.py >> report.md
46-
- name: Publish report
48+
- name: Open Benchmark Report
49+
run: echo "## Model Benchmark" >> report.md
50+
- name: Write Benchmark Report
51+
run: poetry run python tests/metrics/compareMetrics.py >> report.md
52+
- name: Publish Report with CML
4753
env:
4854
REPO_TOKEN: ${{ secrets.GITHUB_TOKEN }}
4955
run: |
@@ -58,8 +64,7 @@ jobs:
5864
echo "### EnergyPriceDaily" >> report.md
5965
cml asset publish tests/metrics/EnergyPriceDaily.svg --md >> report.md
6066
echo "\n</details>" >> report.md
61-
# Post reports as comments in GitHub PRs
62-
cml comment update --target=pr report.md # post to PR
67+
cml comment update --target=pr report.md # Post reports as comments in GitHub PRs
6368
cml check create --title=ModelReport report.md # update status of check in PR
6469
- name: Upload metrics if on main
6570
uses: actions/upload-artifact@v3

neuralprophet/plot_forecast_plotly.py

Lines changed: 44 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -2,18 +2,21 @@
22

33
import numpy as np
44
import pandas as pd
5+
import plotly.express as px
6+
import plotly.graph_objs as go
57

68
from neuralprophet.plot_model_parameters_plotly import get_dynamic_axis_range
79
from neuralprophet.plot_utils import set_y_as_percent
810

911
log = logging.getLogger("NP.plotly")
1012

1113
try:
12-
import plotly.express as px
13-
import plotly.graph_objs as go
1414
from plotly.subplots import make_subplots
1515
from plotly_resampler import register_plotly_resampler, unregister_plotly_resampler
16+
17+
plotly_resampler_installed = True
1618
except ImportError:
19+
plotly_resampler_installed = False
1720
log.error("Importing plotly failed. Interactive plots will not work.")
1821

1922
# UI Configuration
@@ -81,10 +84,13 @@ def plot(
8184
-------
8285
Plotly figure
8386
"""
84-
if resampler_active:
85-
register_plotly_resampler(mode="auto")
86-
else:
87-
unregister_plotly_resampler()
87+
if plotly_resampler_installed:
88+
if resampler_active:
89+
register_plotly_resampler(mode="auto")
90+
else:
91+
unregister_plotly_resampler()
92+
if resampler_active and not plotly_resampler_installed:
93+
log.error("plotly-resampler is not installed. Please install it to use the resampler.")
8894

8995
cross_marker_color = "blue"
9096
cross_symbol = "x"
@@ -222,7 +228,8 @@ def plot(
222228
**layout_args,
223229
)
224230
fig = go.Figure(data=data, layout=layout)
225-
unregister_plotly_resampler()
231+
if plotly_resampler_installed:
232+
unregister_plotly_resampler()
226233
if plotly_static:
227234
fig = fig.show("svg")
228235
return fig
@@ -265,10 +272,14 @@ def plot_components(
265272
Plotly figure
266273
"""
267274
log.debug("Plotting forecast components")
268-
if resampler_active:
269-
register_plotly_resampler(mode="auto")
270-
else:
271-
unregister_plotly_resampler()
275+
if plotly_resampler_installed:
276+
if resampler_active:
277+
register_plotly_resampler(mode="auto")
278+
else:
279+
unregister_plotly_resampler()
280+
if resampler_active and not plotly_resampler_installed:
281+
log.error("plotly-resampler is not installed. Please install it to use the resampler.")
282+
272283
fcst = fcst.fillna(value=np.nan)
273284
components_to_plot = plot_configuration["components_list"]
274285

@@ -339,7 +350,8 @@ def plot_components(
339350
# Reset multiplicative axes labels after tight_layout adjustment
340351
for ax in multiplicative_axes:
341352
ax = set_y_as_percent(ax)
342-
unregister_plotly_resampler()
353+
if plotly_resampler_installed:
354+
unregister_plotly_resampler()
343355
if plotly_static:
344356
fig = fig.show("svg")
345357
return fig
@@ -739,10 +751,14 @@ def plot_nonconformity_scores(scores, alpha, q, method, resampler_active=False):
739751
Figure showing the nonconformity score with horizontal line for q-value based on the significance level or
740752
alpha
741753
"""
742-
if resampler_active:
743-
register_plotly_resampler(mode="auto")
744-
else:
745-
unregister_plotly_resampler()
754+
if plotly_resampler_installed:
755+
if resampler_active:
756+
register_plotly_resampler(mode="auto")
757+
else:
758+
unregister_plotly_resampler()
759+
if resampler_active and not plotly_resampler_installed:
760+
log.error("plotly-resampler is not installed. Please install it to use the resampler.")
761+
746762
if not isinstance(q, list):
747763
q_sym = q
748764
scores = scores["noncon_scores"]
@@ -820,7 +836,8 @@ def plot_nonconformity_scores(scores, alpha, q, method, resampler_active=False):
820836
line_color="red",
821837
)
822838
fig.update_layout(margin=dict(l=70, r=70, t=60, b=50))
823-
unregister_plotly_resampler()
839+
if plotly_resampler_installed:
840+
unregister_plotly_resampler()
824841
return fig
825842

826843

@@ -845,10 +862,14 @@ def plot_interval_width_per_timestep(q_hats, method, resampler_active=False):
845862
plotly.graph_objects.Figure
846863
Figure showing the q-values for each timestep
847864
"""
848-
if resampler_active:
849-
register_plotly_resampler(mode="auto")
850-
else:
851-
unregister_plotly_resampler()
865+
if plotly_resampler_installed:
866+
if resampler_active:
867+
register_plotly_resampler(mode="auto")
868+
else:
869+
unregister_plotly_resampler()
870+
if resampler_active and not plotly_resampler_installed:
871+
log.error("plotly-resampler is not installed. Please install it to use the resampler.")
872+
852873
# check if q_hats contains q_hat_sym
853874
if "q_hat_sym" in q_hats.columns:
854875
q_hats_sym = q_hats["q_hat_sym"]
@@ -880,7 +901,8 @@ def plot_interval_width_per_timestep(q_hats, method, resampler_active=False):
880901
height=400,
881902
)
882903
fig.update_layout(margin=dict(l=70, r=70, t=60, b=50))
883-
unregister_plotly_resampler()
904+
if plotly_resampler_installed:
905+
unregister_plotly_resampler()
884906
return fig
885907

886908

neuralprophet/plot_model_parameters_plotly.py

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,19 @@
33

44
import numpy as np
55
import pandas as pd
6+
import plotly.graph_objs as go
7+
from plotly.subplots import make_subplots
68

79
from neuralprophet.plot_utils import predict_one_season, predict_season_from_dates
810

911
log = logging.getLogger("NP.plotly")
1012

1113
try:
12-
import plotly.graph_objs as go
13-
from plotly.subplots import make_subplots
1414
from plotly_resampler import register_plotly_resampler, unregister_plotly_resampler
15+
16+
plotly_resampler_installed = True
1517
except ImportError:
18+
plotly_resampler_installed = False
1619
log.error("Importing plotly failed. Interactive plots will not work.")
1720

1821
# UI Configuration
@@ -35,7 +38,8 @@
3538
"title": dict(font=dict(size=12)),
3639
"hovermode": "x unified",
3740
}
38-
register_plotly_resampler(mode="auto")
41+
if plotly_resampler_installed:
42+
register_plotly_resampler(mode="auto")
3943

4044

4145
def get_dynamic_axis_range(df_range, type, pad=0.05, inverse=False):
@@ -872,10 +876,14 @@ def plot_parameters(
872876
Returns:
873877
Plotly figure
874878
"""
875-
if resampler_active:
876-
register_plotly_resampler(mode="auto")
877-
else:
878-
unregister_plotly_resampler()
879+
if plotly_resampler_installed:
880+
if resampler_active:
881+
register_plotly_resampler(mode="auto")
882+
else:
883+
unregister_plotly_resampler()
884+
if resampler_active and not plotly_resampler_installed:
885+
log.error("plotly-resampler is not installed. Please install it to use the resampler.")
886+
879887
compnents_to_plot = plot_configuration["components_list"]
880888
additive_future_regressors = plot_configuration["additive_future_regressors"]
881889
additive_events = plot_configuration["additive_events"]
@@ -963,5 +971,6 @@ def plot_parameters(
963971
yaxis.update(**yaxis_args)
964972
for trace in trace_object["traces"]:
965973
fig.add_trace(trace, row=i + 1, col=1) # adapt var name to plotly-resampler
966-
unregister_plotly_resampler()
974+
if plotly_resampler_installed:
975+
unregister_plotly_resampler()
967976
return fig

0 commit comments

Comments
 (0)