From 3f9d2911884445d11fc84eb4fe73a91e88e17329 Mon Sep 17 00:00:00 2001 From: Venelin Stoykov Date: Wed, 20 Dec 2023 00:34:54 +0200 Subject: [PATCH] Upate Python and Django versions - Use latest supported Python and Django versions and drop Python 2 support - Remove some deprecation warnings - Use GitHub Actions instead of TravisCI - Support passing None to validate_file_infection (#18) - Bump version to 1.0.0 --- .github/workflows/python.yaml | 39 ++++++++++++++++++++++++++++++ .gitignore | 1 + .travis.yml | 30 ----------------------- compose.yaml | 5 ++++ setup.cfg | 4 +-- setup.py | 27 +++++++++------------ src/django_clamd/tests/forms.py | 2 +- src/django_clamd/tests/settings.py | 8 +++++- src/django_clamd/tests/test.py | 12 ++++++++- src/django_clamd/validators.py | 4 ++- tox.ini | 38 +++++++++++++++++++++++------ 11 files changed, 111 insertions(+), 59 deletions(-) create mode 100644 .github/workflows/python.yaml delete mode 100644 .travis.yml create mode 100644 compose.yaml diff --git a/.github/workflows/python.yaml b/.github/workflows/python.yaml new file mode 100644 index 0000000..b06e4fe --- /dev/null +++ b/.github/workflows/python.yaml @@ -0,0 +1,39 @@ +name: Python CI + +on: + push: + branches: [ master ] + pull_request: + branches: [ master ] + +jobs: + build: + + runs-on: ubuntu-20.04 + + services: + clamav: + image: clamav/clamav:stable + ports: + - 3310 + + strategy: + max-parallel: 4 + matrix: + python-version: ["3.12", "3.11", "3.10", "3.9", "3.8", "3.7"] + + steps: + - uses: actions/checkout@v4 + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v5 + with: + python-version: ${{ matrix.python-version }} + - name: Install Dependencies + run: | + python -m pip install --upgrade pip + python -m pip install tox tox-gh-actions + - name: Run Tests + env: + CLAMD_USE_TCP: True + CLAMD_TCP_SOCKET: ${{ job.services.clamav.ports[3310] }} + run: tox diff --git a/.gitignore b/.gitignore index a930bd0..8d99563 100644 --- a/.gitignore +++ b/.gitignore @@ -2,5 +2,6 @@ *.egg* .tox .tags +.coverage* dist build diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index dfe665f..0000000 --- a/.travis.yml +++ /dev/null @@ -1,30 +0,0 @@ -language: python -python: - - 3.6 - - 3.5 -env: - - DJANGO=21 - - DJANGO=20 - - DJANGO=111 - -matrix: - fast_finish: true - include: - - python: 3.4 - env: DJANGO=111 - - python: 3.4 - env: DJANGO=18 - - - python: 2.7 - env: DJANGO=111 - - python: 2.7 - env: DJANGO=18 - -sudo: true -install: - - sudo apt-get install clamav-daemon clamav-freshclam clamav-unofficial-sigs - - sudo freshclam --verbose - - sudo service clamav-daemon start - - pip install tox - -script: tox -e py$(python -c 'import sys;print("".join(map(str, sys.version_info[:2])))')-dj${DJANGO} diff --git a/compose.yaml b/compose.yaml new file mode 100644 index 0000000..4af0429 --- /dev/null +++ b/compose.yaml @@ -0,0 +1,5 @@ +services: + clamav: + image: clamav/clamav:stable + ports: + - 3310 \ No newline at end of file diff --git a/setup.cfg b/setup.cfg index 02630fd..1f19245 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,5 +1,3 @@ -[wheel] -universal=1 - [flake8] ignore=E402 +max-line-length = 110 diff --git a/setup.py b/setup.py index 97c70cc..8b3b4d1 100644 --- a/setup.py +++ b/setup.py @@ -6,7 +6,7 @@ setup( name="django-clamd", - version='0.4.0', + version='1.0.0', author="Venelin Stoykov", author_email="vkstoykov@gmail.com", maintainer="Venelin Stoykov", @@ -27,29 +27,26 @@ "Development Status :: 5 - Production/Stable", "Environment :: Web Environment", "Framework :: Django", - "Framework :: Django :: 1.8", - "Framework :: Django :: 1.11", - "Framework :: Django :: 2.0", - "Framework :: Django :: 2.1", + "Framework :: Django :: 3.2", + "Framework :: Django :: 4.2", + "Framework :: Django :: 5.0", "Intended Audience :: Developers", - "License :: OSI Approved :: GNU Library or Lesser General Public License (LGPL)", + "License :: OSI Approved :: GNU Library or Lesser General Public License (LGPL)", # noqa "Operating System :: OS Independent", "Programming Language :: Python", - "Programming Language :: Python :: 2", - "Programming Language :: Python :: 2.7", "Programming Language :: Python :: 3", - "Programming Language :: Python :: 3.4", - "Programming Language :: Python :: 3.5", - "Programming Language :: Python :: 3.6", + "Programming Language :: Python :: 3.7", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", ], install_requires=( "clamd", "Django>=1.4", ), - tests_require=( - "nose==1.3.7", - ), - test_suite='nose.collector', zip_safe=False, include_package_data=True, ) diff --git a/src/django_clamd/tests/forms.py b/src/django_clamd/tests/forms.py index b436f4e..37820bc 100644 --- a/src/django_clamd/tests/forms.py +++ b/src/django_clamd/tests/forms.py @@ -3,4 +3,4 @@ class UploadForm(forms.Form): - upload_file = forms.FileField(validators=[validate_file_infection]) + upload_file = forms.FileField(validators=[validate_file_infection], required=False) diff --git a/src/django_clamd/tests/settings.py b/src/django_clamd/tests/settings.py index 591f7c3..e279814 100644 --- a/src/django_clamd/tests/settings.py +++ b/src/django_clamd/tests/settings.py @@ -1,4 +1,4 @@ - +import os DATABASES = { 'default': { @@ -15,3 +15,9 @@ SECRET_KEY = 'Anti virus scanner' LANGUAGE_CODE = 'en' + +USE_TZ = True + + +CLAMD_USE_TCP = bool(os.getenv("CLAMD_USE_TCP") or False) +CLAMD_TCP_SOCKET = int(os.getenv("CLAMD_TCP_SOCKET") or 3310) diff --git a/src/django_clamd/tests/test.py b/src/django_clamd/tests/test.py index 93cc841..d936fd9 100644 --- a/src/django_clamd/tests/test.py +++ b/src/django_clamd/tests/test.py @@ -26,7 +26,10 @@ def test_has_virus(self): }) def test_has_not_virus(self): - uploaded_file = SimpleUploadedFile('some file.txt', b'File without viruses') + uploaded_file = SimpleUploadedFile( + name='some file.txt', + content=b'File without viruses' + ) form = UploadForm(files={'upload_file': uploaded_file}) self.assertTrue(form.is_valid()) @@ -53,3 +56,10 @@ def tell(self): validate_file_infection(stream) self.assertGreaterEqual(stream._read_bytes, 5 * 1024 * 1024) self.assertEqual(stream.tell(), 0) + + def test_with_None(self): + validate_file_infection(None) + + def test_form_without_file(self): + form = UploadForm(files={'upload_file': None}) + self.assertTrue(form.is_valid()) diff --git a/src/django_clamd/validators.py b/src/django_clamd/validators.py index 1a08de2..9152efe 100644 --- a/src/django_clamd/validators.py +++ b/src/django_clamd/validators.py @@ -12,6 +12,8 @@ def validate_file_infection(file): + if file is None: + return # If django-clamd is disabled (for debugging) then do not check the file. if not CLAMD_ENABLED: warnings.warn('Running clamd validator with CLAMD_ENABLED=False') @@ -25,7 +27,7 @@ def validate_file_infection(file): # Ping the server if it fails than the server is down scanner.ping() # Server is up. This means that the file is too big. - logger.warn('The file is too large for ClamD to scan it. Bytes Read {}'.format(file.tell())) + logger.warning('The file is too large for ClamD to scan it. Bytes Read {}'.format(file.tell())) file.seek(0) if CLAMD_FAIL_BY_DEFAULT: raise ValidationError( diff --git a/tox.ini b/tox.ini index 0dcb882..29996e5 100644 --- a/tox.ini +++ b/tox.ini @@ -1,12 +1,36 @@ [tox] envlist = - py{36,35}-dj{21,20,111} - py{34,27}-{dj18,dj111} + py37-django32 + py38-django{42, 32} + py39-django{42, 32} + py310-django{42, 32} + py311-django{50, 42} + py312-django{50, 42} + py312-djangomain + +[gh-actions] +python = + 3.7: py37 + 3.8: py38 + 3.9: py39 + 3.10: py310 + 3.11: py311 + 3.12: py312 [testenv] -commands = python setup.py test +setenv = COVERAGE_FILE=.coverage.{envname} +passenv = + CLAMD_USE_TCP + CLAMD_TCP_SOCKET +commands = python -Wdefault -m pytest --cov --cov-report term-missing:skip-covered src/django_clamd/tests/test.py deps = - dj21: Django>=2.1,<2.2 - dj20: Django>=2.0,<2.1 - dj111: Django>=1.11,<2.0 - dj18: Django>=1.8,<1.9 + pytest + pytest-cov + django32: django~=3.2.0 + django41: django~=4.1.0 + django42: django~=4.2.0 + django50: django~=5.0.0 + djangomain: https://github.com/django/django/archive/refs/heads/main.zip + +ignore_outcome = + djangomain: true