Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update to Python 3.11, upgrade to SQLAlchemy 2.0 and Flask 2.4, refactor DB code #3446

Merged
merged 34 commits into from
Sep 15, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
3c42031
Upgrade to Python 3.11; bump backend packages
dezhidki Jul 4, 2023
7ad6d28
Refactor to support SQLAlchemy 1.4
dezhidki Jul 4, 2023
b4d779f
Refactor DB queries to use Select API
dezhidki Jul 4, 2023
aaf30be
Refactor to use selectin relationship loader by default
dezhidki Jul 19, 2023
ee44794
Fix tests for Flask 2.4; prepare for SQLAlchemy 2.0
dezhidki Jul 19, 2023
947343b
Bump SQLAlchemy to 2.0
dezhidki Jul 26, 2023
9fdb3c7
Convert Column to mapped_column columns in DB models
dezhidki Jul 26, 2023
a6c9368
Convert DB models to strongly typed Mapped models
dezhidki Jul 27, 2023
b47c2a8
Remove rarely used timtypes class
dezhidki Jul 29, 2023
44f489a
Clean up unused code
dezhidki Jul 29, 2023
c2f7514
Refactor to use SQLAlchemy classes directly instead of SQA-Flask proxy
dezhidki Jul 29, 2023
57a279c
Refactor db.session.execute -> run_sql
dezhidki Jul 29, 2023
8f22f38
Fix typos in models after refactor
dezhidki Jul 29, 2023
3a0b048
Upgrade to PostgreSQL 15
dezhidki Jul 29, 2023
3a0c714
Fix translation regression
dezhidki Aug 1, 2023
42cbc3b
Fix Celery not working
dezhidki Aug 1, 2023
b018149
Fix regression in user answer fetching
dezhidki Aug 1, 2023
e04d0b8
Fix MyPy errors
dezhidki Aug 1, 2023
a8f8b01
Fix formatting
dezhidki Aug 2, 2023
69e4e2d
Fix Python version in CI
dezhidki Aug 2, 2023
6c579c4
Fix tim-base image build target
dezhidki Aug 2, 2023
4d18a16
Use latest Chromedriver
dezhidki Aug 4, 2023
b9838d6
Fix typos
dezhidki Aug 4, 2023
31a8c0f
Fix MyPy error in CLI
dezhidki Aug 4, 2023
8c7bca5
Fix formatting
dezhidki Aug 4, 2023
3a92bf4
Fix regressions in test after Chromedriver upgrade
dezhidki Aug 4, 2023
71a6e19
Fix answer points roundup
dezhidki Aug 4, 2023
df73f71
Don't hash ExportedAnswer
dezhidki Aug 7, 2023
ac00b92
cli: Allow running tests with coverage
dezhidki Aug 9, 2023
f803bdc
Fix regressions after SQLAlchemy upgrade
dezhidki Aug 10, 2023
fe5b7e9
tim: Fix Chromedriver download, update package lock
dezhidki Sep 14, 2023
fa577f1
Fix regression in TIM messages and velps after SQA update
dezhidki Sep 15, 2023
1acc33b
Update Python packages, fix formatting and mypy errors, move back to …
dezhidki Sep 15, 2023
0d8a617
Ensure unzip is installed in tim container
dezhidki Sep 15, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/format.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ jobs:
name: Check Python formatting
runs-on: ubuntu-latest
env:
PYTHON_VERSION: "3.10"
PYTHON_VERSION: "3.11"

steps:
- uses: actions/checkout@v3
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/lint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ jobs:
name: Lint Python
runs-on: ubuntu-latest
env:
PYTHON_VERSION: "3.10"
PYTHON_VERSION: "3.11"

needs: skip_check
if: needs.skip_check.outputs.should_skip != 'true'
Expand Down
36 changes: 31 additions & 5 deletions cli/commands/dev/build.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,18 +27,29 @@
# 2. Specify the task and valid tags in the BUILD_TASKS dictionary.


