Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Issue 415] Add support for python 3 #536

Merged
merged 6 commits into from
May 13, 2019
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 13 additions & 11 deletions .appveyor.yml
Original file line number Diff line number Diff line change
@@ -1,20 +1,22 @@
build: false

environment:
PYTHON: "C:\\Python27"
TOXENV: "py27"
matrix:
- PYTHON: "C:\\Python27"
PYTHON_VERSION: "2.7"
TOXENV: "py27"
- PYTHON: "C:\\Python36"
PYTHON_VERSION: "3.6"
TOXENV: "py36"
AndreiH marked this conversation as resolved.
Show resolved Hide resolved

init:
- ECHO %PYTHON%
- ECHO %TOXENV%
- SET PATH=%PYTHON%;%PYTHON%\\Scripts;%PATH%
- ECHO %PYTHON%
- ECHO %TOXENV%
- SET PATH=%PYTHON%;%PYTHON%\\Scripts;%PATH%

install:
- python -m pip install --upgrade pip
# Latest tox 2.3.x is currently busted:
# https://bitbucket.org/hpk42/tox/issues/314/tox-command-busted-on-windows
- pip install tox==2.2.0

- python -m pip install --upgrade pip
- pip install tox==3.7.0
AndreiH marked this conversation as resolved.
Show resolved Hide resolved

test_script:
- tox
- tox
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
.idea/
.cache/
.tox/
*.egg-info
*.pyc
.coverage
build
dist
36 changes: 21 additions & 15 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,29 +8,35 @@ language: python

matrix:
include:
- python: 2.7
- name: "Run test suite on Linux with Python 2.7"
os: linux
python: 2.7
env: TOXENV=py27
- python: 2.7
- name: "Run test suite on Linux with Python 3.6"
os: linux
python: 3.6
env: TOXENV=py36
- name: "Check code style with pylama on Linux - Python 3.6"
os: linux
python: 3.6
env: TOXENV=pylama
- language: generic
os: osx
# 7.2 is OS X 10.11.x
# 10.1 is OS X 10.13.x
# https://docs.travis-ci.com/user/languages/objective-c/#Supported-OS-X-iOS-SDK-versions
osx_image: xcode7.2
- name: "Run test suite on OS X with Python 2.7"
os: osx
osx_image: xcode10.1
language: generic
python: 2.7
env: TOXENV=py27
- name: "Run test suite on OS X with Python 3.6"
os: osx
AndreiH marked this conversation as resolved.
Show resolved Hide resolved
osx_image: xcode9.4
language: generic
env: TOXENV=py36

install:
- if [ "$TRAVIS_OS_NAME" = "osx" ]; then
curl -O -s https://bootstrap.pypa.io/get-pip.py;
python get-pip.py --user;
export PATH=$PATH:~/Library/Python/2.7/bin;
pip install --user tox virtualenv;
else
pip install tox virtualenv;
fi

install:
- ./.travis/install.sh

script:
- tox
Expand Down
14 changes: 14 additions & 0 deletions .travis/install.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#!/bin/bash

set -e
set -x

ci_requirements="tox virtualenv"

if [ "$TRAVIS_OS_NAME" == "osx" ]; then
curl -O https://bootstrap.pypa.io/get-pip.py
python get-pip.py --user
pip install --user virtualenv
AndreiH marked this conversation as resolved.
Show resolved Hide resolved
fi

pip install $ci_requirements
6 changes: 3 additions & 3 deletions mozdownload/parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@
from __future__ import absolute_import, unicode_literals

import re
import urllib
from HTMLParser import HTMLParser

import requests
from six.moves.html_parser import HTMLParser
from six.moves.urllib.parse import unquote


class DirectoryParser(HTMLParser):
Expand Down Expand Up @@ -68,7 +68,7 @@ def handle_starttag(self, tag, attrs):
# Links look like: /pub/firefox/nightly/2015/
# We have to trim the fragment down to the last item. Also to ensure we
# always get it, we remove a possible final slash first
url = urllib.unquote(attr[1])
url = unquote(attr[1])
self.active_url = url.rstrip('/').split('/')[-1]

