From 9b2c390f13ef290ceac771ed55d1789bd5bba965 Mon Sep 17 00:00:00 2001 From: Peter Foley Date: Sat, 29 May 2021 17:21:55 -0400 Subject: [PATCH] test: use pytest setup.py test is deprecated, switch to pytest. Also fix a bunch of warnings it flagged. --- .github/workflows/ci.yml | 2 +- Ion.egg-info/SOURCES.txt | 7 ++ ci/spec.yml | 4 +- docs/conf.py | 2 +- .../intranet.apps.bus.management.commands.rst | 29 ++++++ .../intranet.apps.bus.management.rst | 18 ++++ docs/sourcedoc/intranet.apps.bus.rst | 8 ++ ...tranet.apps.events.management.commands.rst | 21 ++++ .../intranet.apps.events.management.rst | 18 ++++ docs/sourcedoc/intranet.apps.events.rst | 8 ++ intranet/apps/api/tests.py | 4 +- intranet/apps/auth/views.py | 6 +- intranet/apps/bus/management/__init__.py | 0 intranet/apps/bus/models.py | 3 + intranet/apps/bus/tests.py | 4 +- .../eighth/tests/admin/test_admin_general.py | 3 +- .../eighth/tests/admin/test_admin_groups.py | 10 +- intranet/apps/eighth/utils.py | 6 +- .../apps/eighth/views/admin/attendance.py | 5 +- intranet/apps/eighth/views/monitoring.py | 1 + intranet/apps/events/management/__init__.py | 0 intranet/apps/events/tests.py | 4 +- intranet/apps/events/views.py | 4 +- intranet/apps/users/api.py | 3 +- intranet/apps/users/tests.py | 3 +- intranet/settings/__init__.py | 18 +++- intranet/utils/helpers.py | 8 +- pytest.ini | 6 ++ scripts/format.sh | 2 +- scripts/validate-commit-messages.py | 95 +++++++++++-------- 30 files changed, 225 insertions(+), 77 deletions(-) create mode 100644 docs/sourcedoc/intranet.apps.bus.management.commands.rst create mode 100644 docs/sourcedoc/intranet.apps.bus.management.rst create mode 100644 docs/sourcedoc/intranet.apps.events.management.commands.rst create mode 100644 docs/sourcedoc/intranet.apps.events.management.rst create mode 100644 intranet/apps/bus/management/__init__.py create mode 100644 intranet/apps/events/management/__init__.py create mode 100644 pytest.ini diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1cb18eac55d..5499d94366a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,3 +1,3 @@ # WARNING: Do not edit this file manually! Edit ci/spec.yml and run ci/regen-workflow.py. -{"name": "CI", "on": ["push", "pull_request"], "defaults": {"run": {"shell": "bash"}}, "env": {"PRODUCTION": "TRUE"}, "jobs": {"linting": {"runs-on": "ubuntu-latest", "strategy": {"matrix": {"python-version": [3.7, 3.8]}, "fail-fast": false}, "steps": [{"name": "Set up repo", "uses": "actions/checkout@v2"}, {"name": "Set up Python ${{ matrix.python-version }}", "uses": "actions/setup-python@v2", "with": {"python-version": "${{ matrix.python-version }}"}}, {"name": "Set up pip cache", "uses": "actions/cache@v2", "with": {"path": "~/.cache/pip", "key": "pip-${{ matrix.python-version }}"}}, {"name": "Set up packages", "run": "set -e\n\npip install -U pip setuptools\npip install -U \\\n flake8 pylint pylint-django pylint-plugin-utils isort black==20.8b1 autopep8 \\\n coverage coveralls pyyaml\npip install -U -r requirements.txt\n\necho \"PATH=$PATH\" >> $GITHUB_ENV\n"}, {"name": "Copy secret.py", "run": "cp intranet/settings/ci_secret.py intranet/settings/secret.py"}, {"name": "Run flake8", "run": "flake8 --max-line-length 150 --exclude=*/migrations/* intranet/ scripts/ docs/ *.py"}, {"name": "Run pylint", "run": "pylint --jobs=0 --disable=fixme,broad-except,global-statement,attribute-defined-outside-init,cyclic-import --django-settings-module=intranet.settings intranet/"}, {"name": "Run isort", "run": "isort --check --recursive intranet"}]}, "formatting": {"runs-on": "ubuntu-latest", "strategy": {"matrix": {"python-version": [3.7, 3.8]}, "fail-fast": false}, "steps": [{"name": "Set up repo", "uses": "actions/checkout@v2"}, {"name": "Set up Python ${{ matrix.python-version }}", "uses": "actions/setup-python@v2", "with": {"python-version": "${{ matrix.python-version }}"}}, {"name": "Set up pip cache", "uses": "actions/cache@v2", "with": {"path": "~/.cache/pip", "key": "pip-${{ matrix.python-version }}"}}, {"name": "Set up packages", "run": "set -e\n\npip install -U pip setuptools\npip install -U \\\n flake8 pylint pylint-django pylint-plugin-utils isort black==20.8b1 autopep8 \\\n coverage coveralls pyyaml\npip install -U -r requirements.txt\n\necho \"PATH=$PATH\" >> $GITHUB_ENV\n"}, {"name": "Copy secret.py", "run": "cp intranet/settings/ci_secret.py intranet/settings/secret.py"}, {"name": "Format code", "run": "./scripts/build_ensure_no_changes.sh ./scripts/format.sh"}, {"name": "Format static files and templates", "run": "./scripts/build_ensure_no_changes.sh ./scripts/static_templates_format.sh"}]}, "build": {"runs-on": "ubuntu-latest", "strategy": {"matrix": {"python-version": [3.7, 3.8]}, "fail-fast": false}, "steps": [{"name": "Set up repo (fetching all commits)", "uses": "actions/checkout@v2", "with": {"fetch-depth": 0}}, {"name": "Set up Python ${{ matrix.python-version }}", "uses": "actions/setup-python@v2", "with": {"python-version": "${{ matrix.python-version }}"}}, {"name": "Set up pip cache", "uses": "actions/cache@v2", "with": {"path": "~/.cache/pip", "key": "pip-${{ matrix.python-version }}"}}, {"name": "Set up packages", "run": "set -e\n\npip install -U pip setuptools\npip install -U \\\n flake8 pylint pylint-django pylint-plugin-utils isort black==20.8b1 autopep8 \\\n coverage coveralls pyyaml\npip install -U -r requirements.txt\n\necho \"PATH=$PATH\" >> $GITHUB_ENV\n"}, {"name": "Copy secret.py", "run": "cp intranet/settings/ci_secret.py intranet/settings/secret.py"}, {"name": "Regenerate workflow YAML file and check for changes", "run": "./scripts/build_ensure_no_changes.sh ./ci/regen-workflow.py"}, {"name": "Build docs", "run": "./scripts/build_ensure_no_changes.sh ./scripts/build_docs.sh"}, {"name": "Build sources", "run": "./scripts/build_ensure_no_changes.sh ./scripts/build_sources.sh"}, {"name": "Check for changes to CI spec", "run": "./scripts/build_ensure_no_changes.sh ./ci/regen-workflow.py"}, {"name": "Check for unmigrated changes", "run": "./scripts/build_ensure_no_changes.sh ./manage.py migrate"}, {"name": "Validate PR commit messages", "if": "github.event_name == 'pull_request'", "run": "./scripts/validate-commit-messages.py ${{ github.event.pull_request.base.sha }}..${{ github.event.pull_request.head.sha }}"}, {"name": "Validate push commit messages", "if": "github.event_name == 'push' && (github.repository_owner != 'tjcsl' || github.ref != 'refs/heads/master' || github.ref != 'refs/heads/dev')", "run": "git fetch origin ${{ github.event.before }} && ./scripts/validate-commit-messages.py ${{ github.event.before }}..${{ github.event.after }}"}, {"name": "Push docs", "if": "github.event_name == 'push' && github.ref == 'refs/heads/master' && github.repository_owner == 'tjcsl' && matrix.python-version == 3.8", "run": "./scripts/push_docs.sh", "env": {"GH_TOKEN": "${{ secrets.DOCS_GH_TOKEN }}"}}]}, "tests": {"runs-on": "ubuntu-latest", "strategy": {"matrix": {"python-version": [3.7, 3.8], "node-version": ["12.x"]}, "fail-fast": false}, "services": {"rabbitmq": {"image": "rabbitmq:latest", "ports": ["5672:5672"], "options": "--health-cmd \"rabbitmqctl node_health_check\" --health-interval 6s --health-timeout 5s --health-retries 10"}, "redis": {"image": "redis:latest", "ports": ["6379:6379"], "options": "--entrypoint redis-server"}, "postgres": {"image": "postgres:latest", "env": {"POSTGRES_USER": "postgres", "POSTGRES_PASSWORD": "postgres", "POSTGRES_DB": "postgres"}, "ports": ["5432:5432"], "options": "--health-cmd pg_isready --health-interval 6s --health-timeout 5s --health-retries 9"}}, "steps": [{"name": "Set up repo", "uses": "actions/checkout@v2"}, {"name": "Set up Python ${{ matrix.python-version }}", "uses": "actions/setup-python@v2", "with": {"python-version": "${{ matrix.python-version }}"}}, {"name": "Set up pip cache", "uses": "actions/cache@v2", "with": {"path": "~/.cache/pip", "key": "pip-${{ matrix.python-version }}"}}, {"name": "Set up packages", "run": "set -e\n\npip install -U pip setuptools\npip install -U \\\n flake8 pylint pylint-django pylint-plugin-utils isort black==20.8b1 autopep8 \\\n coverage coveralls pyyaml\npip install -U -r requirements.txt\n\necho \"PATH=$PATH\" >> $GITHUB_ENV\n"}, {"name": "Copy secret.py", "run": "cp intranet/settings/ci_secret.py intranet/settings/secret.py"}, {"name": "Set up Node.js ${{ matrix.node-version }}", "uses": "actions/setup-node@v1", "with": {"node-version": "${{ matrix.node-version }}"}}, {"name": "Install Sass and add Node modules bin to PATH", "run": "set -e\nnpm install sass\necho \"PATH=${{ github.workspace }}/node_modules/.bin:$PATH\" >> $GITHUB_ENV\n"}, {"name": "Set and create PGPASSFILE", "run": "set -e\nPGPASSFILE=${{ runner.temp }}/.pgpass\necho \"PGPASSFILE=$PGPASSFILE\" >> $GITHUB_ENV\necho 127.0.0.1:5432:postgres:postgres:postgres >$PGPASSFILE\nchmod 600 $PGPASSFILE\n"}, {"name": "Create database", "run": "psql -U postgres -h 127.0.0.1 -c 'create database ion'"}, {"name": "install Kerberos", "run": "sudo apt install -y krb5-user"}, {"name": "Run tests", "run": "coverage run ./setup.py test"}, {"name": "Migrate database", "run": "coverage run -a ./manage.py migrate"}, {"name": "Collect static files", "run": "coverage run -a ./manage.py collectstatic --noinput -v 0"}, {"name": "Report coverage to Coveralls", "uses": "AndreMiras/coveralls-python-action@develop", "with": {"parallel": true}}, {"name": "Build coverage XML file", "if": "github.repository_owner == 'tjcsl' && github.event_name != 'pull_request'", "run": "coverage xml"}, {"name": "Report coverage to Codacy", "uses": "codacy/codacy-coverage-reporter-action@master", "if": "github.repository_owner == 'tjcsl' && github.event_name != 'pull_request'", "with": {"coverage-reports": "coverage.xml", "project-token": "${{ secrets.CODACY_PROJECT_TOKEN }}"}}]}, "finish_success": {"needs": ["linting", "formatting", "build", "tests"], "runs-on": "ubuntu-latest", "steps": [{"name": "Tell Coveralls that parallel jobs have finished", "uses": "coverallsapp/github-action@master", "with": {"github-token": "${{ secrets.GITHUB_TOKEN }}", "parallel-finished": true}}]}}} \ No newline at end of file +{"name": "CI", "on": ["push", "pull_request"], "defaults": {"run": {"shell": "bash"}}, "env": {"PRODUCTION": "TRUE"}, "jobs": {"linting": {"runs-on": "ubuntu-latest", "strategy": {"matrix": {"python-version": [3.7, 3.8]}, "fail-fast": false}, "steps": [{"name": "Set up repo", "uses": "actions/checkout@v2"}, {"name": "Set up Python ${{ matrix.python-version }}", "uses": "actions/setup-python@v2", "with": {"python-version": "${{ matrix.python-version }}"}}, {"name": "Set up pip cache", "uses": "actions/cache@v2", "with": {"path": "~/.cache/pip", "key": "pip-${{ matrix.python-version }}"}}, {"name": "Set up packages", "run": "set -e\n\npip install -U pip setuptools\npip install -U \\\n flake8 pylint pylint-django pylint-plugin-utils isort black==20.8b1 autopep8 \\\n coveralls pyyaml pytest-django\npip install -U -r requirements.txt\n\necho \"PATH=$PATH\" >> $GITHUB_ENV\n"}, {"name": "Copy secret.py", "run": "cp intranet/settings/ci_secret.py intranet/settings/secret.py"}, {"name": "Run flake8", "run": "flake8 --max-line-length 150 --exclude=*/migrations/* intranet/ scripts/ docs/ *.py"}, {"name": "Run pylint", "run": "pylint --jobs=0 --disable=fixme,broad-except,global-statement,attribute-defined-outside-init,cyclic-import --django-settings-module=intranet.settings intranet/"}, {"name": "Run isort", "run": "isort --check --recursive intranet"}]}, "formatting": {"runs-on": "ubuntu-latest", "strategy": {"matrix": {"python-version": [3.7, 3.8]}, "fail-fast": false}, "steps": [{"name": "Set up repo", "uses": "actions/checkout@v2"}, {"name": "Set up Python ${{ matrix.python-version }}", "uses": "actions/setup-python@v2", "with": {"python-version": "${{ matrix.python-version }}"}}, {"name": "Set up pip cache", "uses": "actions/cache@v2", "with": {"path": "~/.cache/pip", "key": "pip-${{ matrix.python-version }}"}}, {"name": "Set up packages", "run": "set -e\n\npip install -U pip setuptools\npip install -U \\\n flake8 pylint pylint-django pylint-plugin-utils isort black==20.8b1 autopep8 \\\n coveralls pyyaml pytest-django\npip install -U -r requirements.txt\n\necho \"PATH=$PATH\" >> $GITHUB_ENV\n"}, {"name": "Copy secret.py", "run": "cp intranet/settings/ci_secret.py intranet/settings/secret.py"}, {"name": "Format code", "run": "./scripts/build_ensure_no_changes.sh ./scripts/format.sh"}, {"name": "Format static files and templates", "run": "./scripts/build_ensure_no_changes.sh ./scripts/static_templates_format.sh"}]}, "build": {"runs-on": "ubuntu-latest", "strategy": {"matrix": {"python-version": [3.7, 3.8]}, "fail-fast": false}, "steps": [{"name": "Set up repo (fetching all commits)", "uses": "actions/checkout@v2", "with": {"fetch-depth": 0}}, {"name": "Set up Python ${{ matrix.python-version }}", "uses": "actions/setup-python@v2", "with": {"python-version": "${{ matrix.python-version }}"}}, {"name": "Set up pip cache", "uses": "actions/cache@v2", "with": {"path": "~/.cache/pip", "key": "pip-${{ matrix.python-version }}"}}, {"name": "Set up packages", "run": "set -e\n\npip install -U pip setuptools\npip install -U \\\n flake8 pylint pylint-django pylint-plugin-utils isort black==20.8b1 autopep8 \\\n coveralls pyyaml pytest-django\npip install -U -r requirements.txt\n\necho \"PATH=$PATH\" >> $GITHUB_ENV\n"}, {"name": "Copy secret.py", "run": "cp intranet/settings/ci_secret.py intranet/settings/secret.py"}, {"name": "Regenerate workflow YAML file and check for changes", "run": "./scripts/build_ensure_no_changes.sh ./ci/regen-workflow.py"}, {"name": "Build docs", "run": "./scripts/build_ensure_no_changes.sh ./scripts/build_docs.sh"}, {"name": "Build sources", "run": "./scripts/build_ensure_no_changes.sh ./scripts/build_sources.sh"}, {"name": "Check for changes to CI spec", "run": "./scripts/build_ensure_no_changes.sh ./ci/regen-workflow.py"}, {"name": "Check for unmigrated changes", "run": "./scripts/build_ensure_no_changes.sh ./manage.py migrate"}, {"name": "Validate PR commit messages", "if": "github.event_name == 'pull_request'", "run": "./scripts/validate-commit-messages.py ${{ github.event.pull_request.base.sha }}..${{ github.event.pull_request.head.sha }}"}, {"name": "Validate push commit messages", "if": "github.event_name == 'push' && (github.repository_owner != 'tjcsl' || github.ref != 'refs/heads/master' || github.ref != 'refs/heads/dev')", "run": "git fetch origin ${{ github.event.before }} && ./scripts/validate-commit-messages.py ${{ github.event.before }}..${{ github.event.after }}"}, {"name": "Push docs", "if": "github.event_name == 'push' && github.ref == 'refs/heads/master' && github.repository_owner == 'tjcsl' && matrix.python-version == 3.8", "run": "./scripts/push_docs.sh", "env": {"GH_TOKEN": "${{ secrets.DOCS_GH_TOKEN }}"}}]}, "tests": {"runs-on": "ubuntu-latest", "strategy": {"matrix": {"python-version": [3.7, 3.8], "node-version": ["12.x"]}, "fail-fast": false}, "services": {"rabbitmq": {"image": "rabbitmq:latest", "ports": ["5672:5672"], "options": "--health-cmd \"rabbitmqctl node_health_check\" --health-interval 6s --health-timeout 5s --health-retries 10"}, "redis": {"image": "redis:latest", "ports": ["6379:6379"], "options": "--entrypoint redis-server"}, "postgres": {"image": "postgres:latest", "env": {"POSTGRES_USER": "postgres", "POSTGRES_PASSWORD": "postgres", "POSTGRES_DB": "postgres"}, "ports": ["5432:5432"], "options": "--health-cmd pg_isready --health-interval 6s --health-timeout 5s --health-retries 9"}}, "steps": [{"name": "Set up repo", "uses": "actions/checkout@v2"}, {"name": "Set up Python ${{ matrix.python-version }}", "uses": "actions/setup-python@v2", "with": {"python-version": "${{ matrix.python-version }}"}}, {"name": "Set up pip cache", "uses": "actions/cache@v2", "with": {"path": "~/.cache/pip", "key": "pip-${{ matrix.python-version }}"}}, {"name": "Set up packages", "run": "set -e\n\npip install -U pip setuptools\npip install -U \\\n flake8 pylint pylint-django pylint-plugin-utils isort black==20.8b1 autopep8 \\\n coveralls pyyaml pytest-django\npip install -U -r requirements.txt\n\necho \"PATH=$PATH\" >> $GITHUB_ENV\n"}, {"name": "Copy secret.py", "run": "cp intranet/settings/ci_secret.py intranet/settings/secret.py"}, {"name": "Set up Node.js ${{ matrix.node-version }}", "uses": "actions/setup-node@v1", "with": {"node-version": "${{ matrix.node-version }}"}}, {"name": "Install Sass and add Node modules bin to PATH", "run": "set -e\nnpm install sass\necho \"PATH=${{ github.workspace }}/node_modules/.bin:$PATH\" >> $GITHUB_ENV\n"}, {"name": "Set and create PGPASSFILE", "run": "set -e\nPGPASSFILE=${{ runner.temp }}/.pgpass\necho \"PGPASSFILE=$PGPASSFILE\" >> $GITHUB_ENV\necho 127.0.0.1:5432:postgres:postgres:postgres >$PGPASSFILE\nchmod 600 $PGPASSFILE\n"}, {"name": "Create database", "run": "psql -U postgres -h 127.0.0.1 -c 'create database ion'"}, {"name": "install Kerberos", "run": "sudo apt install -y krb5-user"}, {"name": "Run tests", "run": "coverage run -m pytest"}, {"name": "Migrate database", "run": "coverage run -a ./manage.py migrate"}, {"name": "Collect static files", "run": "coverage run -a ./manage.py collectstatic --noinput -v 0"}, {"name": "Report coverage to Coveralls", "uses": "AndreMiras/coveralls-python-action@develop", "with": {"parallel": true}}, {"name": "Build coverage XML file", "if": "github.repository_owner == 'tjcsl' && github.event_name != 'pull_request'", "run": "coverage xml"}, {"name": "Report coverage to Codacy", "uses": "codacy/codacy-coverage-reporter-action@master", "if": "github.repository_owner == 'tjcsl' && github.event_name != 'pull_request'", "with": {"coverage-reports": "coverage.xml", "project-token": "${{ secrets.CODACY_PROJECT_TOKEN }}"}}]}, "finish_success": {"needs": ["linting", "formatting", "build", "tests"], "runs-on": "ubuntu-latest", "steps": [{"name": "Tell Coveralls that parallel jobs have finished", "uses": "coverallsapp/github-action@master", "with": {"github-token": "${{ secrets.GITHUB_TOKEN }}", "parallel-finished": true}}]}}} \ No newline at end of file diff --git a/Ion.egg-info/SOURCES.txt b/Ion.egg-info/SOURCES.txt index 2613d1e1b0f..f3c91dde4cd 100644 --- a/Ion.egg-info/SOURCES.txt +++ b/Ion.egg-info/SOURCES.txt @@ -15,6 +15,7 @@ deploy fabfile.py manage.py pyproject.toml +pytest.ini requirements.txt setup.py .dependabot/config.yml @@ -72,6 +73,8 @@ docs/sourcedoc/intranet.apps.api.rst docs/sourcedoc/intranet.apps.auth.management.commands.rst docs/sourcedoc/intranet.apps.auth.management.rst docs/sourcedoc/intranet.apps.auth.rst +docs/sourcedoc/intranet.apps.bus.management.commands.rst +docs/sourcedoc/intranet.apps.bus.management.rst docs/sourcedoc/intranet.apps.bus.rst docs/sourcedoc/intranet.apps.dashboard.rst docs/sourcedoc/intranet.apps.dataimport.management.commands.rst @@ -89,6 +92,8 @@ docs/sourcedoc/intranet.apps.eighth.views.rst docs/sourcedoc/intranet.apps.emailfwd.rst docs/sourcedoc/intranet.apps.emerg.rst docs/sourcedoc/intranet.apps.error.rst +docs/sourcedoc/intranet.apps.events.management.commands.rst +docs/sourcedoc/intranet.apps.events.management.rst docs/sourcedoc/intranet.apps.events.rst docs/sourcedoc/intranet.apps.features.rst docs/sourcedoc/intranet.apps.feedback.rst @@ -201,6 +206,7 @@ intranet/apps/bus/tasks.py intranet/apps/bus/tests.py intranet/apps/bus/urls.py intranet/apps/bus/views.py +intranet/apps/bus/management/__init__.py intranet/apps/bus/management/commands/__init__.py intranet/apps/bus/management/commands/import_routes.py intranet/apps/bus/management/commands/reset_routes.py @@ -394,6 +400,7 @@ intranet/apps/events/tasks.py intranet/apps/events/tests.py intranet/apps/events/urls.py intranet/apps/events/views.py +intranet/apps/events/management/__init__.py intranet/apps/events/management/commands/__init__.py intranet/apps/events/management/commands/import_sports.py intranet/apps/events/migrations/0001_initial.py diff --git a/ci/spec.yml b/ci/spec.yml index 7b17612bd10..b24be2d4393 100644 --- a/ci/spec.yml +++ b/ci/spec.yml @@ -59,7 +59,7 @@ env: pip install -U pip setuptools pip install -U \ flake8 pylint pylint-django pylint-plugin-utils isort black==20.8b1 autopep8 \ - coverage coveralls pyyaml + coveralls pyyaml pytest-django pip install -U -r requirements.txt echo "PATH=$PATH" >> $GITHUB_ENV @@ -230,7 +230,7 @@ jobs: # Tests - name: Run tests - run: coverage run ./setup.py test + run: coverage run -m pytest - name: Migrate database run: coverage run -a ./manage.py migrate - name: Collect static files diff --git a/docs/conf.py b/docs/conf.py index 179f2073ac7..70c5d8bcc0b 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -297,7 +297,7 @@ # Example configuration for intersphinx: refer to the Python standard library. intersphinx_mapping = { "python": ("https://docs.python.org/3", None), - "django": ("https://docs.djangoproject.com/en/dev", "https://docs.djangoproject.com/en/dev/_objects"), + "django": ("https://docs.djangoproject.com/en/dev", "https://docs.djangoproject.com/en/dev/_objects/"), } autodoc_inherit_docstrings = False diff --git a/docs/sourcedoc/intranet.apps.bus.management.commands.rst b/docs/sourcedoc/intranet.apps.bus.management.commands.rst new file mode 100644 index 00000000000..14027f0f60d --- /dev/null +++ b/docs/sourcedoc/intranet.apps.bus.management.commands.rst @@ -0,0 +1,29 @@ +intranet.apps.bus.management.commands package +============================================= + +Submodules +---------- + +intranet.apps.bus.management.commands.import\_routes module +----------------------------------------------------------- + +.. automodule:: intranet.apps.bus.management.commands.import_routes + :members: + :undoc-members: + :show-inheritance: + +intranet.apps.bus.management.commands.reset\_routes module +---------------------------------------------------------- + +.. automodule:: intranet.apps.bus.management.commands.reset_routes + :members: + :undoc-members: + :show-inheritance: + +Module contents +--------------- + +.. automodule:: intranet.apps.bus.management.commands + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/sourcedoc/intranet.apps.bus.management.rst b/docs/sourcedoc/intranet.apps.bus.management.rst new file mode 100644 index 00000000000..76a4a8c0cee --- /dev/null +++ b/docs/sourcedoc/intranet.apps.bus.management.rst @@ -0,0 +1,18 @@ +intranet.apps.bus.management package +==================================== + +Subpackages +----------- + +.. toctree:: + :maxdepth: 4 + + intranet.apps.bus.management.commands + +Module contents +--------------- + +.. automodule:: intranet.apps.bus.management + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/sourcedoc/intranet.apps.bus.rst b/docs/sourcedoc/intranet.apps.bus.rst index 9e214e5d42d..20a4b215591 100644 --- a/docs/sourcedoc/intranet.apps.bus.rst +++ b/docs/sourcedoc/intranet.apps.bus.rst @@ -1,6 +1,14 @@ intranet.apps.bus package ========================= +Subpackages +----------- + +.. toctree:: + :maxdepth: 4 + + intranet.apps.bus.management + Submodules ---------- diff --git a/docs/sourcedoc/intranet.apps.events.management.commands.rst b/docs/sourcedoc/intranet.apps.events.management.commands.rst new file mode 100644 index 00000000000..5a948248af8 --- /dev/null +++ b/docs/sourcedoc/intranet.apps.events.management.commands.rst @@ -0,0 +1,21 @@ +intranet.apps.events.management.commands package +================================================ + +Submodules +---------- + +intranet.apps.events.management.commands.import\_sports module +-------------------------------------------------------------- + +.. automodule:: intranet.apps.events.management.commands.import_sports + :members: + :undoc-members: + :show-inheritance: + +Module contents +--------------- + +.. automodule:: intranet.apps.events.management.commands + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/sourcedoc/intranet.apps.events.management.rst b/docs/sourcedoc/intranet.apps.events.management.rst new file mode 100644 index 00000000000..2a68c6f6e9e --- /dev/null +++ b/docs/sourcedoc/intranet.apps.events.management.rst @@ -0,0 +1,18 @@ +intranet.apps.events.management package +======================================= + +Subpackages +----------- + +.. toctree:: + :maxdepth: 4 + + intranet.apps.events.management.commands + +Module contents +--------------- + +.. automodule:: intranet.apps.events.management + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/sourcedoc/intranet.apps.events.rst b/docs/sourcedoc/intranet.apps.events.rst index 5022fd52019..98b5f7c6fb7 100644 --- a/docs/sourcedoc/intranet.apps.events.rst +++ b/docs/sourcedoc/intranet.apps.events.rst @@ -1,6 +1,14 @@ intranet.apps.events package ============================ +Subpackages +----------- + +.. toctree:: + :maxdepth: 4 + + intranet.apps.events.management + Submodules ---------- diff --git a/intranet/apps/api/tests.py b/intranet/apps/api/tests.py index 96e294607fe..7fedbbdb3bf 100644 --- a/intranet/apps/api/tests.py +++ b/intranet/apps/api/tests.py @@ -507,7 +507,7 @@ def test_api_eighth_signup_list(self): def test_api_bus_list(self): self.make_token() - route = Route.objects.create(route_name="JT-001", bus_number="JT-001") + route = Route.objects.create(route_name="JT-01", bus_number="JT-01") response = self.client.get(reverse("api_bus_list"), HTTP_AUTHORIZATION=self.auth) self.assertEqual(response.status_code, 200) @@ -517,7 +517,7 @@ def test_api_bus_list(self): def test_api_bus_detail(self): self.make_token() - route_1 = Route.objects.create(route_name="JT-001", bus_number="JT-001") + route_1 = Route.objects.create(route_name="JT-01", bus_number="JT-01") response = self.client.get(reverse("api_bus_detail", args=[route_1.pk]), HTTP_AUTHORIZATION=self.auth) self.assertEqual(response.status_code, 200) diff --git a/intranet/apps/auth/views.py b/intranet/apps/auth/views.py index ecd9e852d99..55c4f9037d6 100644 --- a/intranet/apps/auth/views.py +++ b/intranet/apps/auth/views.py @@ -22,7 +22,7 @@ from django.views.generic.base import View from ...utils.date import get_senior_graduation_date, get_senior_graduation_year -from ...utils.helpers import dark_mode_enabled, get_ap_week_warning +from ...utils.helpers import awaredate, dark_mode_enabled, get_ap_week_warning from ..dashboard.views import dashboard_view, get_fcps_emerg from ..eighth.models import EighthBlock from ..events.models import Event @@ -92,9 +92,7 @@ def get_week_sports_school_events() -> Tuple[Container[Event], Container[Event]] """ cache_result = cache.get("sports_school_events") if not isinstance(cache_result, tuple): - events = Event.objects.filter( - time__gte=timezone.localtime(), time__lte=(timezone.localdate() + relativedelta(weeks=1)), public=True - ).this_year() + events = Event.objects.filter(time__gte=timezone.localtime(), time__lte=(awaredate() + relativedelta(weeks=1)), public=True).this_year() sports_events = list(events.filter(approved=True, category="sports").order_by("time")[:3]) school_events = list(events.filter(approved=True, category="school").order_by("time")[:3]) diff --git a/intranet/apps/bus/management/__init__.py b/intranet/apps/bus/management/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/intranet/apps/bus/models.py b/intranet/apps/bus/models.py index 8f271887d05..30b1f0414c6 100644 --- a/intranet/apps/bus/models.py +++ b/intranet/apps/bus/models.py @@ -19,3 +19,6 @@ def reset_status(self): def __str__(self): return self.route_name + + class Meta: + ordering = ["route_name"] diff --git a/intranet/apps/bus/tests.py b/intranet/apps/bus/tests.py index a64f4754080..ccad2353090 100644 --- a/intranet/apps/bus/tests.py +++ b/intranet/apps/bus/tests.py @@ -36,7 +36,7 @@ def test_bus(self): m.assert_called() def test_routes(self): - route = Route.objects.get_or_create(route_name="JT-101", bus_number="JT-101")[0] + route = Route.objects.get_or_create(route_name="JT-01", bus_number="JT-01")[0] route.status = "a" route.space = "_1" route.save() @@ -47,7 +47,7 @@ def test_routes(self): self.assertEqual(route.space, "") def test_route_representation(self): - route = Route.objects.get_or_create(route_name="JT-101", bus_number="JT-101")[0] + route = Route.objects.get_or_create(route_name="JT-01", bus_number="JT-01")[0] route_str = str(route) self.assertEqual(route.route_name, route_str) diff --git a/intranet/apps/eighth/tests/admin/test_admin_general.py b/intranet/apps/eighth/tests/admin/test_admin_general.py index 1f8234d417d..8b638f3fc65 100644 --- a/intranet/apps/eighth/tests/admin/test_admin_general.py +++ b/intranet/apps/eighth/tests/admin/test_admin_general.py @@ -6,6 +6,7 @@ from intranet.apps.groups.models import Group +from .....utils.helpers import awaredate from ...models import EighthActivity, EighthBlock, EighthRoom, EighthSponsor from ..eighth_test import EighthAbstractTest @@ -33,7 +34,7 @@ def test_eighth_admin_dashboard_view(self): response = self.client.get(reverse("eighth_admin_dashboard")) self.assertTemplateUsed(response, "eighth/admin/dashboard.html") - self.assertEqual(response.context["start_date"], timezone.localdate()) + self.assertEqual(response.context["start_date"], awaredate()) self.assertQuerysetEqual(response.context["all_activities"], [repr(activity) for activity in EighthActivity.objects.all().order_by("name")]) self.assertQuerysetEqual(response.context["blocks_after_start_date"], [repr(block) for block in EighthBlock.objects.all()]) self.assertQuerysetEqual(response.context["groups"], [repr(group) for group in Group.objects.all().order_by("name")]) diff --git a/intranet/apps/eighth/tests/admin/test_admin_groups.py b/intranet/apps/eighth/tests/admin/test_admin_groups.py index 662abc71536..743986564a7 100644 --- a/intranet/apps/eighth/tests/admin/test_admin_groups.py +++ b/intranet/apps/eighth/tests/admin/test_admin_groups.py @@ -166,7 +166,7 @@ def test_download_group_csv_view(self): group = Group.objects.get_or_create(name="test group 5")[0] user1 = get_user_model().objects.get_or_create(username="2021ttest", first_name="Tommy", last_name="Test", student_id=1234568)[0] user2 = get_user_model().objects.get_or_create(username="2021ttest1", first_name="Thomas", last_name="Test", student_id=1234567)[0] - user3 = get_user_model().objects.get_or_create(username="2021awilliam", first_name="A", last_name="William", student_id=12345679)[0] + user3 = get_user_model().objects.get_or_create(username="2021awilliam", first_name="A", last_name="William", student_id=1234569)[0] for member in [user1, user2, user3]: member.groups.add(group) member.save() @@ -205,7 +205,7 @@ def test_eighth_admin_signup_group(self): username="2021awilliam", first_name="A", last_name="William", - student_id=12345679, + student_id=1234569, user_type="student", graduation_year=get_senior_graduation_year(), )[0] @@ -281,7 +281,7 @@ def test_eighth_admin_distribute_group(self): username="2021awilliam", first_name="A", last_name="William", - student_id=12345679, + student_id=1234569, user_type="student", graduation_year=get_senior_graduation_year(), )[0] @@ -352,7 +352,7 @@ def test_eighth_admin_distribute_unsigned(self): username="2021awilliam", first_name="A", last_name="William", - student_id=12345679, + student_id=1234569, user_type="student", graduation_year=get_senior_graduation_year(), )[0] @@ -417,7 +417,7 @@ def test_eighth_admin_distribute_action(self): username="2021awilliam", first_name="A", last_name="William", - student_id=12345679, + student_id=1234569, user_type="student", graduation_year=get_senior_graduation_year(), )[0] diff --git a/intranet/apps/eighth/utils.py b/intranet/apps/eighth/utils.py index 7d83bbc3d04..b006e82474f 100644 --- a/intranet/apps/eighth/utils.py +++ b/intranet/apps/eighth/utils.py @@ -2,15 +2,17 @@ from django.utils import timezone +from ...utils.helpers import awaredate + DATE_FORMAT = "%m-%d-%Y" def get_start_date(request): if "start_date" in request.session and request.session.get("start_date_set_date") == timezone.localdate().strftime(DATE_FORMAT): date = request.session["start_date"] - return datetime.strptime(date, DATE_FORMAT).date() + return timezone.make_aware(datetime.strptime(date, DATE_FORMAT)) else: - now = timezone.localdate() + now = awaredate() set_start_date(request, now) return now diff --git a/intranet/apps/eighth/views/admin/attendance.py b/intranet/apps/eighth/views/admin/attendance.py index 52e1689516f..5e623f1e5ef 100644 --- a/intranet/apps/eighth/views/admin/attendance.py +++ b/intranet/apps/eighth/views/admin/attendance.py @@ -9,6 +9,7 @@ from django.contrib.auth import get_user_model from django.db.models import Count, Q from django.shortcuts import redirect, render +from django.utils import timezone from .....utils.helpers import is_entirely_digit from ....auth.decorators import eighth_admin_required @@ -198,12 +199,12 @@ def after_deadline_signup_view(request): end_date = request.GET.get("end", "") try: - start_date = datetime.strptime(start_date, "%Y-%m-%d") + start_date = timezone.make_aware(datetime.strptime(start_date, "%Y-%m-%d")) except ValueError: start_date = get_start_date(request) try: - end_date = datetime.strptime(end_date, "%Y-%m-%d") + end_date = timezone.make_aware(datetime.strptime(end_date, "%Y-%m-%d")) except ValueError: end_date = start_date + timedelta(days=7) diff --git a/intranet/apps/eighth/views/monitoring.py b/intranet/apps/eighth/views/monitoring.py index a7fd198db29..070a1953f1e 100644 --- a/intranet/apps/eighth/views/monitoring.py +++ b/intranet/apps/eighth/views/monitoring.py @@ -36,6 +36,7 @@ def metrics_view(request): ) .filter(unique_signups__lt=F("total_signups")) .values_list("id", F("total_signups") - F("unique_signups")) + .order_by("date", "block_letter") .nocache() ): metrics['intranet_eighth_duplicate_signups{{block_id="{}"}}'.format(block_id)] = num_duplicates diff --git a/intranet/apps/events/management/__init__.py b/intranet/apps/events/management/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/intranet/apps/events/tests.py b/intranet/apps/events/tests.py index b9801e1812c..a2b83717d1f 100644 --- a/intranet/apps/events/tests.py +++ b/intranet/apps/events/tests.py @@ -143,7 +143,7 @@ def test_add_event(self): "location": "Location", "scheduled_activity": "", "announcement": "", - "groups": 1, + "groups": [], "show_attending": "on", "show_on_dashboard": "on", "category": "sports", @@ -228,7 +228,7 @@ def test_modify_event(self): "location": "New location", "scheduled_activity": "", "announcement": "", - "groups": 1, + "groups": [], "show_attending": "on", "show_on_dashboard": "on", "category": "sports", diff --git a/intranet/apps/events/views.py b/intranet/apps/events/views.py index fa6cfb6b17a..2b66586f873 100644 --- a/intranet/apps/events/views.py +++ b/intranet/apps/events/views.py @@ -7,7 +7,7 @@ from django.shortcuts import get_object_or_404, redirect, render from django.utils import timezone -from ...utils.helpers import get_id +from ...utils.helpers import awaredate, get_id from ...utils.html import safe_html from ..auth.decorators import deny_restricted from .forms import AdminEventForm, EventForm @@ -60,7 +60,7 @@ def events_view(request): viewable_events = Event.objects.visible_to_user(request.user).this_year().prefetch_related("groups") # get date objects for week and month - today = timezone.localtime().date() + today = awaredate() delta = today - timezone.timedelta(days=today.weekday()) this_week = (delta, delta + timezone.timedelta(days=7)) this_month = (this_week[1], this_week[1] + timezone.timedelta(days=31)) diff --git a/intranet/apps/users/api.py b/intranet/apps/users/api.py index 4b3d6005cf2..bd059a1ca88 100644 --- a/intranet/apps/users/api.py +++ b/intranet/apps/users/api.py @@ -75,7 +75,8 @@ def retrieve(self, request, *args, **kwargs): binary = user.default_photo if binary is None: default_image_path = os.path.join(settings.PROJECT_ROOT, "static/img/default_profile_pic.png") - binary = io.open(default_image_path, mode="rb").read() + with io.open(default_image_path, mode="rb") as f: + binary = f.read() return Response(binary, content_type="image/jpeg") diff --git a/intranet/apps/users/tests.py b/intranet/apps/users/tests.py index 0f74fa5aaea..64879cb29e6 100644 --- a/intranet/apps/users/tests.py +++ b/intranet/apps/users/tests.py @@ -556,7 +556,8 @@ def test_get_profile_picture_api(self): response = self.client.get(reverse("api_user_profile_picture_default", args=[user.pk]), HTTP_AUTHORIZATION=self.auth) self.assertEqual(response.content_type, "image/jpeg") image_path = os.path.join(settings.PROJECT_ROOT, "static/img/default_profile_pic.png") - self.assertEqual(response.content, io.open(image_path, mode="rb").read()) + with io.open(image_path, mode="rb") as f: + self.assertEqual(response.content, f.read()) response_with_username = self.client.get( reverse("api_user_profile_picture_default_by_username", args=[user.username]), HTTP_AUTHORIZATION=self.auth ) diff --git a/intranet/settings/__init__.py b/intranet/settings/__init__.py index 3c1dabec5a5..11b38f35c5c 100644 --- a/intranet/settings/__init__.py +++ b/intranet/settings/__init__.py @@ -71,7 +71,7 @@ PRODUCTION = os.getenv("PRODUCTION", "").upper() == "TRUE" IN_CI = any(os.getenv(key, "").upper() == "TRUE" for key in ["TRAVIS", "GITHUB_ACTIONS"]) # FIXME: figure out a less-hacky way to do this. -TESTING = "test" in sys.argv +TESTING = any("test" in arg for arg in sys.argv) LOGGING_VERBOSE = PRODUCTION # Whether to report master password attempts @@ -240,9 +240,18 @@ "CSS_COMPRESSOR": None, "COMPILERS": ["pipeline.compilers.sass.SASSCompiler"], "STYLESHEETS": { - "base": {"source_filenames": ["css/base.scss", "css/themes.scss", "css/responsive.scss"], "output_filename": "css/base.css"}, - "eighth.admin": {"source_filenames": ["css/eighth.common.scss", "css/eighth.admin.scss"], "output_filename": "css/eighth.admin.css"}, - "eighth.signup": {"source_filenames": ["css/eighth.common.scss", "css/eighth.signup.scss"], "output_filename": "css/eighth.signup.css"}, + "base": { + "source_filenames": ["css/base.scss", "css/themes.scss", "css/responsive.scss"], + "output_filename": "css/base.css", + }, + "eighth.admin": { + "source_filenames": ["css/eighth.common.scss", "css/eighth.admin.scss"], + "output_filename": "css/eighth.admin.css", + }, + "eighth.signup": { + "source_filenames": ["css/eighth.common.scss", "css/eighth.signup.scss"], + "output_filename": "css/eighth.signup.css", + }, }, } # type: Dict[str,Any] @@ -666,7 +675,6 @@ def get_log(name): # pylint: disable=redefined-outer-name; 'name' is used as th }, } - # The debug toolbar is always loaded, unless you manually override SHOW_DEBUG_TOOLBAR SHOW_DEBUG_TOOLBAR = os.getenv("SHOW_DEBUG_TOOLBAR", "YES") == "YES" diff --git a/intranet/utils/helpers.py b/intranet/utils/helpers.py index fc1a970fa7c..b5db2124085 100644 --- a/intranet/utils/helpers.py +++ b/intranet/utils/helpers.py @@ -7,15 +7,17 @@ from urllib import parse from django.conf import settings +from django.utils import timezone from ..apps.auth.helpers import get_login_theme_name from ..apps.emerg.views import get_emerg -# from django.template.loader import get_template -# from django.utils import timezone +logger = logging.getLogger("intranet.settings") -logger = logging.getLogger("intranet.settings") +def awaredate(): + # Note that date objects are always naive, so we have to use datetime for proper timezone support. + return timezone.localtime().replace(hour=0, minute=0, second=0, microsecond=0) def get_id(obj): diff --git a/pytest.ini b/pytest.ini new file mode 100644 index 00000000000..ea744ba11b3 --- /dev/null +++ b/pytest.ini @@ -0,0 +1,6 @@ +[pytest] +DJANGO_SETTINGS_MODULE = intranet.settings +python_files = tests.py test_*.py +# Suppress an pysftp warning about not having any ssh known_hosts. +filterwarnings = error + ignore:Failed to load HostKeys:UserWarning:pysftp diff --git a/scripts/format.sh b/scripts/format.sh index c55573c1ae8..a8145642b84 100755 --- a/scripts/format.sh +++ b/scripts/format.sh @@ -1,4 +1,4 @@ #!/bin/bash cd "$(dirname -- "$(dirname -- "$(readlink -f "$0")")")" -black intranet && autopep8 --in-place --recursive intranet && isort intranet +black . && autopep8 --in-place --recursive . && isort . diff --git a/scripts/validate-commit-messages.py b/scripts/validate-commit-messages.py index b330875ab9b..3674b825a55 100755 --- a/scripts/validate-commit-messages.py +++ b/scripts/validate-commit-messages.py @@ -25,58 +25,73 @@ def pluralize(value, singular="", plural="s"): return singular if value == 1 else plural -commits = [] -for arg in filter(bool, map(str.strip, sys.argv[1:])): - if ".." in arg: - commits.extend(get_output(["git", "log", "--format=%H", arg]).split()) - else: - commits.append(arg) +def get_commits(): + commits = [] + for arg in filter(bool, map(str.strip, sys.argv[1:])): + if ".." in arg: + commits.extend(get_output(["git", "log", "--format=%H", arg]).split()) + else: + commits.append(arg) -if not commits: - sys.exit(0) + if not commits: + sys.exit(0) + return commits -failed = False +def main(): + failed = False -for commit in commits: - short_hash = get_output(["git", "show", "--format=format:%h", "--no-patch", commit]) + for commit in get_commits(): + short_hash = get_output(["git", "show", "--format=format:%h", "--no-patch", commit]) - msg = get_output(["git", "show", "--format=format:%B", "--no-patch", commit]) - lines = msg.splitlines() + msg = get_output(["git", "show", "--format=format:%B", "--no-patch", commit]) + lines = msg.splitlines() - errors = [] + errors = [] - if re.search(r"^(build|chore|ci|docs|feat|fix|perf|refactor|style|test)(\([a-z]+\))?: .*$", lines[0],) is None: - errors.append("First line does not match format") + if ( + re.search( + r"^(build|chore|ci|docs|feat|fix|perf|refactor|style|test)(\([a-z]+\))?: .*$", + lines[0], + ) + is None + ): + errors.append("First line does not match format") - if re.search(r"[^:]: [a-z].*$", lines[0]) is None: - errors.append("First letter in commit message description is not lowercase.") + if re.search(r"[^:]: [a-z].*$", lines[0]) is None: + errors.append("First letter in commit message description is not lowercase.") - if len(lines) > 1 and lines[1]: - errors.append( - "Second line must be empty. Please put a blank line between the subject (first line) and the body/extended description (third line " - "onward). See the official git commit man page for more information: https://git-scm.com/docs/git-commit#_discussion" - ) + if len(lines) > 1 and lines[1]: + errors.append( + "Second line must be empty. Please put a blank line between the subject (first line) and the body/extended description (third line " + "onward). See the official git commit man page for more information: https://git-scm.com/docs/git-commit#_discussion" + ) - long_lines = [i + 1 for i, line in enumerate(lines) if len(line) > 72] - if long_lines: - errors.append( - "Line{} {} {} too long. Please limit all lines to 72 characters.".format( - pluralize(len(long_lines)), join_nicely(long_lines), pluralize(len(long_lines), "is", "are"), + long_lines = [i + 1 for i, line in enumerate(lines) if len(line) > 72] + if long_lines: + errors.append( + "Line{} {} {} too long. Please limit all lines to 72 characters.".format( + pluralize(len(long_lines)), + join_nicely(long_lines), + pluralize(len(long_lines), "is", "are"), + ) ) - ) - if errors: - print("The format of commit {} is invalid:".format(short_hash), file=sys.stderr) - for error in errors: - print("* {}".format(error), file=sys.stderr) + if errors: + print("The format of commit {} is invalid:".format(short_hash), file=sys.stderr) + for error in errors: + print("* {}".format(error), file=sys.stderr) + + failed = True - failed = True + if failed: + sys.exit(1) + else: + print( + "This commit message matches the correct format; *please review it for its content*.", + file=sys.stderr, + ) -if failed: - sys.exit(1) -else: - print( - "This commit message matches the correct format; *please review it for its content*.", file=sys.stderr, - ) +if __name__ == "__main__": + main()