Skip to content

Commit 7874992

Browse files
committed
🚧 use quarto native functionality
- require users to have a Python base installation with jupyter installed - pip install jupyter Then quarto manages to pick up local dependencies and run the notebook (to test)
1 parent 03af479 commit 7874992

File tree

2 files changed

+75
-78
lines changed

2 files changed

+75
-78
lines changed

.github/workflows/cdci.yml

Lines changed: 2 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -126,9 +126,6 @@ jobs:
126126
build-executable:
127127
name: Build-exe-${{ matrix.os.label }}
128128
runs-on: ${{ matrix.os.runner }}
129-
defaults:
130-
run:
131-
shell: bash -el {0}
132129
# needs:
133130
# - test
134131
# - other-reports
@@ -147,29 +144,16 @@ jobs:
147144
# label: "windows-x64"
148145
steps:
149146
- uses: actions/checkout@v4
150-
# - uses: actions/setup-python@v5
151-
# with:
152-
# python-version: ${{ matrix.python-version }}
153-
- uses: conda-incubator/setup-miniconda@v3
147+
- uses: actions/setup-python@v5
154148
with:
155149
python-version: ${{ matrix.python-version }}
156-
activate-environment: "test"
157-
auto-activate-base: true
158-
auto-update-conda: true
159150
- name: Install VueGen GUI and pyinstaller
160151
run: |
161-
conda info
162-
conda info -e
163-
conda list
164152
python -m pip install ".[gui]" pyinstaller
165-
conda list
166153
- name: Build executable
167154
run: |
168-
conda activate test
169155
cd gui
170-
pyinstaller -n vuegen_gui -D --collect-all pyvis --collect-all streamlit --collect-all st_aggrid --collect-all customtkinter --collect-all quarto_cli --collect-all jupyter_core --collect-all yaml --collect-all ipykernel --collect-all nbconvert --collect-all notebook --collect-all ipywidgets --collect-all jupyter_console --collect-all jupyter_client --add-data ../docs/example_data/Basic_example_vuegen_demo_notebook:example_data/Basic_example_vuegen_demo_notebook app.py
171-
conda info
172-
python copy_python_executable.py
156+
pyinstaller -n vuegen_gui -D --collect-all pyvis --collect-all streamlit --collect-all st_aggrid --collect-all customtkinter --collect-all quarto_cli --add-data ../docs/example_data/Basic_example_vuegen_demo_notebook:example_data/Basic_example_vuegen_demo_notebook app.py
173157
- name: Upload executable
174158
uses: actions/upload-artifact@v4
175159
with:

src/vuegen/quarto_reportview.py

Lines changed: 73 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,12 @@ class QuartoReportView(r.ReportView):
2323
def __init__(self, report: r.Report, report_type: r.ReportType):
2424
super().__init__(report=report, report_type=report_type)
2525
self.BUNDLED_EXECUTION = False
26+
self.quarto_path = "quarto"
2627
if getattr(sys, "frozen", False) and hasattr(sys, "_MEIPASS"):
2728
self.report.logger.info("running in a PyInstaller bundle")
2829
self.BUNDLED_EXECUTION = True
2930
self.report.logger.debug(f"sys._MEIPASS: {sys._MEIPASS}")
31+
self.quarto_path = Path(sys._MEIPASS) / "quarto_cli" / "bin" / "quarto"
3032
else:
3133
self.report.logger.info("running in a normal Python process")
3234

@@ -164,74 +166,85 @@ def run_report(self, output_dir: str = BASE_DIR) -> None:
164166
# from quarto_cli import run_quarto # entrypoint of quarto-cli not in module?
165167

