mirror of
https://github.com/django-components/django-components.git
synced 2025-09-26 15:39:08 +00:00
Run tests for all officially supported Django/Python combos
This PR updates the CI to run against the same combinations of Django and Python that Django officially supports. It additionally adds a new script, that can automate this dance the next time: You simply run the script, and copy the results to tox.ini and setup.py.
This commit is contained in:
parent
d57db39f51
commit
b1ea325c5e
4 changed files with 198 additions and 10 deletions
9
.github/workflows/tests.yml
vendored
9
.github/workflows/tests.yml
vendored
|
@ -1,16 +1,17 @@
|
||||||
name: Run tests
|
name: Run tests
|
||||||
|
|
||||||
on:
|
on:
|
||||||
- push
|
push:
|
||||||
- pull_request
|
pull_request:
|
||||||
- workflow_dispatch
|
types: [opened, reopened]
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
runs-on: ubuntu-20.04
|
runs-on: ubuntu-20.04
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
python-version: ['3.6', '3.7', '3.8', '3.9', '3.10']
|
python-version: ['3.6', '3.7', '3.8', '3.9', '3.10', '3.11']
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v3
|
||||||
|
|
180
scripts/supported_versions.py
Normal file
180
scripts/supported_versions.py
Normal file
|
@ -0,0 +1,180 @@
|
||||||
|
import re
|
||||||
|
import textwrap
|
||||||
|
from collections import defaultdict
|
||||||
|
from urllib import request
|
||||||
|
|
||||||
|
|
||||||
|
def get_supported_versions(url):
|
||||||
|
with request.urlopen(url) as response:
|
||||||
|
response_content = response.read()
|
||||||
|
|
||||||
|
content = response_content.decode("utf-8")
|
||||||
|
|
||||||
|
def parse_supported_versions(content):
|
||||||
|
def cut_by_content(content, cut_from, cut_to):
|
||||||
|
return content.split(cut_from)[1].split(cut_to)[0]
|
||||||
|
|
||||||
|
def keys_from_content(content):
|
||||||
|
return re.findall(r"<td>(.*?)</td>", content)
|
||||||
|
|
||||||
|
content = cut_by_content(
|
||||||
|
content,
|
||||||
|
'<span id="what-python-version-can-i-use-with-django">',
|
||||||
|
"</table>",
|
||||||
|
)
|
||||||
|
content = cut_by_content(content, '<tbody valign="top">', "</tbody>")
|
||||||
|
|
||||||
|
versions = keys_from_content(content)
|
||||||
|
version_dict = dict(zip(versions[::2], versions[1::2]))
|
||||||
|
|
||||||
|
django_to_python = {
|
||||||
|
version_to_tuple(python_version): [
|
||||||
|
version_to_tuple(version_string)
|
||||||
|
for version_string in re.findall(
|
||||||
|
r"(?<!\.)\d+\.\d+(?!\.)", django_versions
|
||||||
|
)
|
||||||
|
]
|
||||||
|
for python_version, django_versions in version_dict.items()
|
||||||
|
}
|
||||||
|
return django_to_python
|
||||||
|
|
||||||
|
return parse_supported_versions(content)
|
||||||
|
|
||||||
|
|
||||||
|
def get_latest_version(url):
|
||||||
|
with request.urlopen(url) as response:
|
||||||
|
response_content = response.read()
|
||||||
|
|
||||||
|
content = response_content.decode("utf-8")
|
||||||
|
version_string = re.findall(
|
||||||
|
r"The latest official version is (\d+\.\d)", content
|
||||||
|
)[0]
|
||||||
|
return version_to_tuple(version_string)
|
||||||
|
|
||||||
|
|
||||||
|
def version_to_tuple(version_string):
|
||||||
|
return tuple(int(num) for num in version_string.split("."))
|
||||||
|
|
||||||
|
|
||||||
|
def build_python_to_django(django_to_python, latest_version):
|
||||||
|
python_to_django = defaultdict(list)
|
||||||
|
for django_version, python_versions in django_to_python.items():
|
||||||
|
for python_version in python_versions:
|
||||||
|
if django_version <= latest_version:
|
||||||
|
python_to_django[python_version].append(django_version)
|
||||||
|
|
||||||
|
python_to_django = dict(python_to_django)
|
||||||
|
return python_to_django
|
||||||
|
|
||||||
|
|
||||||
|
def env_format(version_tuple, divider=""):
|
||||||
|
return divider.join(str(num) for num in version_tuple)
|
||||||
|
|
||||||
|
|
||||||
|
def build_tox_envlist(python_to_django):
|
||||||
|
lines = [
|
||||||
|
(
|
||||||
|
env_format(python_version),
|
||||||
|
",".join(env_format(version) for version in django_versions),
|
||||||
|
)
|
||||||
|
for python_version, django_versions in python_to_django.items()
|
||||||
|
]
|
||||||
|
lines = [f"py{a}-django{{{b}}}" for a, b in lines]
|
||||||
|
version_lines = "\n".join([version for version in lines])
|
||||||
|
return "envlist = \n" + textwrap.indent(version_lines, prefix=" ")
|
||||||
|
|
||||||
|
|
||||||
|
def build_gh_actions_envlist(python_to_django):
|
||||||
|
lines = [
|
||||||
|
(
|
||||||
|
env_format(python_version, divider="."),
|
||||||
|
env_format(python_version),
|
||||||
|
",".join(env_format(version) for version in django_versions),
|
||||||
|
)
|
||||||
|
for python_version, django_versions in python_to_django.items()
|
||||||
|
]
|
||||||
|
lines = [f"{a}: py{b}-django{{{c}}}" for a, b, c in lines]
|
||||||
|
version_lines = "\n".join([version for version in lines])
|
||||||
|
return "python = \n" + textwrap.indent(version_lines, prefix=" ")
|
||||||
|
|
||||||
|
|
||||||
|
def build_deps_envlist(python_to_django):
|
||||||
|
all_django_versions = set()
|
||||||
|
for django_versions in python_to_django.values():
|
||||||
|
for django_version in django_versions:
|
||||||
|
all_django_versions.add(django_version)
|
||||||
|
|
||||||
|
lines = [
|
||||||
|
(
|
||||||
|
env_format(django_version),
|
||||||
|
env_format(django_version, divider="."),
|
||||||
|
env_format(
|
||||||
|
(django_version[0], django_version[1] + 1), divider="."
|
||||||
|
),
|
||||||
|
)
|
||||||
|
for django_version in all_django_versions
|
||||||
|
]
|
||||||
|
lines = [f"django{a}: Django>={b},<{c}" for a, b, c in lines]
|
||||||
|
return "deps = \n" + textwrap.indent("\n".join(lines), prefix=" ")
|
||||||
|
|
||||||
|
|
||||||
|
def build_pypi_classifiers(python_to_django):
|
||||||
|
classifiers = []
|
||||||
|
|
||||||
|
all_python_versions = python_to_django.keys()
|
||||||
|
for python_version in all_python_versions:
|
||||||
|
classifiers.append(
|
||||||
|
f"Programming Language :: Python :: {env_format(python_version, divider='.')}"
|
||||||
|
)
|
||||||
|
|
||||||
|
all_django_versions = set()
|
||||||
|
for django_versions in python_to_django.values():
|
||||||
|
for django_version in django_versions:
|
||||||
|
all_django_versions.add(django_version)
|
||||||
|
|
||||||
|
classifiers.append("...")
|
||||||
|
|
||||||
|
for django_version in all_django_versions:
|
||||||
|
classifiers.append(
|
||||||
|
f"Programming Language :: Django :: {env_format(django_version, divider='.')}"
|
||||||
|
)
|
||||||
|
|
||||||
|
return "classifiers=[\n" + textwrap.indent(
|
||||||
|
"\n".join(classifiers), prefix=" "
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
django_to_python = get_supported_versions(
|
||||||
|
"https://docs.djangoproject.com/en/dev/faq/install/"
|
||||||
|
)
|
||||||
|
latest_version = get_latest_version(
|
||||||
|
"https://www.djangoproject.com/download/"
|
||||||
|
)
|
||||||
|
|
||||||
|
python_to_django = build_python_to_django(django_to_python, latest_version)
|
||||||
|
|
||||||
|
tox_envlist = build_tox_envlist(python_to_django)
|
||||||
|
print("Add this to tox.ini:\n")
|
||||||
|
print("[tox]")
|
||||||
|
print(tox_envlist)
|
||||||
|
print()
|
||||||
|
|
||||||
|
gh_actions_envlist = build_gh_actions_envlist(python_to_django)
|
||||||
|
print("[gh-actions]")
|
||||||
|
print(gh_actions_envlist)
|
||||||
|
print()
|
||||||
|
|
||||||
|
deps_envlist = build_deps_envlist(python_to_django)
|
||||||
|
print("[testenv]")
|
||||||
|
print(deps_envlist)
|
||||||
|
print()
|
||||||
|
print()
|
||||||
|
|
||||||
|
print("Add this to setup.py:\n")
|
||||||
|
pypi_classifiers = build_pypi_classifiers(python_to_django)
|
||||||
|
print(pypi_classifiers)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
3
setup.py
3
setup.py
|
@ -28,9 +28,12 @@ setup(
|
||||||
"Programming Language :: Python :: 3.8",
|
"Programming Language :: Python :: 3.8",
|
||||||
"Programming Language :: Python :: 3.9",
|
"Programming Language :: Python :: 3.9",
|
||||||
"Programming Language :: Python :: 3.10",
|
"Programming Language :: Python :: 3.10",
|
||||||
|
"Programming Language :: Python :: 3.11",
|
||||||
"Operating System :: OS Independent",
|
"Operating System :: OS Independent",
|
||||||
"Framework :: Django",
|
"Framework :: Django",
|
||||||
"Framework :: Django :: 3.2",
|
"Framework :: Django :: 3.2",
|
||||||
"Framework :: Django :: 4.0",
|
"Framework :: Django :: 4.0",
|
||||||
|
"Framework :: Django :: 4.1",
|
||||||
|
"Framework :: Django :: 4.2",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
16
tox.ini
16
tox.ini
|
@ -5,9 +5,10 @@
|
||||||
envlist =
|
envlist =
|
||||||
py36-django{32}
|
py36-django{32}
|
||||||
py37-django{32}
|
py37-django{32}
|
||||||
py38-django{32,40}
|
py38-django{32,40,41,42}
|
||||||
py39-django{32,40}
|
py39-django{32,40,41,42}
|
||||||
py310-django{40}
|
py310-django{32,40,41,42}
|
||||||
|
py311-django{41,42}
|
||||||
flake8
|
flake8
|
||||||
isort
|
isort
|
||||||
|
|
||||||
|
@ -15,9 +16,10 @@ envlist =
|
||||||
python =
|
python =
|
||||||
3.6: py36-django{32}
|
3.6: py36-django{32}
|
||||||
3.7: py37-django{32}
|
3.7: py37-django{32}
|
||||||
3.8: py38-django{32,40}
|
3.8: py38-django{32,40,41,42}
|
||||||
3.9: py39-django{32,40}
|
3.9: py39-django{32,40,41,42}
|
||||||
3.10: py310-django{40}, flake8, isort
|
3.10: py310-django{32,40,41,42}
|
||||||
|
3.11: py311-django{41,42}, flake8, isort
|
||||||
fail_on_no_env = True
|
fail_on_no_env = True
|
||||||
|
|
||||||
[testenv]
|
[testenv]
|
||||||
|
@ -26,6 +28,8 @@ deps =
|
||||||
pytest-xdist
|
pytest-xdist
|
||||||
django32: Django>=3.2,<3.3
|
django32: Django>=3.2,<3.3
|
||||||
django40: Django>=4.0,<4.1
|
django40: Django>=4.0,<4.1
|
||||||
|
django41: Django>=4.1,<4.2
|
||||||
|
django42: Django>=4.2,<4.3
|
||||||
flake8
|
flake8
|
||||||
isort
|
isort
|
||||||
commands = py.test {posargs}
|
commands = py.test {posargs}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue