Skip to content

Commit

Permalink
stop using deprecated imp module. update unit tests. add a repo verif…
Browse files Browse the repository at this point in the history
…ication
  • Loading branch information
llazzaro committed Sep 13, 2016
1 parent 01a4a2b commit 337c680
Show file tree
Hide file tree
Showing 3 changed files with 78 additions and 46 deletions.
61 changes: 50 additions & 11 deletions packyou/__init__.py
@@ -1,7 +1,9 @@
# -*- coding: utf-8 -*-
import os
import imp
import sys
from importlib.machinery import PathFinder

import requests

from git import Repo

Expand All @@ -20,9 +22,8 @@ def find_module(self, fullname, path=None):
Finds a module and returns a module loader when
the import uses packyou
"""
if fullname.startswith('packyou'):
self.path = path
return self
self.path = path
return self

def find_and_load_module(self, name, complete_name, path):
"""
Expand All @@ -31,17 +32,47 @@ def find_and_load_module(self, name, complete_name, path):
When the module could not be found it will raise ImportError
"""
if complete_name in sys.modules:
return sys.modules[name]
module_info = imp.find_module(name, path)
module = imp.load_module(name, *module_info)
sys.modules[complete_name] = module
return sys.modules[complete_name]
module = None
module_spec = PathFinder.find_spec(complete_name)
if module_spec:
loader = module_spec.loader
module = loader.load_module()
sys.modules[complete_name] = module
return module

def check_repository_available(self, username, repository_name):
"""
Sometimes github has a - in the username or repository name.
The - can't be used in the import statement.
"""
repo_url = 'https://github.com/{0}/{1}.git'.format(username, repository_name)
response = requests.get(repo_url)
if response.status_code == 404:
if '_' in username:
repo_url = 'https://github.com/{0}/{1}.git'.format(username.replace('_', '-'), repository_name)
response = requests.get(repo_url)
if response.status_code == 200:
return repo_url
if '_' in repository_name:
repo_url = 'https://github.com/{0}/{1}.git'.format(username, repository_name.replace('_', '-'))
response = requests.get(repo_url)
if response.status_code == 200:
return repo_url

repo_url = 'https://github.com/{0}/{1}.git'.format(username.replace('_', '-'), repository_name.replace('_', '-'))
response = requests.get(repo_url)
if response.status_code == 200:
return repo_url
raise ImportError('Github repository not found.')

return repo_url

def clone_github_repo(self, username, repository_name):
"""
Clones a github repo with a username and repository_name
"""
repo_url = 'https://github.com/{0}/{1}.git'.format(username, repository_name)
repo_url = self.check_repository_available(username, repository_name)
repository_local_destination = os.path.join(MODULES_PATH, 'github', username, repository_name)
if not os.path.exists(repository_local_destination):
Repo.clone_from(repo_url, repository_local_destination, branch='master')
Expand All @@ -60,6 +91,7 @@ def update_sys_path(self):
if os.path.isdir(file_or_directory[0]) or os.path.splitext(file_or_directory[0])[1] in ['.py', '.pyc']:
if file_or_directory[0] not in sys.path:
sys.path.append(file_or_directory[0])
# self.find_and_load_module(name, complete_name, path)

def load_module(self, name):
"""
Expand All @@ -71,6 +103,7 @@ def load_module(self, name):
splitted_names = name.split('.')
username = None
repository_name = None
name = splitted_names[-1]
if 'github' in splitted_names:
if len(splitted_names) >= 3:
username = splitted_names[splitted_names.index('github') + 1]
Expand All @@ -80,8 +113,6 @@ def load_module(self, name):
if username and repository_name:
self.clone_github_repo(username, repository_name)

name = splitted_names[-1]

if len(splitted_names) == 2:
self.update_sys_path()
return self.find_and_load_module('github', complete_name, self.path)
Expand All @@ -97,6 +128,14 @@ def load_module(self, name):
if len(splitted_names) >= 5:
return self.find_and_load_module(name, complete_name, self.path)

else:
self.update_sys_path()
module = self.find_and_load_module(name, complete_name, self.path or sys.path)
if not module:
raise ImportError
return module

raise ImportError


sys.meta_path.append(ImportFromGithub())
1 change: 1 addition & 0 deletions setup.py
Expand Up @@ -11,6 +11,7 @@

REQUIREMENTS = [
'gitpython',
'requests',
]

