Skip to content
This repository has been archived by the owner on Sep 26, 2022. It is now read-only.

Commit

Permalink
Landscape.io fixes
Browse files Browse the repository at this point in the history
Updated FileDownloader init signature
Fixed arguments passed to FileDownloader
Updated format strings when logging
Added FileDownloaderError

Fix import

Update tests

Raise error when incorrect type of args are passed to FileDownloader
  • Loading branch information
JMSwag committed Jul 17, 2016
1 parent 67911dc commit 3fa601d
Show file tree
Hide file tree
Showing 14 changed files with 99 additions and 56 deletions.
8 changes: 5 additions & 3 deletions .landscape.yml
Expand Up @@ -2,9 +2,11 @@
doc-warnings: yes
max-line-length: 80
ignore-paths:
- demos
- dev
- docs
- demos/
- dev/
- docs/
- pyupdater/_version.py
- versioneer.py
python-targets:
- 2
- 3
Expand Down
3 changes: 0 additions & 3 deletions .python-version
@@ -1,6 +1,3 @@
3.3.3
3.3.4
3.4.3
3.4.4
3.5.0
3.5.1
2 changes: 1 addition & 1 deletion Makefile
Expand Up @@ -4,7 +4,7 @@ clean:
deps:
pip install -r requirements.txt --upgrade

deps-dev: deps-upgrade
deps-dev:
pip install -r dev/requirements.txt --upgrade

deploy: clean docs-deploy pypi
Expand Down
1 change: 0 additions & 1 deletion dev/requirements.txt
@@ -1,4 +1,3 @@
asciinema
coverage
line_profiler == 1.0
memory_profiler
Expand Down
7 changes: 7 additions & 0 deletions docs/changelog.md
Expand Up @@ -3,6 +3,13 @@
## v2.0.4 - Master
####* This version is not yet released and is under active development.

####Added

- FileDownloaderError

####Fixed

- Using format string while logging

## v2.0.3 - 2016/07/09

Expand Down
4 changes: 2 additions & 2 deletions pyupdater/cli/__init__.py
Expand Up @@ -307,7 +307,7 @@ def _upload(data):
log.info('Logs uploaded to %s', url)


def plugins(args):
def plugins():
plug_mgr = PluginManager({})
names = ['\n']
for n in plug_mgr.get_plugin_names():
Expand Down Expand Up @@ -375,7 +375,7 @@ def _real_main(args): # pragma: no cover
elif cmd == 'pkg':
pkg(args)
elif cmd == 'plugins':
plugins(args)
plugins()
elif cmd == 'settings':
_setting(args)
elif cmd == 'upload':
Expand Down
43 changes: 27 additions & 16 deletions pyupdater/client/downloader.py
Expand Up @@ -22,7 +22,7 @@
import urllib3

from pyupdater.utils import get_hash, get_http_pool

from pyupdater.utils.exceptions import FileDownloaderError
log = logging.getLogger(__name__)


