diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e5cde27e..a0fa3c9f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -5,10 +5,8 @@ on: branches: [master] pull_request: branches: - - '**' + - "**" workflow_dispatch: - branches: - - '**' defaults: run: @@ -22,26 +20,26 @@ jobs: matrix: os: [ubuntu-latest] python-version: - - '3.12' + - "3.12" toxenv: [py, quality] steps: - - uses: actions/checkout@v4 - - name: setup python - uses: actions/setup-python@v5 - with: - python-version: ${{ matrix.python-version }} + - uses: actions/checkout@v4 + - name: setup python + uses: actions/setup-python@v5 + with: + python-version: ${{ matrix.python-version }} - - name: Install pip - run: pip install -r requirements/pip.txt + - name: Install pip + run: pip install -r requirements/pip.txt - - name: Install Dependencies - run: pip install -r requirements/ci.txt + - name: Install Dependencies + run: pip install -r requirements/ci.txt - - name: Run Tests - env: - TOXENV: ${{ matrix.toxenv }} - run: tox + - name: Run Tests + env: + TOXENV: ${{ matrix.toxenv }} + run: tox # Tests that used to be in the cookiecutter-django-ida Makefile but # that have not yet been moved into the regular unit tests (which @@ -52,50 +50,50 @@ jobs: matrix: os: [ubuntu-latest] python-version: - - '3.12' + - "3.12" steps: - - uses: actions/checkout@v4 - - - uses: actions/setup-python@v5 - with: - python-version: ${{ matrix.python-version }} - - - name: Generate demo project - run: | - make requirements - cookiecutter cookiecutter-django-ida --no-input - - - name: "Post-gen: Virtualenv, and set up requirements" - working-directory: repo_name - run: | - virtualenv .venv - source .venv/bin/activate - - make upgrade # TODO should be part of initial cookiecutter setup - make requirements - - - name: "Post-gen: Migrations" - working-directory: repo_name - run: | - source .venv/bin/activate - python manage.py makemigrations - make migrate - - - name: "Quality checks" - working-directory: repo_name - run: | - source .venv/bin/activate - make validate - - - name: "Ensure translations can be compiled" - working-directory: repo_name - run: | - source .venv/bin/activate - sudo apt install gettext # required for msguniq, called by makemessages management command - make fake_translations - - - name: "Ensure docker can build a container" - working-directory: repo_name - run: | - source .venv/bin/activate - docker build . --target app + - uses: actions/checkout@v4 + + - uses: actions/setup-python@v5 + with: + python-version: ${{ matrix.python-version }} + + - name: Generate demo project + run: | + make requirements + cookiecutter cookiecutter-django-ida --no-input + + - name: "Post-gen: Virtualenv, and set up requirements" + working-directory: repo_name + run: | + virtualenv .venv + source .venv/bin/activate + + make upgrade # TODO should be part of initial cookiecutter setup + make requirements + + - name: "Post-gen: Migrations" + working-directory: repo_name + run: | + source .venv/bin/activate + python manage.py makemigrations + make migrate + + - name: "Quality checks" + working-directory: repo_name + run: | + source .venv/bin/activate + make validate + + - name: "Ensure translations can be compiled" + working-directory: repo_name + run: | + source .venv/bin/activate + sudo apt install gettext # required for msguniq, called by makemessages management command + make fake_translations + + - name: "Ensure docker can build a container" + working-directory: repo_name + run: | + source .venv/bin/activate + docker build . --target app diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 255ac097..a4b95c43 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -5,6 +5,11 @@ Change Log This file loosely adheres to the structure of https://keepachangelog.com/, but in reStructuredText instead of Markdown. +2024-08-03 +********** + +- Dropped support for Python 3.8 and Django 3.2 + 2024-05-25 ********** diff --git a/cookiecutter-django-app/README.rst b/cookiecutter-django-app/README.rst index 72328c89..def2a8b6 100644 --- a/cookiecutter-django-app/README.rst +++ b/cookiecutter-django-app/README.rst @@ -54,7 +54,7 @@ Enter the project and take a look around: ls Generate a virtualenv and generate requirements files with dependencies -pinned to current versions (make sure you're using pip 9.0.2+ and Python 3.8): +pinned to current versions (make sure you're using pip 23.2+ and Python 3.12): .. code-block:: bash diff --git a/cookiecutter-django-app/{{cookiecutter.repo_name}}/.github/workflows/ci.yml b/cookiecutter-django-app/{{cookiecutter.repo_name}}/.github/workflows/ci.yml index 0b0f4d05..a48f3567 100644 --- a/cookiecutter-django-app/{{cookiecutter.repo_name}}/.github/workflows/ci.yml +++ b/cookiecutter-django-app/{{cookiecutter.repo_name}}/.github/workflows/ci.yml @@ -5,8 +5,7 @@ on: branches: [main] pull_request: branches: - - '**' - + - "**" jobs: run_tests: @@ -15,31 +14,30 @@ jobs: strategy: matrix: os: [ubuntu-latest] - python-version: ['3.8'] - toxenv: [quality, docs, pii_check, django32, django40] - + python-version: ["3.12"] + toxenv: [quality, docs, pii_check, django42] steps: - - uses: actions/checkout@v3 - - name: setup python - uses: actions/setup-python@v2 - with: - python-version: ${{ matrix.python-version }} - - - name: Install pip - run: pip install -r requirements/pip.txt - - - name: Install Dependencies - run: pip install -r requirements/ci.txt - - - name: Run Tests - env: - TOXENV: ${{ matrix.toxenv }} - run: tox - - - name: Run coverage - if: matrix.python-version == '3.8' && matrix.toxenv == 'django32' - uses: codecov/codecov-action@v4 - with: - token: ${{ secrets.CODECOV_TOKEN }} - flags: unittests - fail_ci_if_error: true + - uses: actions/checkout@v4 + - name: setup python + uses: actions/setup-python@v5 + with: + python-version: ${{ matrix.python-version }} + + - name: Install pip + run: pip install -r requirements/pip.txt + + - name: Install Dependencies + run: pip install -r requirements/ci.txt + + - name: Run Tests + env: + TOXENV: ${{ matrix.toxenv }} + run: tox + + - name: Run coverage + if: matrix.python-version == '3.12' && matrix.toxenv == 'django42' + uses: codecov/codecov-action@v4 + with: + token: ${{ secrets.CODECOV_TOKEN }} + flags: unittests + fail_ci_if_error: true diff --git a/cookiecutter-django-ida/README.rst b/cookiecutter-django-ida/README.rst index f59f422d..2e854c49 100644 --- a/cookiecutter-django-ida/README.rst +++ b/cookiecutter-django-ida/README.rst @@ -5,7 +5,7 @@ A cookiecutter_ template for Open edX Django projects. .. _cookiecutter: https://cookiecutter.readthedocs.org/en/latest/index.html -**This template produces a Python 3.8 project.** +**This template produces a Python 3.12 project.** This cookiecutter template is intended for new edX independently deployable apps (IDAs). It includes the following packages: diff --git a/cookiecutter-django-ida/{{cookiecutter.repo_name}}/.github/workflows/check-reserved-keywords.yml b/cookiecutter-django-ida/{{cookiecutter.repo_name}}/.github/workflows/check-reserved-keywords.yml index ee6440a2..5978ec79 100644 --- a/cookiecutter-django-ida/{{cookiecutter.repo_name}}/.github/workflows/check-reserved-keywords.yml +++ b/cookiecutter-django-ida/{{cookiecutter.repo_name}}/.github/workflows/check-reserved-keywords.yml @@ -10,12 +10,12 @@ jobs: steps: - name: Checkout code - uses: actions/checkout@v2 + uses: actions/checkout@v4 - name: setup python - uses: actions/setup-python@v2 + uses: actions/setup-python@v5 with: - python-version: 3.8 + python-version: 3.12 - name: Install pip run: pip install -r requirements/pip.txt diff --git a/cookiecutter-django-ida/{{cookiecutter.repo_name}}/Dockerfile b/cookiecutter-django-ida/{{cookiecutter.repo_name}}/Dockerfile index dffdcbe4..05cd8c60 100644 --- a/cookiecutter-django-ida/{{cookiecutter.repo_name}}/Dockerfile +++ b/cookiecutter-django-ida/{{cookiecutter.repo_name}}/Dockerfile @@ -21,7 +21,7 @@ FROM ubuntu:focal as app # If you add a package here please include a comment above describing what it is used for RUN apt-get update && DEBIAN_FRONTEND=noninteractive apt-get -qy install --no-install-recommends \ language-pack-en locales \ - python3.8 python3-dev python3-pip \ + python3.12 python3-dev python3-pip \ # The mysqlclient Python package has install-time dependencies libmysqlclient-dev libssl-dev pkg-config \ gcc diff --git a/cookiecutter-python-library/README.rst b/cookiecutter-python-library/README.rst index f707d231..78c9c41a 100644 --- a/cookiecutter-python-library/README.rst +++ b/cookiecutter-python-library/README.rst @@ -5,7 +5,7 @@ A cookiecutter_ template for edX python projects. For django-related cookiecutte .. _cookiecutter: https://cookiecutter.readthedocs.org/en/latest/index.html -**This template produces a Python 3.8 project.** +**This template produces a Python 3.12 project.** This cookiecutter template is intended for new edX python libraries. diff --git a/cookiecutter-xblock/{{cookiecutter.repo_name}}/.github/workflows/ci.yml b/cookiecutter-xblock/{{cookiecutter.repo_name}}/.github/workflows/ci.yml index 2bb499af..432f3798 100644 --- a/cookiecutter-xblock/{{cookiecutter.repo_name}}/.github/workflows/ci.yml +++ b/cookiecutter-xblock/{{cookiecutter.repo_name}}/.github/workflows/ci.yml @@ -5,8 +5,7 @@ on: branches: [main] pull_request: branches: - - '**' - + - "**" jobs: run_tests: @@ -15,31 +14,30 @@ jobs: strategy: matrix: os: [ubuntu-latest] - python-version: ['3.8'] - toxenv: [quality, docs, django32, django40] - + python-version: ["3.12"] + toxenv: [quality, docs, django42] steps: - - uses: actions/checkout@v3 - - name: setup python - uses: actions/setup-python@v2 - with: - python-version: ${{ matrix.python-version }} - - - name: Install pip - run: pip install -r requirements/pip.txt - - - name: Install Dependencies - run: pip install -r requirements/ci.txt - - - name: Run Tests - env: - TOXENV: ${{ matrix.toxenv }} - run: tox - - - name: Run coverage - if: matrix.python-version == '3.8' && matrix.toxenv == 'django32' - uses: codecov/codecov-action@v4 - with: - token: ${{ secrets.CODECOV_TOKEN }} - flags: unittests - fail_ci_if_error: true + - uses: actions/checkout@v4 + - name: setup python + uses: actions/setup-python@v5 + with: + python-version: ${{ matrix.python-version }} + + - name: Install pip + run: pip install -r requirements/pip.txt + + - name: Install Dependencies + run: pip install -r requirements/ci.txt + + - name: Run Tests + env: + TOXENV: ${{ matrix.toxenv }} + run: tox + + - name: Run coverage + if: matrix.python-version == '3.12' && matrix.toxenv == 'django42' + uses: codecov/codecov-action@v4 + with: + token: ${{ secrets.CODECOV_TOKEN }} + flags: unittests + fail_ci_if_error: true diff --git a/cookiecutter-xblock/{{cookiecutter.repo_name}}/Makefile b/cookiecutter-xblock/{{cookiecutter.repo_name}}/Makefile index 1fdbc3cc..20802d1d 100644 --- a/cookiecutter-xblock/{{cookiecutter.repo_name}}/Makefile +++ b/cookiecutter-xblock/{{cookiecutter.repo_name}}/Makefile @@ -51,6 +51,18 @@ dev.build: dev.run: dev.clean dev.build ## Clean, build and run test image docker run -p 8000:8000 -v $(CURDIR):/usr/local/src/$(REPO_NAME) --name $(REPO_NAME)-dev $(REPO_NAME)-dev +dev.stop: ## Stop the running container + docker stop $(REPO_NAME)-dev + +dev.migrate: ## Run migrations in the container + docker exec -it $(REPO_NAME)-dev python manage.py migrate + +dev.logs: ## View logs from the container + docker logs -f $(REPO_NAME)-dev + +dev.exec: ## Execute to the dev container + docker exec -it $(REPO_NAME)-dev /bin/bash + ## Localization targets extract_translations: ## extract strings to be translated, outputting .po files diff --git a/cookiecutter-xblock/{{cookiecutter.repo_name}}/requirements/base.in b/cookiecutter-xblock/{{cookiecutter.repo_name}}/requirements/base.in index 4def84e7..42ea69ff 100644 --- a/cookiecutter-xblock/{{cookiecutter.repo_name}}/requirements/base.in +++ b/cookiecutter-xblock/{{cookiecutter.repo_name}}/requirements/base.in @@ -5,4 +5,3 @@ django-statici18n edx-i18n-tools Mako XBlock -xblock-utils diff --git a/cookiecutter-xblock/{{cookiecutter.repo_name}}/{{cookiecutter.package_name}}/{{cookiecutter.package_name}}.py b/cookiecutter-xblock/{{cookiecutter.repo_name}}/{{cookiecutter.package_name}}/{{cookiecutter.package_name}}.py index d569a372..9e380136 100644 --- a/cookiecutter-xblock/{{cookiecutter.repo_name}}/{{cookiecutter.package_name}}/{{cookiecutter.package_name}}.py +++ b/cookiecutter-xblock/{{cookiecutter.repo_name}}/{{cookiecutter.package_name}}/{{cookiecutter.package_name}}.py @@ -1,11 +1,15 @@ """TO-DO: Write a description of what this XBlock is.""" -import pkg_resources +import os +from importlib import resources + from django.utils import translation from web_fragments.fragment import Fragment from xblock.core import XBlock from xblock.fields import Integer, Scope -from xblockutils.resources import ResourceLoader +from xblock.utils.resources import ResourceLoader + +resource_loader = ResourceLoader(__name__) class {{cookiecutter.class_name}}(XBlock): @@ -23,9 +27,11 @@ class {{cookiecutter.class_name}}(XBlock): ) def resource_string(self, path): - """Handy helper for getting resources from our kit.""" - data = pkg_resources.resource_string(__name__, path) - return data.decode("utf8") + """ + Retrieve string contents for the file path + """ + path = os.path.join('static', path) + return resource_loader.load_unicode(path) # TO-DO: change this view to display your data your own way. def student_view(self, context=None): @@ -34,16 +40,16 @@ def student_view(self, context=None): """ if context: pass # TO-DO: do something based on the context. - html = self.resource_string("static/html/{{cookiecutter.package_name}}.html") + html = self.resource_string("html/{{cookiecutter.package_name}}.html") frag = Fragment(html.format(self=self)) - frag.add_css(self.resource_string("static/css/{{cookiecutter.package_name}}.css")) + frag.add_css(self.resource_string("css/{{cookiecutter.package_name}}.css")) # Add i18n js statici18n_js_url = self._get_statici18n_js_url() if statici18n_js_url: frag.add_javascript_url(self.runtime.local_resource_url(self, statici18n_js_url)) - frag.add_javascript(self.resource_string("static/js/src/{{cookiecutter.package_name}}.js")) + frag.add_javascript(self.resource_string("js/src/{{cookiecutter.package_name}}.js")) frag.initialize_js('{{cookiecutter.class_name}}') return frag @@ -90,13 +96,12 @@ def _get_statici18n_js_url(): locale_code = translation.get_language() if locale_code is None: return None - text_js = 'public/js/translations/{locale_code}/text.js' + text_js = 'static/js/translations/{locale_code}/text.js' lang_code = locale_code.split('-')[0] for code in (locale_code, lang_code, 'en'): - loader = ResourceLoader(__name__) - if pkg_resources.resource_exists( - loader.module_name, text_js.format(locale_code=code)): - return text_js.format(locale_code=code) + text_js_path = text_js.format(locale_code=code) + if resources.files(resource_loader.module_name).joinpath(text_js_path).is_file(): + return text_js_path return None @staticmethod diff --git a/python-template/{{cookiecutter.placeholder_repo_name}}/.github/workflows/ci.yml b/python-template/{{cookiecutter.placeholder_repo_name}}/.github/workflows/ci.yml index 02269f1a..e6645cbd 100644 --- a/python-template/{{cookiecutter.placeholder_repo_name}}/.github/workflows/ci.yml +++ b/python-template/{{cookiecutter.placeholder_repo_name}}/.github/workflows/ci.yml @@ -2,11 +2,10 @@ name: Python CI on: push: - branches: [ main ] + branches: [main] pull_request: branches: - - '**' - + - "**" jobs: run_tests: @@ -15,13 +14,12 @@ jobs: strategy: matrix: os: [ubuntu-latest] - python-version: ['3.8'] - toxenv: ["py38", "quality", "docs", "pii_check"] - + python-version: ["3.12"] + toxenv: ["py311", "quality", "docs", "pii_check"] steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: setup python - uses: actions/setup-python@v2 + uses: actions/setup-python@v5 with: python-version: ${{ matrix.python-version }} @@ -37,7 +35,7 @@ jobs: run: tox - name: Run coverage - if: matrix.python-version == '3.8' && matrix.toxenv == 'py38' + if: matrix.python-version == '3.12' && matrix.toxenv == 'py312' uses: codecov/codecov-action@v4 with: token: ${{ secrets.CODECOV_TOKEN }} diff --git a/python-template/{{cookiecutter.placeholder_repo_name}}/.github/workflows/pypi-publish.yml b/python-template/{{cookiecutter.placeholder_repo_name}}/.github/workflows/pypi-publish.yml index da353d45..5cd627a3 100644 --- a/python-template/{{cookiecutter.placeholder_repo_name}}/.github/workflows/pypi-publish.yml +++ b/python-template/{{cookiecutter.placeholder_repo_name}}/.github/workflows/pypi-publish.yml @@ -5,17 +5,16 @@ on: types: [published] jobs: - push: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v2 + uses: actions/checkout@v4 - name: setup python - uses: actions/setup-python@v2 + uses: actions/setup-python@v5 with: - python-version: 3.8 + python-version: 3.12 - name: Install pip run: pip install -r requirements/pip.txt diff --git a/python-template/{{cookiecutter.placeholder_repo_name}}/.readthedocs.yaml b/python-template/{{cookiecutter.placeholder_repo_name}}/.readthedocs.yaml index ce8bde28..1d8cc9a0 100644 --- a/python-template/{{cookiecutter.placeholder_repo_name}}/.readthedocs.yaml +++ b/python-template/{{cookiecutter.placeholder_repo_name}}/.readthedocs.yaml @@ -14,7 +14,7 @@ sphinx: build: os: "ubuntu-22.04" tools: - python: "3.8" + python: "3.12" python: install: diff --git a/python-template/{{cookiecutter.placeholder_repo_name}}/docs/conf.py b/python-template/{{cookiecutter.placeholder_repo_name}}/docs/conf.py index e5812ce4..2270ebf6 100644 --- a/python-template/{{cookiecutter.placeholder_repo_name}}/docs/conf.py +++ b/python-template/{{cookiecutter.placeholder_repo_name}}/docs/conf.py @@ -523,9 +523,9 @@ def get_version(*file_paths): # Example configuration for intersphinx: refer to the Python standard library. intersphinx_mapping = { - 'python': ('https://docs.python.org/3.8', None), + 'python': ('https://docs.python.org/3.12', None), {%- if cookiecutter.requires_django == "yes" %} - 'django': ('https://docs.djangoproject.com/en/3.2/', 'https://docs.djangoproject.com/en/3.2/_objects/'), + 'django': ('https://docs.djangoproject.com/en/4.2/', 'https://docs.djangoproject.com/en/3.2/_objects/'), 'model_utils': ('https://django-model-utils.readthedocs.io/en/latest/', None), {%- endif %} } diff --git a/python-template/{{cookiecutter.placeholder_repo_name}}/setup.py b/python-template/{{cookiecutter.placeholder_repo_name}}/setup.py index 8a43be9f..5699f680 100755 --- a/python-template/{{cookiecutter.placeholder_repo_name}}/setup.py +++ b/python-template/{{cookiecutter.placeholder_repo_name}}/setup.py @@ -162,7 +162,7 @@ def package_data(pkg, roots): include_package_data=True, install_requires=load_requirements('requirements/base.in'), - python_requires=">=3.8", + python_requires=">=3.12", {%- if cookiecutter.open_source_license in license_classifiers %} license="{{ cookiecutter.open_source_license }}", {%- endif %} @@ -172,7 +172,7 @@ def package_data(pkg, roots): 'Development Status :: 3 - Alpha', {%- if cookiecutter.requires_django == "yes" %} 'Framework :: Django', - 'Framework :: Django :: 3.2', + 'Framework :: Django :: 4.2', {%- endif %} 'Intended Audience :: Developers', {%- if cookiecutter.open_source_license == "AGPL 3.0" %} @@ -184,7 +184,7 @@ def package_data(pkg, roots): {%- endif %} 'Natural Language :: English', 'Programming Language :: Python :: 3', - 'Programming Language :: Python :: 3.8', + 'Programming Language :: Python :: 3.12', ], {%- if cookiecutter.setup_py_keyword_args != "None" %} {{ cookiecutter.setup_py_keyword_args }}