return
Expand Down
30 changes: 15 additions & 15 deletions mozdownload/scraper.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,22 +10,20 @@
import os
import re
import sys
import urllib
from datetime import datetime
from urlparse import urlparse

import mozinfo
import progressbar as pb
import redo
import requests
from six.moves.urllib.parse import quote, urlparse

from mozdownload import errors
from mozdownload import treeherder
from mozdownload.parser import DirectoryParser
from mozdownload.timezones import PacificTimezone
from mozdownload import treeherder
from mozdownload.utils import urljoin


APPLICATIONS = ('devedition', 'firefox', 'fennec', 'thunderbird')

# Some applications contain all locales in a single build
Expand Down Expand Up @@ -164,6 +162,7 @@ def _create_directory_parser(self, url):
@property
def binary(self):
"""Return the name of the build."""

def _get_binary():
# Retrieve all entries from the remote virtual folder
parser = self._create_directory_parser(self.path)
Expand Down Expand Up @@ -195,8 +194,8 @@ def binary_regex(self):
@property
def url(self):
"""Return the URL of the build."""
return urllib.quote(urljoin(self.path, self.binary),
safe='%/:=&?~#+!$,;\'@()*[]|')
return quote(urljoin(self.path, self.binary),
safe='%/:=&?~#+!$,;\'@()*[]|')

@property
def path(self):
Expand Down Expand Up @@ -248,6 +247,7 @@ def detect_platform(self):

def download(self):
"""Download the specified file."""

def total_seconds(td):
# Keep backward compatibility with Python 2.6 which doesn't have
# this method
Expand Down Expand Up @@ -417,7 +417,7 @@ def get_latest_build_date(self):
parser.entries = parser.filter(r'.*%s\.txt' % self.platform_regex)
if not parser.entries:
message = 'Status file for %s build cannot be found' % \
self.platform_regex
self.platform_regex
raise errors.NotFoundError(message, url)

# Read status file for the platform, retrieve build id,
Expand Down Expand Up @@ -457,7 +457,7 @@ def is_build_dir(self, folder_name):
def get_build_info_for_date(self, date, build_index=None):
"""Return the build information for a given date."""
url = urljoin(self.base_url, self.monthly_build_list_regex)
has_time = date and date.time()
has_time = date and date.time() and date.strftime('%H-%M-%S') != '00-00-00'
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Due you know for which value of date this fails? Which test is causing that?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, I see in the stacktrace that there are already the args and values which the tests fail with: https://travis-ci.org/mozilla/mozdownload/jobs/503557491

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As best pick one of those failing tests and run it alone by using the -k option like tox -- -k test_name. Also specify -s so that you get all the output. I would like to know what date.time() differs in between Python2.7 and Python3.

Copy link
Contributor Author

@AndreiH AndreiH Mar 15, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Test test_build_indices
I don't know why -s command did what it should do. I add it at the end: tox -e py27 -- -k test_build_indices > output.txt -s

Python 3.6: https://gist.github.com/AndreiH/d8cb89dd509a7a4733d58ba706fbdb27
Python 2.7: https://gist.github.com/AndreiH/7b32e6c9a22cfb2212d58ab5d5602769

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So here is the snippet for your testing: https://gist.github.com/whimboo/63ac15a7029fa2b6be9da33858fb0a91

Note the different behavior between Python2 and Python3. We have to get it fixed, and comparing to 00:00:00 is not a good idea given that at this second we also could have a sub folder.


self.logger.info('Retrieving list of builds from %s' % url)
parser = self._create_directory_parser(url)
Expand All @@ -467,7 +467,7 @@ def get_build_info_for_date(self, date, build_index=None):
# ensure to select the correct subfolder for localized builds
'L10N': '(-l10n)?' if self.locale_build else '',
'PLATFORM': '' if self.application not in (
'fennec') else '-' + self.platform
'fennec') else '-' + self.platform
}

parser.entries = parser.filter(regex)
Expand All @@ -482,7 +482,7 @@ def get_build_info_for_date(self, date, build_index=None):
if not parser.entries:
date_format = '%Y-%m-%d-%H-%M-%S' if has_time else '%Y-%m-%d'
message = 'Folder for builds on %s has not been found' % \
self.date.strftime(date_format)
self.date.strftime(date_format)
raise errors.NotFoundError(message, url)

