diff --git a/.github/workflows/production-deploy.yml b/.github/workflows/production-deploy.yml index fe7fb79..fd910ab 100644 --- a/.github/workflows/production-deploy.yml +++ b/.github/workflows/production-deploy.yml @@ -16,7 +16,7 @@ on: description: 'Branch to release from' required: true type: string - default: 'main' + default: 'master' seed: description: 'Random seed for reproducible sampling (float in [-1.0, 1.0]). Leave blank to auto-generate.' required: false @@ -34,7 +34,7 @@ on: default: '5' jobs: deploy: - uses: lambda-feedback/evaluation-function-workflows/.github/workflows/deploy.yml@deploy-request + uses: lambda-feedback/evaluation-function-workflows/.github/workflows/deploy.yml@main with: template-repository-name: 'lambda-feedback/evaluation-function-boilerplate-python' build-file: "app/Dockerfile" @@ -42,7 +42,7 @@ jobs: environment: "production" version-bump: ${{ inputs.version-bump }} branch: ${{ inputs.branch }} - run-database-tests: false + run-database-tests: true seed: ${{ inputs.seed }} request_delay: ${{ inputs.request_delay }} max_concurrency: ${{ inputs.max_concurrency }} diff --git a/.github/workflows/staging-deploy.yml b/.github/workflows/staging-deploy.yml index 9c354f2..caf18f5 100644 --- a/.github/workflows/staging-deploy.yml +++ b/.github/workflows/staging-deploy.yml @@ -3,7 +3,7 @@ name: Deploy to Staging on: push: branches: - - main + - master workflow_dispatch: jobs: @@ -18,7 +18,7 @@ jobs: strategy: fail-fast: false matrix: - python-version: ["3.8"] + python-version: ["3.12"] steps: - name: Checkout uses: actions/checkout@v4 @@ -59,7 +59,7 @@ jobs: if-no-files-found: warn deploy: needs: test - uses: lambda-feedback/evaluation-function-workflows/.github/workflows/deploy.yml@deploy-request + uses: lambda-feedback/evaluation-function-workflows/.github/workflows/deploy.yml@main with: template-repository-name: "lambda-feedback/evaluation-function-boilerplate-python" build-file: "app/Dockerfile" diff --git a/app/Dockerfile b/app/Dockerfile index 53ecbea..fa33537 100644 --- a/app/Dockerfile +++ b/app/Dockerfile @@ -1,15 +1,21 @@ -# Base image that bundles AWS Lambda Python 3.8 image with some middleware functions -# FROM base-eval-tmp -FROM ghcr.io/lambda-feedback/baseevalutionfunctionlayer:main-3.8 +# Base image that bundles the AWS Lambda Python image with the lambda-feedback middleware (app.handler) +FROM ghcr.io/lambda-feedback/baseevalutionfunctionlayer:main-3.12 + +# The 3.12 image is Amazon Linux 2023, which doesn't ship `find` (used below). +# git is needed to pip install latex2sympy from GitHub. +RUN dnf install -y git findutils && dnf clean all WORKDIR /app -RUN yum install -y git +ENV PYTHONPATH=/app # Copy and install any packages/modules needed for your evaluation script. COPY requirements.txt . RUN pip3 install -r requirements.txt +# The healthcheck command runs the pytest suite +RUN pip3 install pytest + # Copy the evaluation and testing scripts COPY evaluation.py ./app/ COPY evaluation_test.py ./app/ @@ -34,5 +40,6 @@ COPY docs/user.md ./app/docs/user.md RUN chmod 644 $(find . -type f) RUN chmod 755 $(find . -type d) -# The entrypoint for AWS is to invoke the handler function within the app package -CMD [ "/app/app.handler" ] +# The entrypoint for AWS is to invoke the handler function within the app package. +# Python 3.12's Lambda runtime imports this as a module name, so it can't be a path. +CMD [ "app.handler" ] diff --git a/app/expression_utilities.py b/app/expression_utilities.py index 17c313d..0253435 100644 --- a/app/expression_utilities.py +++ b/app/expression_utilities.py @@ -13,7 +13,9 @@ from sympy.parsing.sympy_parser import T as parser_transformations from sympy.printing.latex import LatexPrinter from sympy import Basic, Symbol +import io import re +import tokenize from typing import Dict, List, TypedDict class ModifiedLatexPrinter(LatexPrinter): @@ -573,6 +575,24 @@ def create_sympy_parsing_params(params, unsplittable_symbols=tuple(), symbol_ass return parsing_params +def reject_invalid_identifiers(expr): + ''' + Raise ValueError if expr contains a name token that is not a valid Python + identifier (e.g. `∞`). + + Python <= 3.11 tokenized such characters as ERRORTOKEN, which made + parse_expr fail. From Python 3.12 (PEP 701) they are emitted as NAME + tokens, and SymPy's auto_symbol silently turns them into symbols. + ''' + try: + tokens = list(tokenize.generate_tokens(io.StringIO(expr).readline)) + except (tokenize.TokenError, SyntaxError): + return # Leave genuine tokenizer errors for parse_expr to report + for token in tokens: + if token.type == tokenize.NAME and not token.string.isidentifier(): + raise ValueError(f"Invalid symbol `{token.string}` in expression `{expr}`") + + def parse_expression(expr, parsing_params): ''' Input: @@ -610,6 +630,7 @@ def parse_expression(expr, parsing_params): transformations = parser_transformations[0:5, 6]+extra_transformations+(split_symbols_custom(can_split),)+parser_transformations[8] if parsing_params.get("rationalise", False): transformations += parser_transformations[11] + reject_invalid_identifiers(expr) if parsing_params.get("simplify", False): parsed_expr = parse_expr(expr, transformations=transformations, local_dict=symbol_dict) parsed_expr = parsed_expr.simplify() diff --git a/app/requirements.txt b/app/requirements.txt index 1f9031a..670bf6a 100755 --- a/app/requirements.txt +++ b/app/requirements.txt @@ -1,5 +1,5 @@ typing_extensions mpmath==1.2.1 -sympy==1.10.1 +sympy==1.12.1 antlr4-python3-runtime==4.7.2 git+https://github.com/lambda-feedback/latex2sympy.git@master#egg=latex2sympy2 \ No newline at end of file diff --git a/pytest.ini b/pytest.ini new file mode 100644 index 0000000..589497f --- /dev/null +++ b/pytest.ini @@ -0,0 +1,4 @@ +[pytest] +# evaluation_tests.py is the name the base layer's healthcheck imports, so +# include it alongside pytest's default patterns. +python_files = test_*.py *_test.py *_tests.py diff --git a/readme.md b/readme.md index 7240643..a0eb1a4 100644 --- a/readme.md +++ b/readme.md @@ -52,7 +52,7 @@ Once the code passes all these tests, it will then be uploaded to AWS and will b ## Pre-requisites Although all programming can be done through the GitHub interface, it is recommended you do this locally on your machine. To do this, you must have installed: -- Python 3.8 or higher. +- Python 3.12 or higher. - GitHub Desktop or the `git` CLI.