33# Depend on `FORCE` to ensure the target is always run
44FORCE :
55
6- # TODO-barret; Use `pybin/activate && COMMAND` approach, not `$(COMMAND)` approach
7-
86.DEFAULT_GOAL := help
97
108define BROWSER_PYSCRIPT
@@ -46,13 +44,8 @@ VENV = .venv
4644PYBIN = $(VENV ) /bin
4745PIP = $(PYBIN ) /pip
4846PYTHON = $(PYBIN ) /python
49- UV = $(PYBIN ) /uv
50- PYBIN_ACTIVATE = $(PYBIN ) /activate
5147SITE_PACKAGES =$(VENV ) /lib/python$(PYTHON_VERSION ) /site-packages
5248
53- # /----------------
54-
55-
5649
5750# -----------------
5851# Core virtual environment and installing
@@ -67,78 +60,61 @@ $(VENV):
6760 $(PYBIN ) /pip install --upgrade pip
6861
6962$(PYBIN ) : $(VENV )
70- $(PYBIN_ACTIVATE ) : $(PYBIN )
7163$(PIP ) : $(PYBIN )
7264
73- UV_PKG = $(SITE_PACKAGES ) /uv
74- $(UV ) : $( UV_PKG )
75- $( UV_PKG ) : $(PIP )
65+ UV = $(SITE_PACKAGES ) /uv
66+ $(UV ) :
67+ $( MAKE ) $(PYBIN )
7668 @echo " -------- Installing uv --------"
77- $(PIP ) install uv # avoid circular dependency
78-
79- # /----------------
69+ . $(PYBIN ) /activate && \
70+ pip install uv
8071
8172# -----------------
8273# Python package executables
8374# -----------------
8475# Use `FOO=$(PYBIN)/foo` to define the path to a package's executable
85- # Use `FOO_PKG=$(SITE_PACKAGES)/foo` to define the path to a package's site-packages directory
86-
87- # Depend on `$(FOO_PKG)` to ensure the package is installed,
88- # but use `$(FOO)` to actually run the package's executable
89-
90- # BLACK = $(PYTHON) -m black
91- BLACK_PKG = $(SITE_PACKAGES ) /black
92- ISORT = $(PYBIN ) /isort
93- ISORT_PKG = $(SITE_PACKAGES ) /isort
94- FLAKE8 = $(PYBIN ) /flake8
95- FLAKE8_PKG = $(SITE_PACKAGES ) /flake8
96- PYTEST = $(PYBIN ) /pytest
97- PYTEST_PKG = $(SITE_PACKAGES ) /pytest
98- COVERAGE = $(PYBIN ) /coverage
99- COVERAGE_PKG = $(SITE_PACKAGES ) /coverage
100- PYRIGHT = $(PYBIN ) /pyright
101- PYRIGHT_PKG = $(SITE_PACKAGES ) /pyright
102- PLAYWRIGHT = $(PYBIN ) /playwright
103- PLAYWRIGHT_PKG = $(SITE_PACKAGES ) /playwright
104- $(BLACK_PKG ) $(ISORT_PKG ) $(FLAKE8_PKG ) $(PYTEST_PKG ) $(COVERAGE_PKG ) $(PYRIGHT_PKG ) $(PLAYWRIGHT_PKG ) :
76+ # Depend on `$(FOO)` to ensure the package is installed,
77+ # but use `$(PYBIN)/foo` to actually run the package's executable
78+ RUFF = $(SITE_PACKAGES ) /ruff
79+ PYTEST = $(SITE_PACKAGES ) /pytest
80+ COVERAGE = $(SITE_PACKAGES ) /coverage
81+ PYRIGHT = $(SITE_PACKAGES ) /pyright
82+ PLAYWRIGHT = $(SITE_PACKAGES ) /playwright
83+ $(PYTEST ) $(COVERAGE ) $(PYRIGHT ) $(PLAYWRIGHT ) :
10584 @$(MAKE ) install-deps
106- # touch $@ # update timestamp of target file
10785
108- # /----------------
10986
11087# -----------------
11188# Helper packages not defined in `setup.cfg`
11289# -----------------
11390
114- TRCLI_PKG = $(SITE_PACKAGES ) /trcli
115- $(TRCLI_PKG ) :
116- @$(MAKE ) $(UV )
91+ TRCLI = $(SITE_PACKAGES ) /trcli
92+ $(TRCLI ) : $(UV )
11793 @echo " -------- Installing trcli --------"
118- $( UV ) pip install trcli
119- # @touch $(PYBIN)/trcli # update timestamp
94+ . $( PYBIN ) /activate && \
95+ uv pip install trcli
12096
121- TWINE_PKG = $(SITE_PACKAGES ) /twine
122- $(TWINE_PKG ) :
123- @$(MAKE ) $(UV )
97+ TWINE = $(SITE_PACKAGES ) /twine
98+ $(TWINE ) : $(UV )
12499 @echo " -------- Installing twine --------"
125- $( UV ) pip install twine
126- # @touch $(PYBIN)/twine # update timestamp
100+ . $( PYBIN ) /activate && \
101+ uv pip install twine
127102
128- RSCONNECT_PKG = $(SITE_PACKAGES ) /rsconnect
129- $(RSCONNECT_PKG ) : # # install the main version of rsconnect till pypi version supports shiny express
130- @$(MAKE ) $(UV )
131- $(UV ) pip install rsconnect @ git+https://github.com/rstudio/rsconnect-python.git
103+ RSCONNECT = $(SITE_PACKAGES ) /rsconnect
104+ $(RSCONNECT ) : $(UV ) # # install the main version of rsconnect till pypi version supports shiny express
105+ @echo " -------- Installing rsconnect --------"
106+ . $(PYBIN ) /activate && \
107+ uv pip install rsconnect @ git+https://github.com/rstudio/rsconnect-python.git
132108
133- # /----------------
134109
135110# -----------------
136111# Type stubs
137112# -----------------
138113
139- typings/uvicorn : $(PYRIGHT_PKG )
114+ typings/uvicorn : $(PYRIGHT )
140115 @echo " -------- Creating stub for uvicorn --------"
141- $(PYRIGHT ) --createstub uvicorn
116+ . $(PYBIN ) /activate && \
117+ pyright --createstub uvicorn
142118
143119typings/matplotlib/__init__.pyi : # # grab type stubs from GitHub
144120 @echo " -------- Creating stub for matplotlib --------"
@@ -147,14 +123,38 @@ typings/matplotlib/__init__.pyi: ## grab type stubs from GitHub
147123 mv typings/python-type-stubs/stubs/matplotlib typings/
148124 rm -rf typings/python-type-stubs
149125
150- typings/seaborn : $(PYRIGHT_PKG )
126+ typings/seaborn : $(PYRIGHT )
151127 @echo " -------- Creating stub for seaborn --------"
152- $(PYRIGHT ) --createstub seaborn
128+ . $(PYBIN ) /activate && \
129+ pyright --createstub seaborn
153130
154131pyright-typings : typings/uvicorn typings/matplotlib/__init__.pyi typings/seaborn
155- # /----------------
156132
133+ # -----------------
134+ # Install
135+ # -----------------
136+ # # install the package to the active Python's site-packages
137+ # Note that instead of --force-reinstall, we uninstall and then install, because
138+ # --force-reinstall also reinstalls all deps. And if we also used --no-deps, then the
139+ # deps wouldn't be installed the first time.
140+ install : dist $(PIP ) FORCE
141+ . $(PYBIN ) /activate && \
142+ pip uninstall -y shiny && \
143+ pip install dist/shiny* .whl
144+
145+ install-deps : $(UV ) FORCE # # install dependencies
146+ . $(PYBIN ) /activate && \
147+ uv pip install -e " .[dev,test]" --refresh
148+
149+
150+
151+ # ## If caching is ever used, we could run:
152+ # install-deps: ## install latest dependencies
153+ # pip install --editable ".[dev,test]" --upgrade --upgrade-strategy eager
157154
155+ # -----------------
156+ # Clean files
157+ # -----------------
158158clean : clean-build clean-pyc clean-test # # remove all build, test, coverage and Python artifacts
159159
160160clean-build : FORCE # # remove build artifacts
@@ -177,110 +177,126 @@ clean-test: FORCE ## remove test and coverage artifacts
177177 rm -fr .pytest_cache
178178 rm -rf typings/
179179
180-
181-
180+ # -----------------
181+ # Check lint, test, and format of code
182+ # -----------------
182183check : check-lint check-types check-tests # # check code, style, types, and test (basic CI)
183184check-fix : format check-lint check-types check-tests # # check and format code, style, types, and test
184185check-lint : check-ruff # # check code formatting and style
185186
186- check-ruff : $(PYBIN ) FORCE
187+ check-ruff : $(RUFF ) FORCE
187188 @echo " -------- Running ruff lint and formatting checks --------"
188189 @# Check imports in addition to code
189190 @# Reason for two commands: https://github.com/astral-sh/ruff/issues/8232
190- # $(PYBIN)/ruff check --select I .
191+ # . $(PYBIN)/activate && \
192+ # ruff check --select I --fix .
191193 # Check lints
192- $(PYBIN ) /ruff check .
194+ . $(PYBIN ) /activate && \
195+ ruff check .
193196 # Check formatting
194- $(PYBIN ) /ruff format --check .
195- check-types : pyright-typings $(PYRIGHT_PKG ) FORCE
197+ . $(PYBIN ) /activate && \
198+ ruff format --check .
199+ check-types : pyright-typings $(PYRIGHT ) FORCE # # check types with pyright
196200 @echo " -------- Checking types with pyright --------"
197- $(PYBIN ) /pyright
198- check-tests : $(PYTEST_PKG ) FORCE
201+ . $(PYBIN ) /activate && \
202+ pyright
203+ check-tests : $(PYTEST ) FORCE
199204 @echo " -------- Running tests with pytest --------"
200- $(PYTHON ) tests/pytest/asyncio_prevent.py
201- $(PYTEST )
205+ . $(PYBIN ) /activate && \
206+ python tests/pytest/asyncio_prevent.py
207+ . $(PYBIN ) /activate && \
208+ pytest
202209
203210
204- pyright : check-types # # check types with pyright
205- lint : check-lint # # check style with flake8
211+ pyright : check-types
212+ lint : check-lint
206213test : check-tests # # check tests quickly with the default Python
207214
215+ # -----------------
216+ # Fix formatting of code
217+ # -----------------
208218format : format-ruff # # format code
209219
210- format-ruff : $(PYBIN ) FORCE
220+ format-ruff : $(RUFF ) FORCE
211221 @echo " -------- Formatting code with ruff --------"
212222 @# Reason for two commands: https://github.com/astral-sh/ruff/issues/8232
213223 @# Fix imports
214- $(PYBIN ) /ruff check --select I --fix .
224+ . $(PYBIN ) /activate && \
225+ ruff check --select I --fix .
215226 @# Fix formatting
216- $(PYBIN ) /ruff format .
227+ . $(PYBIN ) /activate && \
228+ ruff format .
217229
218-
219- # format: format-black format-isort ## format code with black and isort
220- # format-black: $(BLACK_PKG) FORCE
221- # @echo "-------- Formatting code with black --------"
222- # $(PYTHON) -m black .
223- # format-isort: $(ISORT_PKG) FORCE
224- # @echo "-------- Sorting imports with isort --------"
225- # $(ISORT) .
226-
227- docs : FORCE # # docs: build docs with quartodoc
230+ # -----------------
231+ # Documentation
232+ # -----------------
233+ # Install docs deps; Used in `./docs/Makefile`
234+ install-docs : $(UV ) FORCE
235+ . $(PYBIN ) /activate && \
236+ uv pip install -e " .[dev,test,doc]" \
237+ " htmltools @ git+https://github.com/posit-dev/py-htmltools.git" \
238+ " shinylive @ git+https://github.com/posit-dev/py-shinylive.git"
239+
240+ docs : $(PYBIN ) FORCE # # docs: build quartodoc docs
241+ $(MAKE ) install-docs
228242 @echo " -------- Building docs with quartodoc --------"
229243 @cd docs && make quartodoc
230244
231- docs-preview : FORCE # # docs: preview docs in browser
245+ docs-preview : $(PYBIN ) FORCE # # docs: preview docs in browser
246+ $(MAKE ) install-docs
232247 @echo " -------- Previewing docs in browser --------"
233248 @cd docs && make serve
234249
250+ # -----------------
251+ # Testing with playwright
252+ # -----------------
253+
235254# Default `SUB_FILE` to empty
236255SUB_FILE: =
237256
238- install-playwright : $(PLAYWRIGHT_PKG ) FORCE
257+ install-playwright : $(PLAYWRIGHT ) FORCE
239258 @echo " -------- Installing playwright browsers --------"
240- @$(PLAYWRIGHT ) install --with-deps
259+ @. $(PYBIN ) /activate && \
260+ playwright install --with-deps
241261
242- playwright-shiny : install-playwright $(PYTEST_PKG ) FORCE # # end-to-end tests with playwright
243- $(PYTEST ) tests/playwright/shiny/$(SUB_FILE )
262+ playwright-shiny : install-playwright $(PYTEST ) FORCE # # end-to-end tests with playwright
263+ . $(PYBIN ) /activate && \
264+ pytest tests/playwright/shiny/$(SUB_FILE )
244265
245- playwright-deploys : install-playwright $(RSCONNECT_PKG ) $(PYTEST_PKG ) FORCE # # end-to-end tests on examples with playwright
246- $(PYTEST ) tests/playwright/deploys/$(SUB_FILE )
266+ playwright-deploys : install-playwright $(RSCONNECT ) $(PYTEST ) FORCE # # end-to-end tests on examples with playwright
267+ . $(PYBIN ) /activate && \
268+ pytest tests/playwright/deploys/$(SUB_FILE )
247269
248- playwright-examples : install-playwright $(PYTEST_PKG ) FORCE # # end-to-end tests on examples with playwright
249- $(PYTEST ) tests/playwright/examples/$(SUB_FILE )
270+ playwright-examples : install-playwright $(PYTEST ) FORCE # # end-to-end tests on examples with playwright
271+ . $(PYBIN ) /activate && \
272+ pytest tests/playwright/examples/$(SUB_FILE )
250273
251- playwright-debug : install-playwright $(PYTEST_PKG ) FORCE # # All end-to-end tests, chrome only, headed
252- $(PYTEST ) -c tests/playwright/playwright-pytest.ini tests/playwright/$(SUB_FILE )
274+ playwright-debug : install-playwright $(PYTEST ) FORCE # # All end-to-end tests, chrome only, headed
275+ . $(PYBIN ) /activate && \
276+ pytest -c tests/playwright/playwright-pytest.ini tests/playwright/$(SUB_FILE )
253277
254278playwright-show-trace : FORCE # # Show trace of failed tests
255279 npx playwright show-trace test-results/* /trace.zip
256280
257- testrail-junit : install-playwright $(TRCLI_PKG ) $(PYTEST_PKG ) FORCE # # end-to-end tests with playwright and generate junit report
258- $(PYTEST ) tests/playwright/shiny/$(SUB_FILE ) --junitxml=report.xml
281+ testrail-junit : install-playwright $(TRCLI ) $(PYTEST ) FORCE # # end-to-end tests with playwright and generate junit report
282+ . $(PYBIN ) /activate && \
283+ pytest tests/playwright/shiny/$(SUB_FILE ) --junitxml=report.xml
259284
260- coverage : $(PYTEST_PKG ) $(COVERAGE_PKG ) FORCE # # check combined code coverage (must run e2e last)
261- $(PYTEST ) --cov-report term-missing --cov=shiny tests/pytest/ tests/playwright/shiny/$(SUB_FILE )
262- $(PYBIN ) /coverage html
263- $(BROWSER ) htmlcov/index.html
285+ coverage : $(PYTEST ) $(COVERAGE ) FORCE # # check combined code coverage (must run e2e last)
286+ . $(PYBIN ) /activate && \
287+ pytest --cov-report term-missing --cov=shiny tests/pytest/ tests/playwright/shiny/$(SUB_FILE ) && \
288+ coverage html && \
289+ $(BROWSER ) htmlcov/index.html
264290
265- release : $(TWINE_PKG ) dist FORCE # # package and upload a release
266- $(PYBIN ) /twine upload dist/*
291+ # -----------------
292+ # Release
293+ # -----------------
294+ release : $(TWINE ) dist FORCE # # package and upload a release
295+ . $(PYBIN ) /activate && \
296+ twine upload dist/*
267297
268298dist : clean $(PYTHON ) FORCE # # builds source and wheel package
269- $(PYTHON ) setup.py sdist
270- $(PYTHON ) setup.py bdist_wheel
299+ . $(PYBIN ) /activate && \
300+ python setup.py sdist && \
301+ python setup.py bdist_wheel
271302 ls -l dist
272-
273- # # install the package to the active Python's site-packages
274- # Note that instead of --force-reinstall, we uninstall and then install, because
275- # --force-reinstall also reinstalls all deps. And if we also used --no-deps, then the
276- # deps wouldn't be installed the first time.
277- install : dist $(PIP ) FORCE
278- $(PIP ) uninstall -y shiny
279- $(PIP ) install dist/shiny* .whl
280-
281- install-deps : $(UV ) FORCE # # install dependencies
282- $(UV ) pip install -e " .[dev,test]" --refresh
283-
284- # ## If caching is ever used, we could run:
285- # install-deps: ## install latest dependencies
286- # pip install --editable ".[dev,test]" --upgrade --upgrade-strategy eager
0 commit comments