Repository: coralnet/pyspacer (language: python)

Issue:
Switch from Travis CI to GitHub Actions
Same deal as here: https://github.com/beijbom/coralnet/issues/392

Although we can't exactly copy the way CoralNet does it, since Spacer isn't a Django project.


Discussion / hints:

Fix patch:
diff --git a/.github/workflows/python-app.yml b/.github/workflows/python-app.yml
new file mode 100644
index 00000000..115aeabc
--- /dev/null
+++ b/.github/workflows/python-app.yml
@@ -0,0 +1,32 @@
+name: Python application
+
+on:
+  push:
+    branches: [ master ]
+  pull_request:
+    branches: [ master ]
+
+jobs:
+  build:
+
+    runs-on: ubuntu-latest
+    strategy:
+      matrix:
+        python-version: [3.6, 3.7, 3.8]
+
+    steps:
+    - uses: actions/checkout@v2
+    - name: Set up Python ${{ matrix.python-version }}
+      uses: actions/setup-python@v2
+      with:
+        python-version: ${{ matrix.python-version }}
+    - name: Install dependencies
+      run: |
+        python -m pip install --upgrade pip
+        pip install -r requirements.txt
+    - name: Make directories
+      run: |
+        mkdir ../models
+    - name: Run tests
+      run: |
+        python -m unittest
diff --git a/.travis.yml b/.travis.yml
deleted file mode 100644
index f21d7839..00000000
--- a/.travis.yml
+++ /dev/null
@@ -1,16 +0,0 @@
-language: python
-
-python:
-  - "3.5"
-  - "3.6"
-  - "3.7"
-  - "3.8"
-
-install:
-  - pip install -r requirements.txt
-
-before_script:
-  - mkdir ../models
-
-script:
-  - python -m unittest
diff --git a/Dockerfile b/Dockerfile
index 7419b0ad..0f5cd21d 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -78,7 +78,7 @@ RUN pip3 install fire==0.2.1
 RUN pip3 install Pillow==6.2.0
 RUN pip3 install numpy==1.18.1
 RUN pip3 install scikit-learn==0.22.1
-RUN pip3 install scikit-image==0.15.0
+RUN pip3 install scikit-image==0.17.2
 RUN pip3 install torchvision==0.9.0
 RUN pip3 install torch==1.8.0
 RUN pip3 install boto3==1.15.8
diff --git a/README.md b/README.md
index fce84e9b..8659f6f0 100644
--- a/README.md
+++ b/README.md
@@ -1,13 +1,13 @@
 # PySpacer
 