166168
file_path_to_qmd = os.path.join(output_dir, f"{self.BASE_DIR}.qmd")
167-
args = ["quarto", "render", file_path_to_qmd]
169+
args = [self.quarto_path, "render", file_path_to_qmd]
168170
self.report.logger.info(
169171
f"Running '{self.report.title}' '{self.report_type}' report with {args!r}"
170172
)
171-
if not self.BUNDLED_EXECUTION:
172-
subprocess.run(
173-
["quarto", "render", os.path.join(output_dir, f"{self.BASE_DIR}.qmd")],
174-
check=True,
175-
)
176-
try:
177-
if self.report_type == r.ReportType.JUPYTER:
178-
args = ["quarto", "convert", file_path_to_qmd]
179-
subprocess.run(
180-
args,
181-
check=True,
182-
)
183-
self.report.logger.info(
184-
f"Converted '{self.report.title}' '{self.report_type}' report to Jupyter Notebook after execution"
185-
)
186-
self.report.logger.info(
187-
f"'{self.report.title}' '{self.report_type}' report rendered"
188-
)
189-
except subprocess.CalledProcessError as e:
190-
self.report.logger.error(
191-
f"Error running '{self.report.title}' {self.report_type} report: {str(e)}"
173+
subprocess.run(
174+
[
175+
self.quarto_path,
176+
"render",
177+
os.path.join(output_dir, f"{self.BASE_DIR}.qmd"),
178+
],
179+
check=True,
180+
)
181+
try:
182+
if self.report_type == r.ReportType.JUPYTER:
183+
args = [self.quarto_path, "convert", file_path_to_qmd]
184+
subprocess.run(
185+
args,
186+
check=True,
192187
)
193-
raise
194-
except FileNotFoundError as e:
195-
self.report.logger.error(
196-
f"Quarto is not installed. Please install Quarto to run the report: {str(e)}"
188+
self.report.logger.info(
189+
f"Converted '{self.report.title}' '{self.report_type}' report to Jupyter Notebook after execution"
197190
)
198-
raise
199-
else:
200-
quarto_path = Path(sys._MEIPASS) / "quarto_cli" / "bin" / "quarto"
201-
_sys_exe = sys.executable
202-
# set executable to the bundled python (manually added to bundle)
203-
sys.executable = str(Path(sys._MEIPASS).parent / "python")
204-
self.report.logger.info(f"quarto_path: {quarto_path}")
205-
206-
args = [f"{quarto_path}", "convert", file_path_to_qmd]
207-
subprocess.run(
208-
args,
209-
check=True,
210-
)
211191
self.report.logger.info(
212-
f"Converted '{self.report.title}' '{self.report_type}' report to Jupyter Notebook after execution"
192+
f"'{self.report.title}' '{self.report_type}' report rendered"
213193
)
214-
notebook_filename = Path(file_path_to_qmd).with_suffix(".ipynb")
215-
# quarto does not try to execute ipynb files, just render them
216-
# execute manually using bundled python binary
217-
# https://nbconvert.readthedocs.io/en/latest/execute_api.html
218-
import nbformat
219-
from nbconvert.preprocessors import ExecutePreprocessor
220-
221-
with open(notebook_filename, encoding="utf-8") as f:
222-
nb = nbformat.read(f, as_version=4)
223-
logging.getLogger("traitlets").setLevel(logging.INFO)
224-
ep = ExecutePreprocessor(timeout=600, kernel_name="python3")
225-
nb, _ = ep.preprocess(nb, {"metadata": {"path": "./"}})
226-
with open(notebook_filename, "w", encoding="utf-8") as f:
227-
nbformat.write(nb, f)
228-
# quarto does not try execute ipynb files per default, just render these
229-
args = [f"{quarto_path}", "render", notebook_filename]
230-
subprocess.run(
231-
args,
232-
check=True,
194+
except subprocess.CalledProcessError as e:
195+
self.report.logger.error(
196+
f"Error running '{self.report.title}' {self.report_type} report: {str(e)}"
233197
)
234-
sys.executable = _sys_exe
198+
raise
199+
except FileNotFoundError as e:
200+
self.report.logger.error(
201+
f"Quarto is not installed. Please install Quarto to run the report: {str(e)}"
202+
)
203+
raise
204+
# else:
205+
# quarto_path = Path(sys._MEIPASS) / "quarto_cli" / "bin" / "quarto"
206+
# _sys_exe = sys.executable
207+
# set executable to the bundled python (manually added to bundle)
208+
# sys.executable = str(Path(sys._MEIPASS).parent / "python")
209+
# self.report.logger.info(f"quarto_path: {self.quarto_path}")
210+
211+
# args = [f"{quarto_path}", "render", file_path_to_qmd]
212+
# subprocess.run(
213+
# args,
214+
# check=True,
215+
# )
216+
# self.report.logger.info(
217+
# f"Converted '{self.report.title}' '{self.report_type}' report to Jupyter Notebook after execution"
218+
# )
219+
# notebook_filename = Path(file_path_to_qmd).with_suffix(".ipynb")
220+
# try papermill
221+
# import papermill as pm
222+
223+
# pm.execute_notebook(
224+
# "path/to/input.ipynb",
225+
# "path/to/output.ipynb",
226+
# parameters=dict(alpha=0.6, ratio=0.1),
227+
# )
228+
# quarto does not try to execute ipynb files, just render them
229+
# execute manually using bundled python binary
230+
# https://nbconvert.readthedocs.io/en/latest/execute_api.html
231+
# import nbformat
232+
# from nbconvert.preprocessors import ExecutePreprocessor
233+
234+
# with open(notebook_filename, encoding="utf-8") as f:
235+
# nb = nbformat.read(f, as_version=4)
236+
# logging.getLogger("traitlets").setLevel(logging.INFO)
237+
# ep = ExecutePreprocessor(timeout=600, kernel_name="python3")
238+
# nb, _ = ep.preprocess(nb, {"metadata": {"path": "./"}})
239+
# with open(notebook_filename, "w", encoding="utf-8") as f:
240+
# nbformat.write(nb, f)
241+
# quarto does not try execute ipynb files per default, just render these
242+
# args = [f"{quarto_path}", "render", notebook_filename]
243+
# subprocess.run(
244+
# args,
245+
# check=True,
246+
# )
247+
# sys.executable = _sys_exe
235248

236249
def _create_yaml_header(self) -> str:
237250
"""

0 commit comments

Comments
 (0)