# If no index has been given, set it to the last build of the day.
Expand Down Expand Up @@ -663,8 +663,8 @@ def query_versions(self, version=None):
parser = self._create_directory_parser(url)
if version:
versions = parser.filter(RELEASE_AND_CANDIDATE_LATEST_VERSIONS[version])
from distutils.version import LooseVersion
versions.sort(key=LooseVersion)
from packaging.version import LegacyVersion
versions.sort(key=LegacyVersion)
return [versions[-1]]
else:
return parser.entries
Expand All @@ -690,7 +690,7 @@ def get_build_info(self):
parser = self._create_directory_parser(url)
if not parser.entries:
message = 'Folder for specific candidate builds at %s has not' \
'been found' % url
'been found' % url
raise errors.NotFoundError(message, url)

self.show_matching_builds(parser.entries)
Expand Down Expand Up @@ -909,11 +909,11 @@ def get_build_info_for_index(self, build_index=None):
# If a timestamp is given, retrieve the folder with the timestamp
# as name
parser.entries = self.timestamp in parser.entries and \
[self.timestamp]
[self.timestamp]

elif self.date:
# If date is given, retrieve the subset of builds on that date
parser.entries = filter(self.date_matches, parser.entries)
parser.entries = list(filter(self.date_matches, parser.entries))

if not parser.entries:
message = 'No builds have been found'
Expand Down
6 changes: 3 additions & 3 deletions mozdownload/treeherder.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,12 @@
from __future__ import absolute_import, unicode_literals

import logging
import six

from thclient import TreeherderClient

from mozdownload.errors import NotSupportedError


PLATFORM_MAP = {
'android-api-9': {'build_platform': 'android-2-3-armv7-api9'},
'android-api-11': {'build_platform': 'android-4-0-armv7-api11'},
Expand Down Expand Up @@ -69,11 +69,11 @@ def query_builds_by_revision(self, revision, job_type_name='Build', debug_build=

try:
self.logger.info('Querying {url} for list of builds for revision: {revision}'.format(
url=self.client.server_url, revision=revision))
url=self.client.server_url, revision=revision))

# Retrieve the option hash to filter for type of build (opt, and debug for now)
option_hash = None
for key, values in self.client.get_option_collection_hash().iteritems():
for key, values in six.iteritems(self.client.get_option_collection_hash()):
for value in values:
if value['name'] == ('debug' if debug_build else 'opt'):
option_hash = key
Expand Down
7 changes: 4 additions & 3 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
mozinfo >= 0.9
mozinfo >= 1.0.0
progressbar2 >= 3.34.3
redo==2.0.2
requests >= 2.9.1, <3.0.0
treeherder-client==5.0.0
requests >= 2.21.0, <3.0.0
treeherder-client >= 5.0.0, <6.0.0
packaging == 19.0
2 changes: 1 addition & 1 deletion tests/cli/test_cli_arguments.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,4 @@ def test_unrecognized_argument():
stderr=subprocess.STDOUT)
except subprocess.CalledProcessError as e:
output = e.output
assert re.search(r'mozdownload: error: unrecognized arguments: --abc', output) is not None
assert re.search(r'mozdownload: error: unrecognized arguments: --abc'.encode('utf-8'), output) is not None
2 changes: 1 addition & 1 deletion tests/cli/test_cli_print_url.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,4 @@ def test_print_url_argument():
output = subprocess.check_output(args, stderr=subprocess.STDOUT)
except subprocess.CalledProcessError as e:
output = e.output
assert re.search(url, output) is not None
assert re.search(url.encode('utf-8'), output) is not None
2 changes: 2 additions & 0 deletions tests/cli/test_correct_scraper.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@
'fname': '8fcac92cfcad-firefox-38.0a1.en-US.win32.installer.exe',
},
}


