-
Notifications
You must be signed in to change notification settings - Fork 60
/
Makefile
481 lines (391 loc) · 11.7 KB
/
Makefile
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
#
# Convenient Makefile to help with development.
#
# Try `make help` for help.
#
MODULE = aiosql
SHELL = /bin/bash
.ONESHELL:
PYTHON = python
LOGLVL = info
PYTEST = pytest --log-level=$(LOGLVL) --capture=tee-sys --asyncio-mode=auto
PYTOPT =
VENV = venv
PIP = pip
WAIT = ./tests/wait.py
.PHONY: help
help:
@echo "useful targets:"
echo " - help: show this help"
echo " - venv: generate python virtual environment directory"
echo " - venv.dev: make venv suitable for development"
echo " - venv.prod: make venv suitable for production"
echo " - venv.last: fill venv with latests packages"
echo " - clean: clean up various generated files and directories"
echo " - clean.venv: also remove the venv directory"
echo " - check.pytest: run pytest tests"
echo " - check.mypy: run mypy type checker"
echo " - check.flake8: run flake8 code style checks"
echo " - check.ruff: run ruff code style checks"
echo " - check.black: run black formatter checks"
echo " - check.coverage: run coverage and generate html report"
echo " - check.rstcheck: check rest files"
echo " - check: run all above checks"
echo " - publish: publish a new release on pypi (for maintainers)"
#
# VIRTUAL ENVIRONMENT
#
# NOTE: pinning module versions is somehow counter productive because we really
# want to work with multiple versions of python, which all have their own
# requirements and dependencies and random incompatibilities wrt libraries,
# so the result is kind of a mess, so we attempt at doing nearly nothing and
# hope for the best, i.e. dependencies will not break the library.
#
.PHONY: venv.dev venv.prod venv.last
venv:
$(PYTHON) -m venv venv
source venv/bin/activate
$(PIP) install --upgrade pip
venv.dev: venv
source venv/bin/activate
$(PIP) install .[dev,dev-postgres,dev-sqlite,dev-duckdb]
venv.dist: venv
source venv/bin/activate
$(PIP) install .[dist]
venv.prod: venv
venv.last: venv
source venv/bin/activate
$(PIP) install $$($(PIP) freeze | cut -d= -f1 | grep -v -- '^-e') -U
# direct module installation for github or docker
ifdef VENV
PIP = $(VENV)/bin/pip
INSTALL = $(VENV)/.aiosql_installed
else
INSTALL = .aiosql_installed
endif
$(INSTALL): $(VENV)
$(PIP) install -e .
touch $@
#
# CLEANUP
#
.PHONY: clean
clean:
find . -type d -name __pycache__ -print0 | xargs -0 rm -rf
$(RM) -r dist build .mypy_cache .pytest_cache htmlcov $(MODULE).egg-info docs/build docs/html
$(RM) .coverage .coverage.* poetry.lock
.PHONY: clean.venv
clean.venv: clean
$(RM) -r venv $(MODULE).egg-info
.PHONY: clean.docker
clean.docker: clean docker.rm
$(MAKE) -C docker clean
$(RM) .docker.*
#
# VARIOUS CHECKS
#
# the targets below are expected to work more or less for:
# - local tests (pytest managed instances)
# - local docker tests (docker servers, local client)
# - full docker tests (docker servers and clients)
# - github tests
#
.PHONY: check.mypy
check.mypy: $(VENV)
[ "$(VENV)" ] && source $(VENV)/bin/activate
mypy --install-types --non-interactive $(MODULE)
.PHONY: check.pyright
check.pyright: $(VENV)
[ "$(VENV)" ] && source $(VENV)/bin/activate
pyright $(MODULE)
.PHONY: check.ruff
check.ruff: $(VENV)
[ "$(VENV)" ] && source $(VENV)/bin/activate
ruff check $(MODULE)
.PHONY: check.flake8
check.flake8: $(VENV)
[ "$(VENV)" ] && source $(VENV)/bin/activate
flake8 $(MODULE)
.PHONY: check.black
check.black: $(VENV)
[ "$(VENV)" ] && source $(VENV)/bin/activate
black $(MODULE) tests --check
.PHONY: check.rstcheck
check.rstcheck: $(VENV)
[ "$(VENV)" ] && source $(VENV)/bin/activate
rstcheck --ignore-directives=toctree,literalinclude --ignore-roles=doc,ref docs/source/*.rst
.PHONY: check.pytest
check.pytest: check.pytest.local
# mysql or mariadb
MYSQL = mysql
.PHONY: check.pytest.local
check.pytest.local: check.pytest.misc check.pytest.postgres.local check.pytest.$(MYSQL).local
.PHONY: check.coverage
check.coverage: check.coverage.local
.PHONY: check
check: check.ruff check.pyright check.pytest check.coverage check.rstcheck
#
# pytest/coverage local/detached tests
#
check.pytest.%.detached: $(INSTALL)
check.pytest.%.local: WAIT=:
check.pytest.%.local: $(VENV)
#
# Postgres
#
PG_HOST = localhost
PG_PORT = 15432
PG_USER = pytest
PG_PASS = pytest
PG_NAME = pytest
PG_DETACHED = \
--postgresql-detached \
--postgresql-host=$(PG_HOST) \
--postgresql-port=$(PG_PORT) \
--postgresql-user=$(PG_USER) \
--postgresql-password=$(PG_PASS) \
--postgresql-dbname=$(PG_NAME)
.PHONY: check.pytest.postgres.detached
check.pytest.postgres.detached: PYTOPT+=$(PG_DETACHED)
check.pytest.postgres.detached: check.pytest.postgres
.PHONY: check.pytest.postgres.local
check.pytest.postgres.local: check.pytest.postgres
.PHONY: check.pytest.postgres
check.pytest.postgres: $(INSTALL)
[ "$(VENV)" ] && source $(VENV)/bin/activate
$(WAIT) $(PG_HOST) $(PG_PORT) 5 || exit 1
$(PYTEST) $(PYTOPT) \
tests/test_psycopg2.py \
tests/test_psycopg3.py \
tests/test_pygresql.py \
tests/test_pg8000.py \
tests/test_asyncpg.py
#
# MySQL
#
.PHONY: check.pytest.mysql.local
check.pytest.mysql.local: check.pytest.mysql
MY_HOST = localhost
MY_PORT = 13306
MY_USER = pytest
MY_PASS = pytest
MY_NAME = pytest
MY_DETACHED = \
--mysql-detached \
--mysql-tries=10 \
--mysql-host=$(MY_HOST) \
--mysql-port=$(MY_PORT) \
--mysql-user=$(MY_USER) \
--mysql-passwd=$(MY_PASS) \
--mysql-dbname=$(MY_NAME)
.PHONY: check.pytest.mysql.detached
check.pytest.mysql.detached: PYTOPT+=$(MY_DETACHED)
check.pytest.mysql.detached: check.pytest.mysql
.PHONY: check.pytest.mysql
check.pytest.mysql: $(INSTALL)
[ "$(VENV)" ] && source $(VENV)/bin/activate
# FIXME this does not seem to work…
$(WAIT) $(MY_HOST) $(MY_PORT) 10 || exit 1
set -e
# run with all 3 drivers
$(PYTEST) $(PYTOPT) --mysql-driver=MySQLdb tests/test_mysqldb.py
$(PYTEST) $(PYTOPT) --mysql-driver=mysql.connector tests/test_myco.py
$(PYTEST) $(PYTOPT) --mysql-driver=pymysql tests/test_pymysql.py
.PHONY: check.pytest.skip.local
check.pytest.skip.local:
# skip
#
# MariaDB
#
.PHONY: check.pytest.mariadb.local
check.pytest.mariadb.local: check.pytest.mariadb
MA_HOST = localhost
MA_PORT = 23306
MA_USER = pytest
MA_PASS = pytest
MA_NAME = pytest
MA_DETACHED = \
--mysql-detached \
--mysql-tries=2 \
--mysql-host=$(MA_HOST) \
--mysql-port=$(MA_PORT) \
--mysql-user=$(MA_USER) \
--mysql-passwd=$(MA_PASS) \
--mysql-dbname=$(MA_NAME)
.PHONY: check.pytest.mariadb.detached
check.pytest.mariadb.detached: PYTOPT+=$(MA_DETACHED)
check.pytest.mariadb.detached: check.pytest.mariadb
.PHONY: check.pytest.mariadb
check.pytest.mariadb: $(INSTALL)
[ "$(VENV)" ] && source $(VENV)/bin/activate
$(WAIT) $(MA_HOST) $(MA_PORT) 5 || exit 1
$(PYTEST) $(PYTOPT) --mysql-driver=mariadb tests/test_mariadb.py
#
# MS SQL Server
#
MS_HOST = localhost
MS_PORT = 1433
MS_USER = sa
MS_PASS = Abc123..
MS_NAME = pytest
MS_DETACHED = \
--mssql-tries=10 \
--mssql-server=$(MS_HOST) \
--mssql-port=$(MS_PORT) \
--mssql-user=$(MS_USER) \
--mssql-password=$(MS_PASS) \
--mssql-database=$(MS_NAME)
.PHONY: check.pytest.mssql.detached
check.pytest.mssql.detached: PYTOPT+=$(MS_DETACHED)
check.pytest.mssql.detached: check.pytest.mssql
.PHONY: check.pytest.mssql
check.pytest.mssql: $(INSTALL)
[ "$(VENV)" ] && source $(VENV)/bin/activate
sleep 5
$(WAIT) $(MS_HOST) $(MS_PORT) 10 || exit 1
$(PYTEST) $(PYTOPT) tests/test_pymssql.py
#
# SQLite3, DuckDB and Misc
#
.PHONY: check.pytest.misc
check.pytest.misc: $(INSTALL)
[ "$(VENV)" ] && source $(VENV)/bin/activate
$(PYTEST) $(PYTOPT) \
tests/test_loading.py \
tests/test_patterns.py \
tests/test_sqlite3.py \
tests/test_apsw.py \
tests/test_aiosqlite.py \
tests/test_duckdb.py
# run coverage by overriding PYTEST
COVERAGE = coverage
# parallel runs need a merge afterwards
COVER_RUN = $(COVERAGE) run -p
check.coverage.%: PYTEST=$(COVER_RUN) -m pytest
.PHONY: check.coverage.postgres.detached
check.coverage.postgres.detached: check.pytest.postgres.detached
.PHONY: check.coverage.postgres.local
check.coverage.postgres.local: check.pytest.postgres.local
.PHONY: check.coverage.mysql.detached
check.coverage.mysql.detached: check.pytest.mysql.detached
.PHONY: check.coverage.mysql.local
check.coverage.mysql.local: check.pytest.mysql.local
.PHONY: check.coverage.mariadb.detached
check.coverage.mariadb.detached: check.pytest.mariadb.detached
.PHONY: check.coverage.mariadb.local
check.coverage.mariadb.local: check.pytest.mariadb.local
.PHONY: check.coverage.mssql.detached
check.coverage.mssql.detached: check.pytest.mssql.detached
.PHONY: check.coverage.skip.local
check.coverage.skip.local:
# skipped!
.PHONY: check.coverage.misc
check.coverage.misc: check.pytest.misc
.PHONY: check.coverage.local
check.coverage.local: check.coverage.misc check.coverage.postgres.local check.coverage.$(MYSQL).local
$(MAKE) check.coverage.combine
IS_DOCKER =
FAIL_UNDER = $(shell python -c 'import sys; import platform; print(100.0 if sys.version_info < (3, 13) and platform.python_implementation() == "CPython" else 83.9)')
.PHONY: check.coverage.combine
check.coverage.combine: $(VENV)
[ "$(VENV)" ] && source $(VENV)/bin/activate
$(COVERAGE) combine
if [[ "$(IS_DOCKER)" ]] ; then
sqlite3 .coverage "UPDATE File SET path=REPLACE(path, '/code/', '$$PWD/')"
else
$(COVERAGE) html
fi
$(COVERAGE) report --show-missing --precision=1 --fail-under=$(FAIL_UNDER) --include='$(MODULE)/*'
#
# Docker runs
# - servers are started with docker
# - pytests run against them
#
.PHONY: docker.pytest
docker.pytest:
$(MAKE) -C docker $@
.PHONY: docker.coverage
docker.coverage:
$(MAKE) -C docker $@
$(MAKE) IS_DOCKER=1 check.coverage.combine
# start docker servers for local detached tests
.docker.run.postgres:
docker run -d --name aiosql-tests-postgres \
-p $(PG_PORT):5432 \
-e POSTGRES_USER=$(PG_USER) \
-e POSTGRES_PASSWORD=$(PG_PASS) \
-e POSTGRES_DB=$(PG_NAME) \
postgres
sleep 5
touch $@
.docker.run.mysql:
docker run -d --name aiosql-tests-mysql \
-p $(MY_PORT):3306 \
-e MYSQL_ROOT_PASSWORD=$(MY_PASS) \
-e MYSQL_USER=$(MY_USER) \
-e MYSQL_PASSWORD=$(MY_PASS) \
-e MYSQL_DATABASE=$(MY_NAME) \
mysql
sleep 5
touch $@
.docker.run.mariadb:
docker run -d --name aiosql-tests-mariadb \
-p $(MA_PORT):3306 \
-e MYSQL_ROOT_PASSWORD=$(MA_PASS) \
-e MYSQL_USER=$(MA_USER) \
-e MYSQL_PASSWORD=$(MA_PASS) \
-e MYSQL_DATABASE=$(MA_NAME) \
mariadb
sleep 5
touch $@
.docker.run.mssql:
docker run -d --name aiosql-tests-mssql \
-p $(MS_PORT):1433 \
-e ACCEPT_EULA=1 \
-e MSSQL_PID=Developer \
-e MSSQL_SA_PASSWORD=$(MS_PASS) \
mcr.microsoft.com/mssql/server:2022-latest
sleep 5
touch $@
.PHONY: check.pytest.docker.postgres
check.pytest.docker.postgres: .docker.run.postgres
$(MAKE) check.pytest.postgres.detached
.PHONY: check.pytest.docker.mysql
check.pytest.docker.mysql: .docker.run.mysql
$(MAKE) check.pytest.mysql.detached
.PHONY: check.pytest.docker.mariadb
check.pytest.docker.mariadb: .docker.run.mariadb
$(MAKE) check.pytest.mariadb.detached
.PHONY: check.pytest.docker.mssql
check.pytest.docker.mssql: .docker.run.mssql
$(MAKE) check.pytest.mssql.detached
# FIXME?
.PHONY: check.pytest.docker
check.pytest.docker:
$(MAKE) check.pytest.misc
$(MAKE) check.pytest.docker.postgres
$(MAKE) check.pytest.docker.mysql
$(MAKE) check.pytest.docker.mariadb
$(MAKE) check.pytest.docker.mssql
$(MAKE) docker.clean
DOCKER.server = aiosql-tests-postgres aiosql-tests-mysql aiosql-tests-mariadb aiosql-tests-mssql
.PHONY: docker.stop
docker.stop:
docker stop $(DOCKER.server) || exit 0
.PHONY: docker.rm
docker.rm: docker.stop
docker container rm $(DOCKER.server)
$(RM) .docker.run.*
#
# PYPI PUBLICATION
#
dist: venv.dist
source venv/bin/activate
$(PYTHON) -m build
check.publish: dist
source venv/bin/activate
twine check dist/*
.PHONY: publish
publish: dist
echo "# run twine to publish on pypi"
echo venv/bin/twine upload dist/*