Skip to content

Commit

Permalink
Added Python3 compatibility (#2)
Browse files Browse the repository at this point in the history
* Added Python3 compatibility
* Switched Coveralls for Codecov
  • Loading branch information
Dachaz authored Aug 8, 2020
1 parent 9d8740a commit e64199e
Show file tree
Hide file tree
Showing 13 changed files with 76 additions and 27 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ __MACOSX
.vscode
.coverage
.pytest_cache
.pybuilder
target/*
*.pyc
test/test-files
Expand Down
14 changes: 7 additions & 7 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
sudo: false
os: linux
dist: xenial
language: python
cache: pip

python:
- '2.7'

install:
- pip install coveralls pybuilder codacy-coverage
- "2.7"
- "3.7"

script:
- pyb

after_success:
- coveralls --verbose
- python-codacy-coverage -r ./target/reports/coverage.xml
- bash <(curl -s https://codecov.io/bash)
- python-codacy-coverage -r ./target/reports/scenery_coverage.xml
5 changes: 5 additions & 0 deletions CHANGELOG
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
1.0.1 / 2020-08-04
* Added support for Python3

1.0.0 / 2019-02-23
* Initial release
9 changes: 5 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
# Scenery

[![Build Status](https://travis-ci.org/Dachaz/scenery.svg?branch=master)](https://travis-ci.org/Dachaz/scenery)
[![Coverage Status](https://coveralls.io/repos/github/Dachaz/scenery/badge.svg?branch=master)](https://coveralls.io/github/Dachaz/scenery?branch=master)
[![Codacy Badge](https://api.codacy.com/project/badge/Grade/33d64d7332654e348c31498c954ba3a9)](https://www.codacy.com/app/Dachaz/scenery?utm_source=github.com&amp;utm_medium=referral&amp;utm_content=Dachaz/scenery&amp;utm_campaign=Badge_Grade)
[![codecov](https://codecov.io/gh/Dachaz/scenery/branch/master/graph/badge.svg)](https://codecov.io/gh/Dachaz/scenery)
[![Codacy Badge](https://api.codacy.com/project/badge/Grade/33d64d7332654e348c31498c954ba3a9)](https://www.codacy.com/app/Dachaz/scenery?utm_source=github.com&utm_medium=referral&utm_content=Dachaz/scenery&utm_campaign=Badge_Grade)
[![PyPI version](https://badge.fury.io/py/scenery.svg)](https://badge.fury.io/py/scenery)

A command-line tool that automates renaming of so-called "Scene Release" files by fetching episode names (from TVMaze) and which uses pattern-based generic building blocks (show name, season number, episode number, episode title) to format the output.
Expand Down Expand Up @@ -35,6 +35,7 @@ pip install scenery
⚠️ This will only install the command-line utility. You'll still have to ssh into the device to use it!

## Usage

```bash
usage: scenery [-h] [-p PATTERN] [-s] [-e] [-o] [-d] [-v] [-f] path

Expand Down Expand Up @@ -63,7 +64,7 @@ optional arguments:

## Developer notes

The project has been implemented in Python 2 to be compatible with a fairly outdated NAS that is running it.
The project has been implemented in Python 2 to be compatible with a fairly outdated NAS that is running it. Minimum effort has been done to make this project run on Python 3 (using [six](https://six.readthedocs.io)).

For the main part of the codebase, [PyBuilder](http://pybuilder.github.io) is used to do analysis (flake8, coverage), run the tests tests and bundle the package.

Expand All @@ -85,4 +86,4 @@ To understand the full building process of a My Cloud OS3 binary, please refer t

## License

Copyright © 2019 Dachaz. This software is licensed under the **MIT License**.
Copyright © 2019-2020 Dachaz. This software is licensed under the **MIT License**.
6 changes: 4 additions & 2 deletions build.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@
blocks (show name, season number, episode number, episode title) to format the output.
"""
url = 'https://github.com/dachaz/scenery'
version = '1.0.0'
equires_python = "=2.7"
version = '1.0.1'
requires_python = ">=2.7"

default_task = ["install_dependencies", "analyze", "publish"]

Expand All @@ -42,6 +42,8 @@ def initialize(project):
'Programming Language :: Python',
'Programming Language :: Python :: 2',
'Programming Language :: Python :: 2.7',
'Programming Language :: Python :: 3',
'Programming Language :: Python :: 3.7',
'Development Status :: 5 - Production/Stable',
'Environment :: Console',
'Intended Audience :: End Users/Desktop',
Expand Down
9 changes: 9 additions & 0 deletions build.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#!/bin/bash

# Python 2 build
docker build -t scenery-py2 -f py2.Dockerfile .
docker run scenery-py2

# Python 3 build
docker build -t scenery-py3 -f py3.Dockerfile .
docker run scenery-py3
10 changes: 10 additions & 0 deletions py2.Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
FROM python:2

COPY requirements.txt /tmp/
RUN pip install -r /tmp/requirements.txt

WORKDIR /usr/src/scenery

COPY ./ /usr/src/scenery

ENTRYPOINT pyb
10 changes: 10 additions & 0 deletions py3.Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
FROM python:3

COPY requirements.txt /tmp/
RUN pip install -r /tmp/requirements.txt

WORKDIR /usr/src/scenery

COPY ./ /usr/src/scenery

ENTRYPOINT pyb
3 changes: 3 additions & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
six
pybuilder
codacy-coverage
2 changes: 1 addition & 1 deletion src/scenery/MetadataTools.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ def generateFilename(sceneFile, pattern, zeroesSeason=False, zeroesEpisodes=Fals
}

out = pattern
for symbol, replacement in replacements.iteritems():
for symbol, replacement in replacements.items():
out = out.replace(symbol, replacement)

return out + extension
11 changes: 8 additions & 3 deletions src/scenery/TitleFetcher.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import json
import logging
import urllib2
import six
from six.moves.urllib.parse import quote
from scenery.model.SceneFileMetadata import SceneFileMetadata
from scenery.model.SceneFileMetadataCache import SceneFileMetadataCache

Expand All @@ -13,14 +14,18 @@ def getTitle(meta):
return cache.getTitle(meta)


def buildUrl(showName):
return TVMAZE_SEARCH_URL + quote(showName)


def fetchEpisodes(showName):
# Make sure to fetch from TVMaze only once per application run
if cache.hasShow(showName):
return

try:
url = TVMAZE_SEARCH_URL + showName
response = urllib2.urlopen(url)
url = buildUrl(showName)
response = six.moves.urllib.request.urlopen(url) # nosec The URL is guaranteed to be safe by buildUrl
data = json.loads(response.read())

# If the server decided to return no episode data, mark the show as unknown
Expand Down
3 changes: 3 additions & 0 deletions test/Scenery_tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ class SceneryTests(unittest.TestCase):
WORK_DIR = os.path.join(tempfile.gettempdir(), 'scenery-test-files')
TEST_ROOT = os.path.dirname(__file__)

# assertItemsEqual got renamed to assertCountEqual in py3
assertItemsEqual = unittest.TestCase.assertItemsEqual if hasattr(unittest.TestCase, 'assertItemsEqual') else unittest.TestCase.assertCountEqual

def setUp(self):
# In case an earlier run ended abruptly, clean up
if os.path.exists(self.WORK_DIR):
Expand Down
20 changes: 10 additions & 10 deletions test/TitleFetcher_tests.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
from mockito import when, mock, unstub, verify, ANY, ARGS
from scenery.TitleFetcher import getTitle, fetchEpisodes, TVMAZE_SEARCH_URL, cache
from scenery.TitleFetcher import getTitle, fetchEpisodes, buildUrl, cache
from scenery.model.SceneFileMetadata import SceneFileMetadata
import logging
import unittest
import urllib2
import six
import os


Expand All @@ -18,19 +18,19 @@ def setUp(self):
bobData = open(os.path.join(testRoot, 'test-assets', '107.json')).read()
self.bobResponse = mock()
when(self.bobResponse).read().thenReturn(bobData)
bobUrl1 = TVMAZE_SEARCH_URL + 'Bobs Burgers'
bobUrl2 = TVMAZE_SEARCH_URL + "Bob's Burgers"
when(urllib2).urlopen(bobUrl1).thenReturn(self.bobResponse)
when(urllib2).urlopen(bobUrl2).thenReturn(self.bobResponse)
bobUrl1 = buildUrl('Bobs Burgers')
bobUrl2 = buildUrl("Bob's Burgers")
when(six.moves.urllib.request).urlopen(bobUrl1).thenReturn(self.bobResponse)
when(six.moves.urllib.request).urlopen(bobUrl2).thenReturn(self.bobResponse)

# Mock 2: The endpoint returns only show info
xfData = open(os.path.join(testRoot, 'test-assets', '430.json')).read()
self.xfResponse = mock()
when(self.xfResponse).read().thenReturn(xfData)
xfUrl1 = TVMAZE_SEARCH_URL + 'The X-Files'
xfUrl2 = TVMAZE_SEARCH_URL + 'The X Files'
when(urllib2).urlopen(xfUrl1).thenReturn(self.xfResponse)
when(urllib2).urlopen(xfUrl2).thenReturn(self.xfResponse)
xfUrl1 = buildUrl('The X-Files')
xfUrl2 = buildUrl('The X Files')
when(six.moves.urllib.request).urlopen(xfUrl1).thenReturn(self.xfResponse)
when(six.moves.urllib.request).urlopen(xfUrl2).thenReturn(self.xfResponse)

def test_only_one_request_is_sent_to_server_for_shows_with_similar_names(self):
fetchEpisodes('Bobs Burgers')
Expand Down

0 comments on commit e64199e

Please sign in to comment.