@pytest.mark.parametrize("data", tests.values())
def test_correct_cli_scraper(httpd, tmpdir, data, mocker):
query_builds_by_revision = mocker.patch('mozdownload.treeherder.Treeherder.query_builds_by_revision')
Expand Down
8 changes: 7 additions & 1 deletion tests/cli/test_output.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
#!/usr/bin/env python

# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this file,
# You can obtain one at http://mozilla.org/MPL/2.0/.

import subprocess

from mozdownload import __version__, cli
Expand All @@ -6,4 +12,4 @@
def test_cli_executes():
"""Test that cli will start and print usage message"""
output = subprocess.check_output(['mozdownload', '--help'])
assert cli.__doc__.format(__version__) in output
assert cli.__doc__.format(__version__) in output.decode("utf-8")
12 changes: 7 additions & 5 deletions tests/daily_scraper/test_daily_scraper.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,9 @@
# You can obtain one at http://mozilla.org/MPL/2.0/.

import os
import urllib

import pytest
from six.moves.urllib.parse import unquote

from mozdownload import DailyScraper
from mozdownload.utils import urljoin
Expand Down Expand Up @@ -48,15 +49,15 @@
({'platform': 'win32', 'branch': 'mozilla-central', 'date': '2013-07-02', 'build_number': 1},
'2013-07-02-03-12-13-mozilla-central-firefox-27.0a1.en-US.win32.installer.exe',
'firefox/nightly/2013/07/2013-07-02-03-12-13-mozilla-central/firefox-27.0a1.en-US.win32.installer.exe'),
# Old stub format
# Old stub format
({'platform': 'win32', 'branch': 'mozilla-central', 'date': '2013-09-30', 'is_stub_installer': True},
'2013-09-30-03-02-04-mozilla-central-firefox-27.0a1.en-US.win32.installer-stub.exe',
'firefox/nightly/2013/09/2013-09-30-03-02-04-mozilla-central/firefox-27.0a1.en-US.win32.installer-stub.exe'),
# Old file name format
# Old file name format
({'platform': 'win64', 'branch': 'mozilla-central', 'date': '2013-09-30'},
'2013-09-30-03-02-04-mozilla-central-firefox-27.0a1.en-US.win64-x86_64.installer.exe',
'firefox/nightly/2013/09/2013-09-30-03-02-04-mozilla-central/firefox-27.0a1.en-US.win64-x86_64.installer.exe'),
# New stub format
# New stub format
({'platform': 'win32', 'branch': 'mozilla-central', 'is_stub_installer': True},
'2013-10-01-03-02-04-mozilla-central-Firefox Installer.en-US.exe',
'firefox/nightly/2013/10/2013-10-01-03-02-04-mozilla-central/Firefox Installer.en-US.exe'),
Expand Down Expand Up @@ -126,6 +127,7 @@
'mobile/nightly/2016/02/2016-02-02-00-40-08-mozilla-aurora-android-api-15/fennec-46.0a2.multi.android-arm.apk'),
]


@pytest.mark.parametrize("args,filename,url", firefox_tests + thunderbird_tests + fennec_tests)
def test_scraper(httpd, tmpdir, args, filename, url):
"""Testing various download scenarios for DailyScraper"""
Expand All @@ -134,4 +136,4 @@ def test_scraper(httpd, tmpdir, args, filename, url):
expected_target = os.path.join(str(tmpdir), filename)
assert scraper.filename == expected_target

assert urllib.unquote(scraper.url) == urljoin(httpd.get_url(), url)
assert unquote(scraper.url) == urljoin(httpd.get_url(), url)
7 changes: 6 additions & 1 deletion tests/directory_parser/test_directory_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@

import os

import six

from mozdownload.parser import DirectoryParser
from mozdownload.utils import urljoin

Expand Down Expand Up @@ -44,7 +46,10 @@ def test_filter(httpd):
parser.entries = parser.filter(r'^\d+$')

# Get only the subdirectories of the folder
dirs = os.walk(folder_path).next()[1]
if six.PY2:
dirs = os.walk(folder_path).next()[1]
elif six.PY3:
dirs = os.walk(folder_path).__next__()[1]
dirs.sort()
assert parser.entries == dirs

Expand Down
Loading