-[![Build Status](https://travis-ci.com/beijbom/pyspacer.svg?branch=master)](https://travis-ci.com/beijbom/pyspacer)
+[![CI Status](https://github.com/beijbom/pyspacer/actions/workflows/python-app.yml/badge.svg)](https://github.com/beijbom/pyspacer/actions/workflows/python-app.yml)
 [![PyPI version](https://badge.fury.io/py/pyspacer.svg)](https://badge.fury.io/py/pyspacer)
 
 This repository provide utilities to extract features from random point 
 locations in images and then training classifiers over those features.
 It is used in the vision backend of `https://github.com/beijbom/coralnet`.
 
-Spacer currently supports python >=3.5.
+Spacer currently supports python >=3.6.
 
 ### Overview
 Spacer executes tasks as defined in messages. The messages types are defined
diff --git a/requirements.txt b/requirements.txt
index 0067e9e5..7c12876e 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -6,7 +6,7 @@ Pillow==6.2.2
 numpy==1.18.1
 scipy==1.4.1
 scikit-learn==0.22.1
-scikit-image==0.15.0
+scikit-image==0.17.2
 torch==1.4.0
 torchvision==0.5.0
 boto3==1.15.8
diff --git a/setup.py b/setup.py
index 45717799..cf930d1f 100644
--- a/setup.py
+++ b/setup.py
@@ -19,18 +19,18 @@
                                                'spacer.tests',
                                                'spacer.tests.*']),
     classifiers=[
-        "Programming Language :: Python :: 3.5",
+        "Programming Language :: Python :: 3.6",
         "License :: OSI Approved :: MIT License",
         "Operating System :: OS Independent",
     ],
-    python_requires='>=3.5',
+    python_requires='>=3.6',
     install_requires=[
         'wget==3.2',
         'tqdm==4.43.0',
         'Pillow>=4.2.0',
         'numpy>=1.17.5',
         'scikit-learn==0.22.1',
-        'scikit-image==0.15.0',
+        'scikit-image==0.17.2',
         'torch==1.4.0',
         'torchvision==0.5.0',
         'boto3',


Test patch:
diff --git a/spacer/tests/test_mailman.py b/spacer/tests/test_mailman.py
index e29fce96..f2bcb4bb 100644
--- a/spacer/tests/test_mailman.py
+++ b/spacer/tests/test_mailman.py
@@ -12,16 +12,19 @@
     DataLocation, \
     ImageLabels
 
+TEST_URL = \
+    'https://upload.wikimedia.org/wikipedia/commons/7/7b/Red_sea_coral_reef.jpg'
+TEST_URL_FILENAME = 'Red_sea_coral_reef.jpg'
+
 
 class TestProcessJobErrorHandling(unittest.TestCase):
 
     def setUp(self):
         config.filter_warnings()
-        self.url = 'https://homepages.cae.wisc.edu/~ece533/images/baboon.png'
 
     def tearDown(self):
-        if os.path.exists('baboon.png'):
-            os.remove('baboon.png')
+        if os.path.exists(TEST_URL_FILENAME):
+            os.remove(TEST_URL_FILENAME)
 
     def test_input_type(self):
         self.assertRaises(AssertionError, process_job, 'sdf')
@@ -69,7 +72,7 @@ def test_img_classify_feature_extractor_name(self):
                      tasks=[ClassifyImageMsg(
                          job_token='my_job',
                          image_loc=DataLocation(storage_type='url',
-                                                key=self.url),
+                                                key=TEST_URL),
                          feature_extractor_name='invalid_name',
                          rowcols=[(1, 1)],
                          classifier_loc=DataLocation(storage_type='memory',
@@ -87,7 +90,7 @@ def test_img_classify_classifier_key(self):
                      tasks=[ClassifyImageMsg(
                          job_token='my_job',
                          image_loc=DataLocation(storage_type='url',
-                                                key=self.url),
+                                                key=TEST_URL),
                          feature_extractor_name='dummy',
                          rowcols=[(1, 1)],
                          classifier_loc=DataLocation(storage_type='memory',
@@ -136,11 +139,10 @@ class TestProcessJobMultiple(unittest.TestCase):
 
     def setUp(self):
         config.filter_warnings()
-        self.url = 'https://homepages.cae.wisc.edu/~ece533/images/baboon.png'
 
     def tearDown(self):
-        if os.path.exists('baboon.png'):
-            os.remove('baboon.png')
+        if os.path.exists(TEST_URL_FILENAME):
+            os.remove(TEST_URL_FILENAME)
 
     def test_multiple_feature_extract(self):
         extract_msg = ExtractFeaturesMsg(
@@ -148,7 +150,7 @@ def test_multiple_feature_extract(self):
             feature_extractor_name='dummy',
             rowcols=[(1, 1)],
             image_loc=DataLocation(storage_type='url',
-                                   key=self.url),
+                                   key=TEST_URL),
             feature_loc=DataLocation(storage_type='memory',
                                      key='my_feats'))
 
@@ -166,7 +168,7 @@ def test_multiple_feature_extract_one_fail(self):
             feature_extractor_name='dummy',
             rowcols=[(1, 1)],
             image_loc=DataLocation(storage_type='url',
-                                   key=self.url),
+                                   key=TEST_URL),
             feature_loc=DataLocation(storage_type='memory',
                                      key='my_feats'))
 
diff --git a/spacer/tests/test_tasks.py b/spacer/tests/test_tasks.py
index babb56bf..cabaa832 100644
--- a/spacer/tests/test_tasks.py
+++ b/spacer/tests/test_tasks.py
@@ -27,6 +27,9 @@
 from spacer.train_utils import make_random_data
 from spacer.train_utils import train
 
+TEST_URL = \
+    'https://upload.wikimedia.org/wikipedia/commons/7/7b/Red_sea_coral_reef.jpg'
+
 
 class TestImageAndPointLimitsAsserts(unittest.TestCase):
 
@@ -340,8 +343,7 @@ def test_deploy_simple(self):
         msg = ClassifyImageMsg(
             job_token='my_job',
             image_loc=DataLocation(storage_type='url',
-                                   key='https://homepages.cae.wisc.edu/~ece533'
-                                       '/images/baboon.png'),
+                                   key=TEST_URL),
             feature_extractor_name='dummy',
             rowcols=[(100, 100), (200, 200)],
             classifier_loc=DataLocation(storage_type='s3',
@@ -369,8 +371,7 @@ def test_classify_image_with_caching(self):
         msg = ClassifyImageMsg(
             job_token='my_job',
             image_loc=DataLocation(storage_type='url',
-                                   key='https://homepages.cae.wisc.edu/~ece533'
-                                       '/images/baboon.png'),
+                                   key=TEST_URL),
             feature_extractor_name='dummy',
             rowcols=[(100, 100), (200, 200)],
             classifier_loc=DataLocation(storage_type='s3',
@@ -381,8 +382,7 @@ def test_classify_image_with_caching(self):
         msg2 = ClassifyImageMsg(
             job_token='my_job',
             image_loc=DataLocation(storage_type='url',
-                                   key='https://homepages.cae.wisc.edu/~ece533'
-                                       '/images/baboon.png'),
+                                   key=TEST_URL),
             feature_extractor_name='dummy',
             rowcols=[(100, 100), (200, 200)],
             classifier_loc=DataLocation(storage_type='s3',
@@ -403,8 +403,7 @@ def test_image_classify(self):
         msg = ClassifyImageMsg(
             job_token='my_job',
             image_loc=DataLocation(storage_type='url',
-                                   key='https://homepages.cae.wisc.edu/~ece533'
-                                       '/images/baboon.png'),
+                                   key=TEST_URL),
             feature_extractor_name='dummy',
             rowcols=[(-1, -1)],
             classifier_loc=DataLocation(storage_type='s3',