def build_tim(tag: Optional[str], no_cache: bool) -> Optional[List[str]]:
def build_tim(
tag: Optional[str], no_cache: bool, build_args: List[str]
) -> Optional[List[str]]:
assert tag is not None
config = get_config()
image_suffix = "-base" if tag == "base" else ""
image_name = f"{config.images_repository}/tim{image_suffix}"
image_name_specific = f"{image_name}:{tim_image_tag()}"
image_name_latest = f"{image_name}:latest"
cwd = Path.cwd()
dockerfile = cwd / "timApp" / "Dockerfile"
build_args_cli = []
if build_args:
for arg in build_args:
build_args_cli.append("--build-arg")
build_args_cli.append(arg)
run_docker(
[
"build",
*(["--no-cache"] if no_cache else []),
*build_args_cli,
"--target",
tag,
"--tag",
image_name_specific,
"--tag",
Expand All @@ -51,15 +62,23 @@ def build_tim(tag: Optional[str], no_cache: bool) -> Optional[List[str]]:
return [image_name_specific, image_name_latest]


def build_csplugin(tag: Optional[str], no_cache: bool) -> Optional[List[str]]:
def build_csplugin(
tag: Optional[str], no_cache: bool, build_args: List[str]
) -> Optional[List[str]]:
assert tag is not None
config = get_config()
image_name = f"{config.images_repository}/cs3:{tag}-{csplugin_image_tag()}"
context = Path.cwd() / "timApp" / "modules" / "cs"
build_args_cli = []
if build_args:
for arg in build_args:
build_args_cli.append("--build-arg")
build_args_cli.append(arg)
run_docker(
[
"build",
*(["--no-cache"] if no_cache else []),
*build_args_cli,
"--tag",
image_name,
"--target",
Expand All @@ -76,12 +95,13 @@ def build_csplugin(tag: Optional[str], no_cache: bool) -> Optional[List[str]]:
class Arguments:
push: bool
no_cache: bool
build_args: List[str]
tasks: List[str]


class BuildTask(NamedTuple):
tags: Optional[List[str]]
build: Callable[[Optional[str], bool], Optional[List[str]]]
build: Callable[[Optional[str], bool, List[str]], Optional[List[str]]]


BUILD_TASKS: Dict[str, BuildTask] = {
Expand All @@ -104,12 +124,12 @@ def run(args: Arguments) -> None:
if build_tags:
for tag in build_tags:
log_info(f"Building {task}:{tag}")
images = build_task.build(tag, args.no_cache)
images = build_task.build(tag, args.no_cache, args.build_args)
if images:
built_images.extend(images)
else:
log_info(f"Building {task}")
images = build_task.build(None, args.no_cache)
images = build_task.build(None, args.no_cache, args.build_args)
if images:
built_images.extend(images)

Expand Down Expand Up @@ -137,6 +157,12 @@ def init(parser: ArgumentParser) -> None:
action="store_true",
dest="no_cache",
)
parser.add_argument(
"--build-arg",
help="Build arguments to pass to the Docker build command.",
action="append",
dest="build_args",
)
parser.add_argument(
"tasks",
nargs="*",
Expand Down
10 changes: 9 additions & 1 deletion cli/commands/test.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ class Arguments:
down: bool
up: bool
new_screenshots: bool
coverage: bool


BROWSER_TEST_SCRIPT = """
Expand Down Expand Up @@ -72,7 +73,8 @@ def run(args: Arguments) -> None:
else:
test_parameters = ["discover", "-v", f"tests/{args.target}", "test_*.py", "."]

test_command = ["python3", "-m", "unittest", *test_parameters]
base_command = ["python3"] if not args.coverage else ["coverage", "run"]
test_command = [*base_command, "-m", "unittest", *test_parameters]

# Browser tests can be flaky (in part of lackluster flask support for Selenium, in part of the tests).
# It's better to retry it a few times
Expand Down Expand Up @@ -125,3 +127,9 @@ def init(parser: ArgumentParser) -> None:
"Run a specific test module or test function. Format is <module>[.<function>]. "
"Special value 'all' runs all tests.",
)
parser.add_argument(
"--coverage",
help="Run tests with coverage",
action="store_true",
dest="coverage",
)
19 changes: 12 additions & 7 deletions cli/templates/docker/docker-compose.tmpl.yml
Original file line number Diff line number Diff line change
Expand Up @@ -71,9 +71,9 @@ services:
profiles:
- prod
- dev
image: postgres:11
image: postgres:15
volumes:
- data11:/var/lib/postgresql/data
- db_data:/var/lib/postgresql/data
command: [
"postgres",
"-c", "log_statement=mod",
Expand All @@ -88,7 +88,9 @@ services:
- /run/postgresql
- /tmp
environment:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgresql
POSTGRES_HOST_AUTH_METHOD: "md5"
ports: ${ jsonify(["5432:5432"] if tim.is_dev else []) }
logging:
# According to docs, "local" is more compact and performant than the default json-file driver.
Expand All @@ -97,7 +99,7 @@ services:
max-size: "50m"
max-file: "100"
postgresql-test:
image: postgres:11
image: postgres:15
profiles:
- test
- dev
Expand All @@ -106,7 +108,9 @@ services:
- /var/lib/postgresql/data
ports: ${ jsonify(["5433:5432"] if tim.is_dev else []) }
environment:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgresql
POSTGRES_HOST_AUTH_METHOD: "md5"
csplugin:
image: ${compose.images_repository}/cs3:${csplugin.target}-${csplugin.image_tag}
build:
Expand Down Expand Up @@ -258,7 +262,7 @@ ${ partial("docker", "csplugin_mongodb.tmpl.yml") if csplugin.is_mongodb_enabled
- redis_data:/data
celery:
image: ${compose.images_repository}/tim:${tim.image_tag}
command: celery worker -A timApp.tim_celery.celery --concurrency 4
command: celery -A timApp.tim_celery.celery worker --concurrency 4
profiles:
- prod
- dev
Expand Down Expand Up @@ -291,8 +295,8 @@ ${ partial("docker", "csplugin_mongodb.tmpl.yml") if csplugin.is_mongodb_enabled
- prod
- dev
command: >-
celery beat
-A timApp.tim_celery.celery
celery -A timApp.tim_celery.celery
beat
-S timApp.celery_sqlalchemy_scheduler.schedulers:DatabaseScheduler
--pidfile /var/run/celery/celerybeat.pid
volumes:
Expand Down Expand Up @@ -396,6 +400,7 @@ ${ partial("docker", "csplugin_mongodb.tmpl.yml") if csplugin.is_mongodb_enabled
volumes:
- .:/service:rw
environment:
TIM_TESTING: 1
TIM_SETTINGS: testconfig.py
PYTHONPATH: /service
CI: ${CI:-false}
Expand Down Expand Up @@ -426,7 +431,7 @@ ${ partial("docker", "csplugin_mongodb.tmpl.yml") if csplugin.is_mongodb_enabled
read_only: true
${ partial("docker", "mailman.tmpl.yml") if mailman.is_dev else "" }
volumes:
data11:
db_data:
cache:
caddy_data:
caddy_config:
Expand Down
Loading
Loading