From 48b2e2a0f9f0ceb253f6f77a2462aa2afe24205c Mon Sep 17 00:00:00 2001 From: Gert Van Gool Date: Fri, 29 Mar 2019 20:27:38 +0100 Subject: [PATCH 01/11] Adds example app --- example/__init__.py | 0 example/settings.py | 118 ++++++++++++++++++++++++++++++++++++++++++++ example/urls.py | 17 +++++++ example/wsgi.py | 28 +++++++++++ 4 files changed, 163 insertions(+) create mode 100644 example/__init__.py create mode 100644 example/settings.py create mode 100644 example/urls.py create mode 100644 example/wsgi.py diff --git a/example/__init__.py b/example/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/example/settings.py b/example/settings.py new file mode 100644 index 0000000..2ea2964 --- /dev/null +++ b/example/settings.py @@ -0,0 +1,118 @@ +# Django settings for example project. + +DEBUG = True +TEMPLATE_DEBUG = DEBUG + +ADMINS = ( + # ('Your Name', 'your_email@example.com'), +) + +MANAGERS = ADMINS + +DATABASES = { + 'default': { + 'ENGINE': 'django.db.backends.sqlite3', # Add 'postgresql_psycopg2', 'mysql', 'sqlite3' or 'oracle'. + 'NAME': ':memory:', # Or path to database file if using sqlite3. + 'USER': '', # Not used with sqlite3. + 'PASSWORD': '', # Not used with sqlite3. + 'HOST': '', # Set to empty string for localhost. Not used with sqlite3. + 'PORT': '', # Set to empty string for default. Not used with sqlite3. + } +} + +# Hosts/domain names that are valid for this site; required if DEBUG is False +# See https://docs.djangoproject.com/en/1.4/ref/settings/#allowed-hosts +ALLOWED_HOSTS = [] + +# Local time zone for this installation. Choices can be found here: +# http://en.wikipedia.org/wiki/List_of_tz_zones_by_name +# although not all choices may be available on all operating systems. +# In a Windows environment this must be set to your system time zone. +TIME_ZONE = 'America/Chicago' + +# Language code for this installation. All choices can be found here: +# http://www.i18nguy.com/unicode/language-identifiers.html +LANGUAGE_CODE = 'en-us' + +SITE_ID = 1 + +# If you set this to False, Django will make some optimizations so as not +# to load the internationalization machinery. +USE_I18N = True + +# If you set this to False, Django will not format dates, numbers and +# calendars according to the current locale. +USE_L10N = True + +# If you set this to False, Django will not use timezone-aware datetimes. +USE_TZ = True + +# Absolute filesystem path to the directory that will hold user-uploaded files. +# Example: "/home/media/media.lawrence.com/media/" +MEDIA_ROOT = '' + +# URL that handles the media served from MEDIA_ROOT. Make sure to use a +# trailing slash. +# Examples: "http://media.lawrence.com/media/", "http://example.com/media/" +MEDIA_URL = '' + +# Absolute path to the directory static files should be collected to. +# Don't put anything in this directory yourself; store your static files +# in apps' "static/" subdirectories and in STATICFILES_DIRS. +# Example: "/home/media/media.lawrence.com/static/" +STATIC_ROOT = '' + +# URL prefix for static files. +# Example: "http://media.lawrence.com/static/" +STATIC_URL = '/static/' + +# Additional locations of static files +STATICFILES_DIRS = ( + # Put strings here, like "/home/html/static" or "C:/www/django/static". + # Always use forward slashes, even on Windows. + # Don't forget to use absolute paths, not relative paths. +) + +# List of finder classes that know how to find static files in +# various locations. +STATICFILES_FINDERS = ( + 'django.contrib.staticfiles.finders.FileSystemFinder', + 'django.contrib.staticfiles.finders.AppDirectoriesFinder', +# 'django.contrib.staticfiles.finders.DefaultStorageFinder', +) + +# Make this unique, and don't share it with anybody. +SECRET_KEY = '3$q5+il@s_@%7@rc*brr^&v^rc*0c_f+gecwq+la+a9n-c$l!5' + +# List of callables that know how to import templates from various sources. +TEMPLATE_LOADERS = ( + 'django.template.loaders.filesystem.Loader', + 'django.template.loaders.app_directories.Loader', +) + +MIDDLEWARE_CLASSES = ( + 'django.middleware.common.CommonMiddleware', + 'django.contrib.sessions.middleware.SessionMiddleware', + 'django.middleware.csrf.CsrfViewMiddleware', + 'django.contrib.auth.middleware.AuthenticationMiddleware', + 'django.contrib.messages.middleware.MessageMiddleware', +) + +ROOT_URLCONF = 'example.urls' + +# Python dotted path to the WSGI application used by Django's runserver. +WSGI_APPLICATION = 'example.wsgi.application' + +INSTALLED_APPS = ( + 'django.contrib.auth', + 'django.contrib.contenttypes', + 'django.contrib.sessions', + 'django.contrib.sites', + 'django.contrib.messages', + 'django.contrib.staticfiles', + 'django.contrib.admin', + 'flickr', + 'taggit', + 'taggit_templatetags', +) + diff --git a/example/urls.py b/example/urls.py new file mode 100644 index 0000000..4cad48f --- /dev/null +++ b/example/urls.py @@ -0,0 +1,17 @@ +from django.conf.urls import patterns, include, url + +# Uncomment the next two lines to enable the admin: +# from django.contrib import admin +# admin.autodiscover() + +urlpatterns = patterns('', + # Examples: + # url(r'^$', 'example.views.home', name='home'), + # url(r'^example/', include('example.foo.urls')), + + # Uncomment the admin/doc line below to enable admin documentation: + # url(r'^admin/doc/', include('django.contrib.admindocs.urls')), + + # Uncomment the next line to enable the admin: + # url(r'^admin/', include(admin.site.urls)), +) diff --git a/example/wsgi.py b/example/wsgi.py new file mode 100644 index 0000000..9b42e63 --- /dev/null +++ b/example/wsgi.py @@ -0,0 +1,28 @@ +""" +WSGI config for example project. + +This module contains the WSGI application used by Django's development server +and any production WSGI deployments. It should expose a module-level variable +named ``application``. Django's ``runserver`` and ``runfcgi`` commands discover +this application via the ``WSGI_APPLICATION`` setting. + +Usually you will have the standard Django WSGI application here, but it also +might make sense to replace the whole Django WSGI application with a custom one +that later delegates to the Django one. For example, you could introduce WSGI +middleware here, or combine a Django application with an application of another +framework. + +""" +import os + +os.environ.setdefault("DJANGO_SETTINGS_MODULE", "example.settings") + +# This application object is used by any WSGI server configured to use this +# file. This includes Django's development server, if the WSGI_APPLICATION +# setting points here. +from django.core.wsgi import get_wsgi_application +application = get_wsgi_application() + +# Apply WSGI middleware here. +# from helloworld.wsgi import HelloWorldApplication +# application = HelloWorldApplication(application) From 360c9b485bf8f6e86771d9cb39c215768c823f7e Mon Sep 17 00:00:00 2001 From: Gert Van Gool Date: Fri, 29 Mar 2019 20:28:15 +0100 Subject: [PATCH 02/11] Sets upper limits to package for known working versions --- req.pip | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/req.pip b/req.pip index 8c5ed3c..561669d 100644 --- a/req.pip +++ b/req.pip @@ -1,5 +1,5 @@ -django>=1.4 -bunch -django-taggit -django-taggit-templatetags -oauth2 \ No newline at end of file +django>=1.4,<1.5 +bunch==1.0.1 +django-taggit==0.9.3 +django-taggit-templatetags==0.4.6.dev0 +oauth2==1.5.211 From 3a0b5083ddaaee86792a4bcf965744b6a9c14f40 Mon Sep 17 00:00:00 2001 From: Gert Van Gool Date: Fri, 29 Mar 2019 20:44:32 +0100 Subject: [PATCH 03/11] Run tests --- .gitlab-ci.yml | 21 +++++++++++++++++++++ requirements_test.txt | 4 ++++ setup.cfg | 13 +++++++++++++ tox.ini | 26 ++++++++++++++++++++++++++ 4 files changed, 64 insertions(+) create mode 100644 .gitlab-ci.yml create mode 100644 requirements_test.txt create mode 100644 setup.cfg create mode 100644 tox.ini diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml new file mode 100644 index 0000000..e851587 --- /dev/null +++ b/.gitlab-ci.yml @@ -0,0 +1,21 @@ +stages: + - build + - test + +before_script: + - pip install tox + +build: + image: python:2.7 + stage: build + script: + - python setup.py sdist bdist_wheel --universal + - echo "What's in the package?" + - tar -tvf dist/django-flickr-*tar.gz + - unzip -l dist/django_flickr-*whl + +test-py27: + image: python:2.7 + stage: test + script: + - tox -e $(tox -ls | grep py27 | sed -e 'N;s/\n/,/') diff --git a/requirements_test.txt b/requirements_test.txt new file mode 100644 index 0000000..92ff2fa --- /dev/null +++ b/requirements_test.txt @@ -0,0 +1,4 @@ +pytest<4 +pytest-cov +django-test-plus==1.0.15 +pytest-django<3.0 diff --git a/setup.cfg b/setup.cfg new file mode 100644 index 0000000..5b6c94f --- /dev/null +++ b/setup.cfg @@ -0,0 +1,13 @@ +[coverage:run] +source = flickr + +[coverage:report] +omit = + */migrations/* + +[tool:pytest] +DJANGO_SETTINGS_MODULE = example.settings +django_find_project = false +python_paths = . +python_files = tests.py test_*.py *_tests.py +norecursedirs = build dist docs *.egg-info htmlcov diff --git a/tox.ini b/tox.ini new file mode 100644 index 0000000..c21a155 --- /dev/null +++ b/tox.ini @@ -0,0 +1,26 @@ +[tox] +envlist = py27-django14 + +[testenv] +setenv = + PYTHONPATH = {toxinidir} +commands = pytest --cov --cov-report=term-missing +deps = + django14: Django>=1.4,<1.5 + django15: Django>=1.5,<1.6 + django16: Django>=1.6,<1.7 + django17: Django>=1.7,<1.8 + django18: Django>=1.8,<1.9 + django19: Django>=1.9,<1.10 + django110: Django>=1.10,<1.11 + django111: Django>=1.11,<2.0 + django20: Django>=2.0,<2.1 + django21: Django>=2.1,<2.2 + django22: Django>=2.2,<2.3 + -r req.pip + -r requirements_test.txt +basepython = + py37: python3.7 + py36: python3.6 + py35: python3.5 + py27: python2.7 From f8a489da85ccbdf4a7bf80843f2fffd0e42430e4 Mon Sep 17 00:00:00 2001 From: Gert Van Gool Date: Sat, 17 Aug 2019 13:16:11 +0200 Subject: [PATCH 04/11] Test tzoffset (add timezone info to test data) --- flickr/tests.py | 1 + flickr/tests_data.py | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/flickr/tests.py b/flickr/tests.py index 2234013..2a12cb3 100644 --- a/flickr/tests.py +++ b/flickr/tests.py @@ -38,6 +38,7 @@ def test_user(self): self.assertEqual(fu.iconfarm, json_user['person']['iconfarm']) self.assertEqual(fu.path_alias, json_user['person']['path_alias']) self.assertEqual(fu.profileurl, json_user['person']['profileurl']['_content'].replace('\\/', '/')) + self.assertEqual(fu.tzoffset, json_user['person']['timezone']['offset']) def test_photo_create(self): json_info = json_photos_extras['photos']['photo'][0] diff --git a/flickr/tests_data.py b/flickr/tests_data.py index ce6829c..e8db2c1 100644 --- a/flickr/tests_data.py +++ b/flickr/tests_data.py @@ -105,7 +105,8 @@ "username": { "_content": "zalew" }, "realname": { "_content": "jakub zalewski" }, "mbox_sha1sum": { "_content": "xxxxxxxx" }, - "location": { "_content": "" }, + "location": { "_content": "Belgium" }, + "timezone": { "timezone_id": "Europe/Brussels", "offset": "+01:00", "label": "Brussels, Copenhagen, Madrid, Paris"}, "photosurl": { "_content": "http:\/\/www.flickr.com\/photos\/zalew\/" }, "profileurl": { "_content": "http:\/\/www.flickr.com\/people\/zalew\/" }, "mobileurl": { "_content": "http:\/\/m.flickr.com\/photostream.gne?id=2306806" }, From 4d852a710254a250ef1ecb18d4b60be2ef068f17 Mon Sep 17 00:00:00 2001 From: Gert Van Gool Date: Sat, 17 Aug 2019 14:02:56 +0200 Subject: [PATCH 05/11] Handle tzoffset is None --- flickr/models.py | 4 ++-- flickr/utils.py | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/flickr/models.py b/flickr/models.py index bac7beb..723f2d4 100644 --- a/flickr/models.py +++ b/flickr/models.py @@ -141,7 +141,7 @@ def _prepare_data(self, photo, flickr_user, info=None, exif=None, geo=None, **kw 'title': info_bunch.title._content, 'description': info_bunch.description._content, 'date_posted': ts_to_dt(info_bunch.dates.posted, flickr_user.tzoffset), - 'date_taken': '%s%s' % (info_bunch.dates.taken, flickr_user.tzoffset), + 'date_taken': '%s%s' % (info_bunch.dates.taken, flickr_user.tzoffset or ""), 'date_taken_granularity': info_bunch.dates.takengranularity, 'date_updated': ts_to_dt(info_bunch.dates.lastupdate, flickr_user.tzoffset), 'tags': info_bunch.tags.tag, @@ -174,7 +174,7 @@ def _prepare_data(self, photo, flickr_user, info=None, exif=None, geo=None, **kw 'license': photo_bunch.license, } if photo_info['date_taken']: - photo_info['date_taken'] = '%s%s' % (photo_info['date_taken'], flickr_user.tzoffset) + photo_info['date_taken'] = '%s%s' % (photo_info['date_taken'], flickr_user.tzoffset or "") photo_data.update(photo_info) diff --git a/flickr/utils.py b/flickr/utils.py index ed6f9ff..b265479 100755 --- a/flickr/utils.py +++ b/flickr/utils.py @@ -2,6 +2,8 @@ def ts_to_dt(timestamp, offset=''): + if offset is None: + offset = "" return '%s%s' % (datetime.fromtimestamp(int(timestamp)).strftime('%Y-%m-%d %H:%M:%S'), offset) From bc770e7550183db4fcb410587edc0316ed9a105e Mon Sep 17 00:00:00 2001 From: Gert Van Gool Date: Sat, 17 Aug 2019 14:03:23 +0200 Subject: [PATCH 06/11] Photo's update_from_manager needs flickr_user as first argument --- flickr/tests.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/flickr/tests.py b/flickr/tests.py index 2a12cb3..3be0dfe 100644 --- a/flickr/tests.py +++ b/flickr/tests.py @@ -74,7 +74,7 @@ def test_photo_update(self): new_title = 'whoa that is a new title here' json_info['title'] = new_title self.assertNotEqual(photo.title, json_info['title']) - Photo.objects.update_from_json(flickr_id=photo.flickr_id, photo=json_info, sizes=json_sizes, exif=json_exif) + Photo.objects.update_from_json(self.flickr_user, flickr_id=photo.flickr_id, photo=json_info, sizes=json_sizes, exif=json_exif) obj = Photo.objects.get(flickr_id=photo.flickr_id) self.assertEqual(obj.title, new_title) @@ -125,7 +125,7 @@ def test_dynamic_sizes(self): for size in size_bunch: self.assertEqual(unslash(size.source), getattr(photo, FLICKR_PHOTO_SIZES[size.label]['label']).source) self.assertEqual(unslash(size.url), getattr(photo, FLICKR_PHOTO_SIZES[size.label]['label']).url) - Photo.objects.update_from_json(flickr_id=photo.flickr_id, photo=json_info_photo, info=json_info, sizes=json_sizes, exif=json_exif) + Photo.objects.update_from_json(self.flickr_user, flickr_id=photo.flickr_id, photo=json_info_photo, info=json_info, sizes=json_sizes, exif=json_exif) photo = Photo.objects.get(flickr_id=photo.flickr_id) self.assertEqual(photo.square_source, photo.square.source) self.assertEqual(photo.thumb_source, photo.thumb.source) @@ -147,7 +147,7 @@ def test_dynamic_sizes_dbhits(self): for size in size_bunch: self.assertEqual(unslash(size.source), getattr(photo, FLICKR_PHOTO_SIZES[size.label]['label']).source) self.assertEqual(unslash(size.url), getattr(photo, FLICKR_PHOTO_SIZES[size.label]['label']).url) - Photo.objects.update_from_json(flickr_id=photo.flickr_id, photo=json_info, sizes=json_sizes, exif=json_exif) + Photo.objects.update_from_json(self.flickr_user, flickr_id=photo.flickr_id, photo=json_info, sizes=json_sizes, exif=json_exif) photo = Photo.objects.get(flickr_id=photo.flickr_id) with self.assertNumQueries(1): size_bunch = bunchify(json_sizes['sizes']['size']) From c0acae340122ab0f34b7a37c08625b3c828d7611 Mon Sep 17 00:00:00 2001 From: Gert Van Gool Date: Sat, 17 Aug 2019 14:08:20 +0200 Subject: [PATCH 07/11] Collection's _prepare_data take arguments in different order --- flickr/models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/flickr/models.py b/flickr/models.py index 723f2d4..69ece6d 100644 --- a/flickr/models.py +++ b/flickr/models.py @@ -689,7 +689,7 @@ def _prepare_data(self, info, flickr_user, parent=None): return data def create_obj(self, info, parent=None, flickr_user=None, **kwargs): - data = self._prepare_data(info, parent, flickr_user) + data = self._prepare_data(info, parent=parent, flickr_user=flickr_user) sets_data = cols_data = None if 'sets' in data.keys(): sets_data = data.pop('sets') From 857884fbce3954db296049ac9ca357d58f24789b Mon Sep 17 00:00:00 2001 From: Gert Van Gool Date: Sat, 17 Aug 2019 15:23:54 +0200 Subject: [PATCH 08/11] Adds tests for views --- flickr/templatetags/flickr_tags.py | 2 +- flickr/tests.py | 41 ++++++++++++++++++++++++++++++ 2 files changed, 42 insertions(+), 1 deletion(-) diff --git a/flickr/templatetags/flickr_tags.py b/flickr/templatetags/flickr_tags.py index 4fbddc3..c552a80 100644 --- a/flickr/templatetags/flickr_tags.py +++ b/flickr/templatetags/flickr_tags.py @@ -9,7 +9,7 @@ def flickr_photo(photo, size='medium', flickr_link=False): if not photo: return {} - if size == 'large' and photo.date_posted <= datetime.datetime(2010, 05, 25): + if size == 'large' and photo.date_posted.date() <= datetime.date(2010, 05, 25): if photo.user.ispro: size = 'ori' else: diff --git a/flickr/tests.py b/flickr/tests.py index 3be0dfe..dcd22b5 100644 --- a/flickr/tests.py +++ b/flickr/tests.py @@ -3,8 +3,11 @@ from bunch import bunchify from datetime import datetime from django.contrib.auth.models import User +from django.core.urlresolvers import reverse +from django.template.base import TemplateDoesNotExist from django.test import TestCase from django.test.client import Client +from django.test.utils import override_settings from flickr.flickr_spec import FLICKR_PHOTO_SIZES from flickr.models import FlickrUser, Photo, PhotoSet, Collection from flickr.tests_data import json_user, json_sizes, json_exif, json_geo, json_info, \ @@ -154,3 +157,41 @@ def test_dynamic_sizes_dbhits(self): for size in size_bunch: self.assertEqual(unslash(size.source), getattr(photo, FLICKR_PHOTO_SIZES[size.label]['label']).source) self.assertEqual(unslash(size.url), getattr(photo, FLICKR_PHOTO_SIZES[size.label]['label']).url) + + @override_settings(ROOT_URLCONF='flickr.urls') + def test_views_index(self): + response = self.client.get(reverse('flickr_index')) + self.assertEquals(response.status_code, 200) + self.assertTrue("flickr/index.html" in [tmpl.name for tmpl in response.templates]) + + @override_settings(ROOT_URLCONF='flickr.urls') + def test_views_photo_invalid(self): + with self.assertRaises(TemplateDoesNotExist) as exc_info: + self.client.get(reverse('flickr_photo', kwargs={'flickr_id': 99999})) + self.assertEquals(str(exc_info.exception), "404.html") + with self.assertRaises(ValueError) as exc_info: + self.client.get(reverse('flickr_photo', kwargs={'flickr_id': "random"})) + + @override_settings(ROOT_URLCONF='flickr.urls') + def test_views_photo(self): + json_info = json_photos_extras['photos']['photo'][0] + FlickrUser.objects.update_from_json(self.flickr_user.id, json_user) + flickr_user = FlickrUser.objects.get(flickr_id=json_user['person']['id']) + photo = Photo.objects.create_from_json(flickr_user=flickr_user, photo=json_info, sizes=None, exif=json_exif) + + response = self.client.get(reverse('flickr_photo', kwargs={'flickr_id': photo.flickr_id})) + self.assertEquals(response.status_code, 200) + self.assertTrue("flickr/photo_page.html" in [tmpl.name for tmpl in response.templates]) + self.assertTrue(photo.title in response.content) + + @override_settings(ROOT_URLCONF='flickr.urls') + def test_views_photoset(self): + json_info = json_photos_extras['photos']['photo'][0] + photo = Photo.objects.create_from_json(flickr_user=self.flickr_user, photo=json_info, sizes=json_sizes, exif=json_exif) + photoset = PhotoSet.objects.create_from_json(flickr_user=self.flickr_user, info=json_set_info['photoset'], photos=json_set_photos) + + response = self.client.get(reverse('flickr_photoset', kwargs={'flickr_id': photoset.flickr_id})) + self.assertEquals(response.status_code, 200) + self.assertTrue("flickr/index.html" in [tmpl.name for tmpl in response.templates]) + self.assertTrue(photoset.title in response.content) + self.assertTrue(photo.description in response.content) From ebaf5cf166af89a6c19436f57b23ec425d3dd9d6 Mon Sep 17 00:00:00 2001 From: Gert Van Gool Date: Sat, 17 Aug 2019 15:31:31 +0200 Subject: [PATCH 09/11] Import all files that are not touched during tests --- flickr/tests.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/flickr/tests.py b/flickr/tests.py index dcd22b5..644e13f 100644 --- a/flickr/tests.py +++ b/flickr/tests.py @@ -195,3 +195,8 @@ def test_views_photoset(self): self.assertTrue("flickr/index.html" in [tmpl.name for tmpl in response.templates]) self.assertTrue(photoset.title in response.content) self.assertTrue(photo.description in response.content) + + def test_imports(self): + import flickr.admin + import flickr.management.commands.flickr_download + import flickr.management.commands.flickr_sync From d560dba9dee1eead7c58e9f21f88d9f720a5863c Mon Sep 17 00:00:00 2001 From: Gert Van Gool Date: Sat, 17 Aug 2019 16:25:34 +0200 Subject: [PATCH 10/11] django-flickr 0.3.6 CHANGES - Fixed tests - Converting tzoffset from None to "" - Fixed creating collections - Fixed the templatetag (timezone-aware datetime comparisons) --- flickr/__init__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/flickr/__init__.py b/flickr/__init__.py index 5b00bc1..eaef223 100644 --- a/flickr/__init__.py +++ b/flickr/__init__.py @@ -1,2 +1,2 @@ -VERSION = (0, 3, 5) -DEV_STATUS = '3 - Alpha' +VERSION = (0, 3, 6) +DEV_STATUS = '4 - Beta' From f3d8adccfe8842d392e765a8e3c6d99e1fb1c99d Mon Sep 17 00:00:00 2001 From: Gert Van Gool Date: Sat, 31 Aug 2019 12:02:00 +0200 Subject: [PATCH 11/11] Adds GitHub Actions for running tests --- .github/workflows/main.yml | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 .github/workflows/main.yml diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml new file mode 100644 index 0000000..d744bca --- /dev/null +++ b/.github/workflows/main.yml @@ -0,0 +1,22 @@ +name: CI + +on: [push] + +jobs: + test: + runs-on: ubuntu-latest + strategy: + matrix: + python: [ '2.7' ] + name: Python ${{ matrix.python }} tests + steps: + - uses: actions/checkout@master + - name: Setup python + uses: actions/setup-python@v1 + with: + python-version: ${{ matrix.python }} + architecture: x64 + - name: Running tox + run: | + python -m pip install tox + tox -e $(tox -ls | grep py$(echo ${{ matrix.python }} | sed 's/\.//') | sed ':1;N;s/\n/,/;t1')