TEST_REQUIREMENTS = [
Expand Down
62 changes: 27 additions & 35 deletions tests/test_github_importer.py
@@ -1,15 +1,14 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from pytest import raises
from mock import patch
from mock import Mock, patch

from packyou import ImportFromGithub


@patch('sys.modules')
@patch('imp.find_module')
@patch('imp.load_module')
def test_first_level_of_import_name(imp_load_module, imp_find_module_mock, sys_modules_mock):
@patch('packyou.PathFinder')
@patch('packyou.requests')
def test_first_level_of_import_name(requests_mock, path_finder_mock, sys_modules_mock):
sys_modules = {}

def getitem(name):
Expand All @@ -20,25 +19,24 @@ def setitem(name, val):

sys_modules_mock.__getitem__.side_effect = getitem
sys_modules_mock.__setitem__.side_effect = setitem
imp_load_module.return_value = 'mocked_module'
importer = ImportFromGithub()
module = importer.load_module('packyou.github')

assert imp_find_module_mock.mock_calls[0][1] == ('github', None)
assert module == 'mocked_module'
assert sys_modules_mock['packyou.github'] == 'mocked_module'

mocked_response = Mock()
mocked_response.status_code = 200
requests_mock.return_value = mocked_response
assert 'packyou.github' not in sys_modules
importer.load_module('packyou.github')
assert 'packyou.github' in sys_modules
# check cached module in sys.modules
module = importer.load_module('packyou.github')
assert module == 'mocked_module'
importer.load_module('packyou.github')
assert path_finder_mock.mock_calls[0][1] == ('packyou.github',)


@patch('packyou.open')
@patch('os.mkdir')
@patch('sys.modules')
@patch('imp.find_module')
@patch('imp.load_module')
def test_second_level_of_import_name(imp_load_module, imp_find_module_mock, sys_modules_mock, mkdir_mock, open_mock):
@patch('packyou.PathFinder')
def test_second_level_of_import_name(path_finder_mock, sys_modules_mock, mkdir_mock, open_mock):
sys_modules = {}

def getitem(name):
Expand All @@ -49,23 +47,20 @@ def setitem(name, val):

sys_modules_mock.__getitem__.side_effect = getitem
sys_modules_mock.__setitem__.side_effect = setitem
imp_load_module.return_value = 'mocked_module'
importer = ImportFromGithub()
module = importer.load_module('packyou.github.github_username')
importer.load_module('packyou.github.github_username')

assert 'packyou/github/github_username/__init__.py' in open_mock.mock_calls[0][1][0]
assert 'packyou/github/github_username' in mkdir_mock.mock_calls[0][1][0]
assert imp_find_module_mock.mock_calls[0][1] == ('github_username', None)
assert module == 'mocked_module'
assert sys_modules_mock['packyou.github.github_username'] == 'mocked_module'
assert path_finder_mock.mock_calls[0][1] == ('packyou.github.github_username', )


@patch('packyou.open')
@patch('packyou.Repo')
@patch('sys.modules')
@patch('imp.find_module')
@patch('imp.load_module')
def test_third_level_of_import_name(imp_load_module, imp_find_module_mock, sys_modules_mock, repo_mock, open_mock):
@patch('packyou.PathFinder')
@patch('packyou.requests')
def test_third_level_of_import_name(requests_mock, path_finder_mock, sys_modules_mock, repo_mock, open_mock):
sys_modules = {}

def getitem(name):
Expand All @@ -76,18 +71,15 @@ def setitem(name, val):

sys_modules_mock.__getitem__.side_effect = getitem
sys_modules_mock.__setitem__.side_effect = setitem
imp_load_module.return_value = 'mocked_module'
importer = ImportFromGithub()
module = importer.load_module('packyou.github.github_username.test_repo')

mocked_response = Mock()
mocked_response.status_code = 200
requests_mock.return_value = mocked_response

importer.load_module('packyou.github.github_username.test_repo')
assert 'packyou/github/github_username/test_repo/__init__.py' in open_mock.mock_calls[0][1][0]
assert repo_mock.mock_calls[0][1][0] == 'https://github.com/github_username/test_repo.git'
assert 'packyou/github/github_username/test_repo' in repo_mock.mock_calls[0][1][1]
assert imp_find_module_mock.mock_calls[0][1] == ('test_repo', None)
assert module == 'mocked_module'
assert sys_modules_mock['packyou.github.github_username.test_repo'] == 'mocked_module'


def test_raise_import_error_when_load_module_is_called_without_github():
importer = ImportFromGithub()
with raises(ImportError):
importer.load_module('os.path')
assert path_finder_mock.mock_calls[0][1] == ('packyou.github.github_username.test_repo', )
assert requests_mock.mock_calls[0][1][0] == 'https://github.com/github_username/test_repo.git'

0 comments on commit 337c680

Please sign in to comment.