Expand All @@ -47,22 +47,36 @@ class FileDownloader(object):
False: Don't verify https connection
"""
def __init__(self, filename, urls, hexdigest=None, verify=True,
progress_hooks=None):
self.filename = filename
if isinstance(urls, list) is False:
self.urls = [urls]
else:
self.urls = urls
self.hexdigest = hexdigest
self.verify = verify
def __init__(self, *args, **kwargs):
# We'll append the filename to one of the provided urls
# to create the download link
try:
self.filename = args[0]
except IndexError:
raise FileDownloaderError('No filename provided', expected=True)

try:
self.urls = args[1]
except IndexError:
raise FileDownloaderError('No urls provided', expected=True)
# User may have accidently passed a string to
# the urls para
if isinstance(self.urls, list) is False:
raise FileDownloaderError('Must pass list of urls', expected=True)

try:
self.hexdigest = args[2]
except IndexError:
self.hexdigest = kwargs.get('hexdigest')

self.verify = kwargs.get('verify', True)
self.progress_hooks = kwargs.get('progress_hooks', [])
# End of user configurable options
self.b_size = 4096 * 4
self.file_binary_data = None
self.my_file = BytesIO()
self.content_length = None
if progress_hooks is None:
progress_hooks = []
self.progress_hooks = progress_hooks

if self.verify is True:
self.http_pool = get_http_pool()
else:
Expand Down Expand Up @@ -159,9 +173,6 @@ def _download_to_memory(self):
self.b_size = self._best_block_size(end_block - start_block,
len(block))
log.debug('Block size: %s', self.b_size)
# Saving data to memory
# ToDo: Consider writing file to cache to enable resumable
# downloads
self.my_file.write(block)
recieved_data += len(block)
percent = self._calc_progress_percent(recieved_data,
Expand Down
2 changes: 1 addition & 1 deletion pyupdater/client/patcher.py
Expand Up @@ -257,7 +257,7 @@ def _download_verify_patches(self):
for p in self.patch_data:
# Initialize downloader
fd = FileDownloader(p['patch_name'], p['patch_urls'],
p['patch_hash'], self.verify)
hexdigest=p['patch_hash'], verify=self.verify)

# Attempt to download resource
data = fd.download_verify_return()
Expand Down
3 changes: 2 additions & 1 deletion pyupdater/client/updates.py
Expand Up @@ -324,7 +324,8 @@ def _full_update(self, name):
with jms_utils.paths.ChDir(self.update_folder):
log.info('Downloading update...')
fd = FileDownloader(filename, self.update_urls,
file_hash, self.verify, self.progress_hooks)
hexdigest=file_hash, verify=self.verify,
progress_hooks=self.progress_hooks)
result = fd.download_verify_write()
if result:
log.info('Download Complete')
Expand Down
36 changes: 24 additions & 12 deletions pyupdater/compat.py
@@ -1,9 +1,11 @@
import argparse
import logging
import os
# Optpare is deprecated
# Optpare is deprecated. This will results in an error for the user.
# Users have to user PyInstaller > 3.0 or Python version lower
# then the version which removed optparse from the stdlib.
try:
import optparse
import optparse # noqa
except ImportError:
optparse = None

Expand Down Expand Up @@ -50,7 +52,6 @@ def run_makespec(args, opts=None):
spec_file = _pyi_makespec.main(args.scriptname, **vars(args))
log.info('wrote %s', spec_file)


if is_pyi30:
# We will exit with an error message in builder.py
if optparse is None:
Expand All @@ -59,19 +60,27 @@ def run_makespec(args, opts=None):
parser = optparse.OptionParser(usage=('%prog [opts] <scriptname> [ '
'<scriptname> ...] | <specfil'
'e>'))
_pyi_makespec.__add_options(parser)
_pyi_log.__add_options(parser)
_pyi_compat.__add_obsolete_options(parser)

# We are hacking into pyinstaller here & are aware of the risks
# using noqa below so landscape.io will ignore it
_pyi_makespec.__add_options(parser) # noqa
_pyi_log.__add_options(parser) # noqa
_pyi_compat.__add_obsolete_options(parser) # noqa
# End hacking
opts, args = parser.parse_args(pyi_args)
_pyi_log.__process_options(parser, opts)
# We are hacking into pyinstaller here & are aware of the risks
# using noqa below so landscape.io will ignore it
_pyi_log.__process_options(parser, opts) # noqa
# End hacking

run_makespec(args, opts)
else:
parser = argparse.ArgumentParser()
_pyi_makespec.__add_options(parser)
_pyi_log.__add_options(parser)
_pyi_compat.__add_obsolete_options(parser)
# We are hacking into pyinstaller here & are aware of the risks
# using noqa below so landscape.io will ignore it
_pyi_makespec.__add_options(parser) # noqa
_pyi_log.__add_options(parser) # noqa
_pyi_compat.__add_obsolete_options(parser) # noqa
# End hacking
parser.add_argument('scriptname', nargs='+')

args = parser.parse_args(pyi_args)
Expand All @@ -80,7 +89,10 @@ def run_makespec(args, opts=None):
# namespace of the Pyinstaller.log module. logger is used
# in the Pyinstaller.log.__process_options call
_pyi_log.init()
_pyi_log.__process_options(parser, args)
# We are hacking into pyinstaller here & are aware of the risks
# using noqa below so landscape.io will ignore it
_pyi_log.__process_options(parser, args) # noqa
# End hacking

run_makespec(args)

Expand Down
5 changes: 4 additions & 1 deletion pyupdater/uploader.py
Expand Up @@ -164,7 +164,10 @@ class AbstractBaseUploaderMeta(type):

def __call__(cls, *args, **kwargs):
obj = type.__call__(cls, *args, **kwargs)
obj._check_attributes()
# We are using this meta class to ensure plugin authors have
# a plugin name & author name as class attributes.
obj._check_attributes() # noqa
# End ignore
return obj


Expand Down
12 changes: 6 additions & 6 deletions pyupdater/utils/__init__.py
Expand Up @@ -219,7 +219,7 @@ def config_plugin(self, name, config):
plugin.set_config(plugin_config)
except Exception as err:
log.error('There was an error during configuration '
'of {} crated by {}'.format(plugin.name, plugin.author))
'of %s crated by %s', plugin.name, plugin.author)
log.error(err)
log.debug(err, exc_info=True)

Expand Down Expand Up @@ -632,18 +632,18 @@ def dict_to_str_sanatize(data):
return new_data


def _decode_offt(bytes):
def _decode_offt(_bytes):
"""Decode an off_t value from a string.
This decodes a signed integer into 8 bytes. I'd prefer some sort of
signed vint representation, but this is the format used by bsdiff4.
"""
if sys.version_info[0] < 3:
bytes = map(ord, bytes)
x = bytes[7] & 0x7F
_bytes = map(ord, _bytes)
x = _bytes[7] & 0x7F
for b in xrange(6, -1, -1):
x = x * 256 + bytes[b]
if bytes[7] & 0x80:
x = x * 256 + _bytes[b]
if _bytes[7] & 0x80:
x = -x
return x

Expand Down
5 changes: 5 additions & 0 deletions pyupdater/utils/exceptions.py
Expand Up @@ -59,6 +59,11 @@ def __init__(self, *args, **kwargs):
super(ClientError, self).__init__(*args, **kwargs)


class FileDownloaderError(STDError):
def __init__(self, *args, **kwargs):
super(FileDownloaderError, self).__init__(*args, **kwargs)


class PackageHandlerError(STDError):
"""Raised for PackageHandler exceptions"""
def __init__(self, *args, **kwargs):
Expand Down
24 changes: 15 additions & 9 deletions tests/test_downloader.py
Expand Up @@ -18,32 +18,33 @@
import pytest

from pyupdater.client.downloader import FileDownloader
from pyupdater.utils.exceptions import FileDownloaderError


FILENAME = 'dont+delete+pyu+test.txt'
FILENAME_WITH_SPACES = 'dont delete pyu test.txt'
FILE_HASH = '82719546b992ef81f4544fb2690c6a05b300a0216eeaa8f3616b3b107a311629'
URL = 'https://pyu-tester.s3.amazonaws.com/'
URLS = ['https://pyu-tester.s3.amazonaws.com/']


@pytest.mark.usefixtue("cleandir")
class TestData(object):

def test_return(self):
fd = FileDownloader(FILENAME, URL, FILE_HASH, verify=True)
fd = FileDownloader(FILENAME, URLS, FILE_HASH, verify=True)
binary_data = fd.download_verify_return()
assert binary_data is not None

def test_cb(self):
def cb(status):
pass
fd = FileDownloader(FILENAME, URL, FILE_HASH,
fd = FileDownloader(FILENAME, URLS, hexdigest=FILE_HASH,
progress_hooks=[cb], verify=True)
binary_data = fd.download_verify_return()
assert binary_data is not None

def test_return_fail(self):
fd = FileDownloader(FILENAME, URL,
fd = FileDownloader(FILENAME, URLS,
'JKFEIFJILEFJ983NKFNKL', verify=True)
binary_data = fd.download_verify_return()
assert binary_data is None
Expand All @@ -52,27 +53,32 @@ def test_return_fail(self):
@pytest.mark.usefixtue("cleandir")
class TestUrl(object):
def test_url_with_spaces(self):
fd = FileDownloader(FILENAME_WITH_SPACES, URL,
FILE_HASH, verify=True)
fd = FileDownloader(FILENAME_WITH_SPACES, URLS,
hexdigest=FILE_HASH, verify=True)
binary_data = fd.download_verify_return()
assert binary_data is not None

def test_bad_url(self):
fd = FileDownloader(FILENAME, 'bad url', 'bad hash', verify=True)
fd = FileDownloader(FILENAME, ['bad url'], hexdigest='bad hash',
verify=True)
binary_data = fd.download_verify_return()
assert binary_data is None

def test_url_as_string(self):
with pytest.raises(FileDownloaderError):
fd = FileDownloader(FILENAME, URLS[0])


@pytest.mark.usefixtue("cleandir")
class TestContentLength(object):
def test_bad_content_length(self):
class FakeHeaders(object):
headers = {}
fd = FileDownloader(FILENAME, URL, FILE_HASH, verify=True)
fd = FileDownloader(FILENAME, URLS, hexdigest=FILE_HASH, verify=True)
data = FakeHeaders()
assert fd._get_content_length(data) == 100001

def test_good_conent_length(self):
fd = FileDownloader(FILENAME, URL, FILE_HASH, verify=True)
fd = FileDownloader(FILENAME, URLS, hexdigest=FILE_HASH, verify=True)
fd.download_verify_return()
assert fd.content_length == 2387

0 comments on commit 3fa601d

Please sign in to comment.