Skip to content

Commit

Permalink
[change] Enable python 3.7 compatibility (Flexget#2225)
Browse files Browse the repository at this point in the history
* Added python 3.7 to test matrix

* Updated required requirements

* updated to latest ubuntu image

* Fix re.sub usage for python 3.7

* Update requirements.in for python 3.7

* Workaround rtorrent test on python 3.7

* Use raw strings with regexps (previously DeprecationWarning)

* Version bump due to possible config changes needed
  • Loading branch information
gazpachoking authored Jan 6, 2019
1 parent 21f6032 commit aa014b8
Show file tree
Hide file tree
Showing 15 changed files with 71 additions and 33 deletions.
21 changes: 21 additions & 0 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,24 @@ jobs:
command: |
.circleci/coverage.sh
test-py37:
docker:
- image: flexget/cci-python:3.7
environment:
- VCR_RECORD_MODE=none
steps:
- checkout
- restore_cache:
keys:
- py3.7-deps-{{ checksum "requirements.txt" }}{{ checksum "dev-requirements.txt" }}{{ checksum "dev-requirements-extras.txt" }}
- py3.7-deps- # fallback to using the latest cache if no exact match is found
- run: *install_deps
- save_cache:
paths:
- ./venv
key: py3.7-deps-{{ checksum "requirements.txt" }}{{ checksum "dev-requirements.txt" }}{{ checksum "dev-requirements-extras.txt" }}
- run: *run_tests

deploy:
docker:
- image: flexget/cci-python:3.5
Expand Down Expand Up @@ -133,6 +151,7 @@ workflows:
- "test-py34"
- "test-py35"
- "test-py36"
- "test-py37"

auto-build-test-and-deploy:
triggers:
Expand All @@ -147,12 +166,14 @@ workflows:
- "test-py34"
- "test-py35"
- "test-py36"
- "test-py37"
- deploy:
requires:
- "test-py27"
- "test-py34"
- "test-py35"
- "test-py36"
- "test-py37"

notify:
webhooks:
Expand Down
2 changes: 1 addition & 1 deletion .circleci/images/python27/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
FROM circleci/python:2.7

# Install extra repos
RUN sudo sed -i 's/debian jessie main$/debian jessie main contrib non-free/' /etc/apt/sources.list
RUN sudo sed -i 's/debian stretch main$/debian stretch main contrib non-free/' /etc/apt/sources.list

# Install unrar used by some flexget tests
RUN sudo apt-get update; sudo apt-get install -qy unrar
Expand Down
2 changes: 1 addition & 1 deletion .circleci/images/python33/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
FROM circleci/python:3.3

# Install extra repos
RUN sudo sed -i 's/debian jessie main$/debian jessie main contrib non-free/' /etc/apt/sources.list
RUN sudo sed -i 's/debian stretch main$/debian stretch main contrib non-free/' /etc/apt/sources.list

# Install unrar used by some flexget tests
RUN sudo apt-get update; sudo apt-get install -qy unrar
Expand Down
2 changes: 1 addition & 1 deletion .circleci/images/python34/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
FROM circleci/python:3.4

# Install extra repos
RUN sudo sed -i 's/debian jessie main$/debian jessie main contrib non-free/' /etc/apt/sources.list
RUN sudo sed -i 's/debian stretch main$/debian stretch main contrib non-free/' /etc/apt/sources.list

# Install unrar used by some flexget tests
RUN sudo apt-get update; sudo apt-get install -qy unrar
Expand Down
2 changes: 1 addition & 1 deletion .circleci/images/python35/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
FROM circleci/python:3.5

# Install extra repos
RUN sudo sed -i 's/debian jessie main$/debian jessie main contrib non-free/' /etc/apt/sources.list
RUN sudo sed -i 's/debian stretch main$/debian stretch main contrib non-free/' /etc/apt/sources.list

# Install unrar used by some flexget tests
RUN sudo apt-get update; sudo apt-get install -qy unrar
Expand Down
2 changes: 1 addition & 1 deletion .circleci/images/python36/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
FROM circleci/python:3.6

# Install extra repos
RUN sudo sed -i 's/debian jessie main$/debian jessie main contrib non-free/' /etc/apt/sources.list
RUN sudo sed -i 's/debian stretch main$/debian stretch main contrib non-free/' /etc/apt/sources.list

# Install unrar used by some flexget tests
RUN sudo apt-get update; sudo apt-get install -qy unrar
Expand Down
10 changes: 10 additions & 0 deletions .circleci/images/python37/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
FROM circleci/python:3.7

# Install extra repos
RUN sudo sed -i 's/debian stretch main$/debian stretch main contrib non-free/' /etc/apt/sources.list

# Install unrar used by some flexget tests
RUN sudo apt-get update; sudo apt-get install -qy unrar

# Use virtualenv as we test on py2.7, keeps it consistant
RUN sudo pip install virtualenv
2 changes: 1 addition & 1 deletion flexget/_version.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,4 @@
The jenkins release job will automatically strip the .dev for release,
and update the version again for continued development.
"""
__version__ = '2.17.26.dev'
__version__ = '2.18.0.dev'
1 change: 1 addition & 0 deletions flexget/plugins/clients/rtorrent.py
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,7 @@ def load(self, raw_torrent, fields=None, start=False, mkdir=True):
# Additional fields to set
for key, val in fields.items():
# Values must be escaped if within params
# TODO: What are the escaping requirements? re.escape works differently on python 3.7+
params.append('d.%s.set=%s' % (key, re.escape(native_str(val))))

if mkdir and 'directory' in fields:
Expand Down
3 changes: 2 additions & 1 deletion flexget/plugins/parsers/parser_common.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,8 @@ def name_to_re(name, ignore_prefixes=None, parser=None):
res = res.strip()
# accept either '&' or 'and'
res = re.sub(' (&|and) ', ' (?:and|&) ', res, re.UNICODE)
res = re.sub(' +', blank + '*', res, re.UNICODE)
# The replacement has a regex escape in it (\w) which needs to be escaped again in python 3.7+
res = re.sub(' +', blank.replace('\\', '\\\\') + '*', res, re.UNICODE)
if parenthetical:
res += '(?:' + blank + '+' + parenthetical + ')?'
# Turn on exact mode for series ending with a parenthetical,
Expand Down
4 changes: 2 additions & 2 deletions flexget/tests/test_regexp_list.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@


class TestRegexpList(object):
config = """
config = r"""
tasks:
regexp_list_add:
mock:
Expand All @@ -25,7 +25,7 @@ class TestRegexpList(object):
- title:
replace:
regexp: '$'
format: ' s\d{2}e\d{2}'
format: ' s\\d{2}e\\d{2}'
- title:
replace:
regexp: ' '
Expand Down
6 changes: 5 additions & 1 deletion flexget/tests/test_rtorrent.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
from future.moves.xmlrpc import client as xmlrpc_client

import os
import re

import mock

Expand Down Expand Up @@ -67,7 +68,10 @@ def test_load(self, mocked_proxy):

fields = [p for p in called_args[2:]]
assert len(fields) == 3
assert 'd.directory.set=\\/data\\/downloads' in fields
# TODO: check the note in clients/rtorrent.py about this escaping.
# The client should be fixed to work consistenly on all python versions
# Calling re.escape here is a workaround so test works on python 3.7 and older versions
assert ('d.directory.set=' + re.escape('/data/downloads')) in fields
assert 'd.custom1.set=testing' in fields
assert 'd.priority.set=3' in fields

Expand Down
42 changes: 21 additions & 21 deletions flexget/utils/titles/series.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,36 +41,36 @@ class SeriesParser(TitleParser):

# Make sure none of these are found embedded within a word or other numbers
ep_regexps = ReList([TitleParser.re_not_in_word(regexp) for regexp in [
'(?:series|season|s)\s?(\d{1,4})(?:\s(?:.*\s)?)?(?:episode|ep|e|part|pt)\s?(\d{1,3}|%s)(?:\s?e?(\d{1,2}))?' %
r'(?:series|season|s)\s?(\d{1,4})(?:\s(?:.*\s)?)?(?:episode|ep|e|part|pt)\s?(\d{1,3}|%s)(?:\s?e?(\d{1,2}))?' %
roman_numeral_re,
'(?:series|season)\s?(\d{1,4})\s(\d{1,3})\s?of\s?(?:\d{1,3})',
'(\d{1,2})\s?x\s?(\d+)(?:\s(\d{1,2}))?',
'(\d{1,3})\s?of\s?(?:\d{1,3})',
'(?:episode|e|ep|part|pt)\s?(\d{1,3}|%s)' % roman_numeral_re,
'part\s(%s)' % '|'.join(map(str, english_numbers)),
r'(?:series|season)\s?(\d{1,4})\s(\d{1,3})\s?of\s?(?:\d{1,3})',
r'(\d{1,2})\s?x\s?(\d+)(?:\s(\d{1,2}))?',
r'(\d{1,3})\s?of\s?(?:\d{1,3})',
r'(?:episode|e|ep|part|pt)\s?(\d{1,3}|%s)' % roman_numeral_re,
r'part\s(%s)' % '|'.join(map(str, english_numbers)),
]])
season_pack_regexps = ReList([
# S01 or Season 1 but not Season 1 Episode|Part 2
r'(?:season\s?|s)(\d{1,})(?:\s|$)(?!(?:(?:.*?\s)?(?:episode|e|ep|part|pt)\s?(?:\d{1,3}|%s)|(?:\d{1,3})\s?of\s?(?:\d{1,3})))' % roman_numeral_re,
'(\d{1,3})\s?x\s?all', # 1xAll
r'(\d{1,3})\s?x\s?all', # 1xAll
])
unwanted_regexps = ReList([
'(\d{1,3})\s?x\s?(0+)[^1-9]', # 5x0
'S(\d{1,3})D(\d{1,3})', # S3D1
r'(\d{1,3})\s?x\s?(0+)[^1-9]', # 5x0
r'S(\d{1,3})D(\d{1,3})', # S3D1
r'(?:s|series|\b)\s?\d\s?(?:&\s?\d)?[\s-]*(?:complete|full)',
'disc\s\d'])
r'disc\s\d'])
# Make sure none of these are found embedded within a word or other numbers
date_regexps = ReList([TitleParser.re_not_in_word(regexp) for regexp in [
'(\d{2,4})%s(\d{1,2})%s(\d{1,2})' % (separators, separators),
'(\d{1,2})%s(\d{1,2})%s(\d{2,4})' % (separators, separators),
'(\d{4})x(\d{1,2})%s(\d{1,2})' % separators,
'(\d{1,2})(?:st|nd|rd|th)?%s([a-z]{3,10})%s(\d{4})' % (separators, separators)]])
r'(\d{2,4})%s(\d{1,2})%s(\d{1,2})' % (separators, separators),
r'(\d{1,2})%s(\d{1,2})%s(\d{2,4})' % (separators, separators),
r'(\d{4})x(\d{1,2})%s(\d{1,2})' % separators,
r'(\d{1,2})(?:st|nd|rd|th)?%s([a-z]{3,10})%s(\d{4})' % (separators, separators)]])
sequence_regexps = ReList([TitleParser.re_not_in_word(regexp) for regexp in [
'(\d{1,3})(?:v(?P<version>\d))?',
'(?:pt|part)\s?(\d+|%s)' % roman_numeral_re]])
unwanted_sequence_regexps = ReList(['seasons?\s?\d{1,2}'])
r'(\d{1,3})(?:v(?P<version>\d))?',
r'(?:pt|part)\s?(\d+|%s)' % roman_numeral_re]])
unwanted_sequence_regexps = ReList([r'seasons?\s?\d{1,2}'])
id_regexps = ReList([])
clean_regexps = ReList(['\[.*?\]', '\(.*?\)'])
clean_regexps = ReList([r'\[.*?\]', r'\(.*?\)'])
# ignore prefix regexps must be passive groups with 0 or 1 occurrences eg. (?:prefix)?
ignore_prefixes = default_ignore_prefixes

Expand Down Expand Up @@ -158,7 +158,7 @@ def guess_name(self):
"""This will attempt to guess a series name based on the provided data."""
# We need to replace certain characters with spaces to make sure episode parsing works right
# We don't remove anything, as the match positions should line up with the original title
clean_title = re.sub('[_.,\[\]\(\):]', ' ', self.data)
clean_title = re.sub(r'[_.,\[\]\(\):]', ' ', self.data)
if self.parse_unwanted(clean_title):
return
match = self.parse_date(clean_title)
Expand All @@ -183,7 +183,7 @@ def guess_name(self):
# Remove possible episode title from series name (anything after a ' - ')
name = name.split(' - ')[0]
# Replace some special characters with spaces
name = re.sub('[\._\(\) ]+', ' ', name).strip(' -')
name = re.sub(r'[\._\(\) ]+', ' ', name).strip(' -')
# Normalize capitalization to title case
name = capwords(name)
self.name = name
Expand Down Expand Up @@ -275,7 +275,7 @@ def parse(self, data=None, field=None, quality=None):
# Remove unwanted words from data for ep / id parsing
data_stripped = self.remove_words(data_stripped, self.remove, not_in_word=True)

data_parts = re.split('[\W_]+', data_stripped)
data_parts = re.split(r'[\W_]+', data_stripped)

for part in data_parts[:]:
if part in self.propers:
Expand Down
4 changes: 2 additions & 2 deletions requirements.in
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
FeedParser>=5.2.1
SQLAlchemy >=1.0.9, <1.999
PyYAML
PyYAML>=3.13
# Beautifulsoup 4.5+ is required to support different versions of html5lib
beautifulsoup4>=4.5
html5lib>=0.11
PyRSS2Gen
pynzb
#PY3 progressbar
rpyc==3.3.0
rpyc~=4.0
jinja2~=2.10
# There is a bug in requests 2.4.0 where it leaks urllib3 exceptions
requests>=2.20.0
Expand Down
1 change: 1 addition & 0 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ def load_requirements(filename):
"Programming Language :: Python :: 3.4",
"Programming Language :: Python :: 3.5",
"Programming Language :: Python :: 3.6",
"Programming Language :: Python :: 3.7",
"Programming Language :: Python :: Implementation :: CPython",
"Programming Language :: Python :: Implementation :: PyPy",
]
Expand Down

0 comments on commit aa014b8

Please sign in to comment.