Skip to content

Commit

Permalink
Merge pull request conan-io#3876 from memsharded/feature/fix_python_r…
Browse files Browse the repository at this point in the history
…equires_imports

Feature/fix python requires imports
  • Loading branch information
memsharded authored Oct 30, 2018
2 parents a40b8a5 + 2db97c2 commit b7b90b3
Show file tree
Hide file tree
Showing 6 changed files with 76 additions and 36 deletions.
16 changes: 4 additions & 12 deletions conans/client/graph/python_requires.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
import imp
import sys
import os
from collections import namedtuple

from conans.model.ref import ConanFileReference
from conans.client.loader import parse_conanfile
from conans.client.recorder.action_recorder import ActionRecorder
from conans.model.ref import ConanFileReference
from conans.model.requires import Requirement
from collections import namedtuple


PythonRequire = namedtuple("PythonRequire", "conan_ref module")
Expand Down Expand Up @@ -36,13 +34,7 @@ def __call__(self, require):
result = self._proxy.get_recipe(r, False, False, remote_name=None,
recorder=ActionRecorder())
path, _, _, reference = result
try:
dirname = os.path.dirname(path)
sys.path.append(dirname)
# replace avoid warnings in Py2 with dots
module = imp.load_source(str(r).replace(".", "*"), path)
finally:
sys.path.pop()
module, _ = parse_conanfile(path)
python_require = PythonRequire(reference, module)
self._cached_requires[require] = python_require
self._requires.append(python_require)
Expand Down
12 changes: 6 additions & 6 deletions conans/client/loader.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ def __init__(self, runner, output, python_requires):
sys.modules["conans"].python_requires = python_requires

def load_class(self, conanfile_path):
loaded, filename = _parse_file(conanfile_path)
loaded, filename = parse_conanfile(conanfile_path)
try:
conanfile = _parse_module(loaded, filename)
conanfile.python_requires = self._python_requires.requires
Expand Down Expand Up @@ -218,17 +218,17 @@ def _invalid_python_requires(require):
raise ConanException("Invalid use of python_requires(%s)" % require)


def _parse_file(conan_file_path):
def parse_conanfile(conan_file_path):
""" From a given path, obtain the in memory python import module
"""

if not os.path.exists(conan_file_path):
raise NotFoundException("%s not found!" % conan_file_path)

module_id = str(uuid.uuid1())
current_dir = os.path.dirname(conan_file_path)
sys.path.insert(0, current_dir)
try:
module_id = str(uuid.uuid1())
current_dir = os.path.dirname(conan_file_path)
sys.path.append(current_dir)
old_modules = list(sys.modules.keys())
with chdir(current_dir):
sys.dont_write_bytecode = True
Expand Down Expand Up @@ -256,6 +256,6 @@ def _parse_file(conan_file_path):
raise ConanException("Unable to load conanfile in %s\n%s" % (conan_file_path,
'\n'.join(trace[3:])))
finally:
sys.path.pop()
sys.path.pop(0)

return loaded, module_id
7 changes: 3 additions & 4 deletions conans/test/client/cmd/export_test.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@

import os
import shutil
import unittest
Expand All @@ -9,7 +8,7 @@
from conans.test.utils.tools import TestServer, TestClient
from conans.util.files import save, load
from conans.client.cmd.export import _replace_scm_data_in_conanfile
from conans.client.loader import _parse_file
from conans.client.loader import parse_conanfile
from conans.test.utils.test_files import temp_folder
from conans.model.scm import SCMData

Expand All @@ -24,7 +23,7 @@ class ConanLib(ConanFile):
scm = {{"revision": "{revision}",
"type": "git",
"url": "{url}"}}
{after_scm}
{after_recipe}
Expand All @@ -49,7 +48,7 @@ def _do_actual_test(self, scm_data, after_scm, after_recipe):
scm_data = SCMData(conanfile=namedtuple('_', 'scm')(scm=scm_data))
_replace_scm_data_in_conanfile(self.conanfile_path, scm_data)
self.assertEqual(load(self.conanfile_path), target_conanfile)
_parse_file(self.conanfile_path) # Check that the resulting file is valid python code.
parse_conanfile(self.conanfile_path) # Check that the resulting file is valid python code.

def test_conanfile_after_scm(self):
scm_data = {'type': 'git',
Expand Down
4 changes: 3 additions & 1 deletion conans/test/functional/scm_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import os
import unittest
from collections import namedtuple
from nose.plugins.attrib import attr

from conans.client.tools.scm import Git, SVN
from conans.model.ref import ConanFileReference, PackageReference
Expand Down Expand Up @@ -36,6 +37,7 @@ def build(self):
base_svn = base % "svn"


@attr('git')
class GitSCMTest(unittest.TestCase):

def setUp(self):
Expand Down Expand Up @@ -477,14 +479,14 @@ def scm_serialization_test(self):
self.assertEquals(data, data2)


@attr('svn')
class SVNSCMTest(SVNLocalRepoTestCase):

def setUp(self):
self.reference = ConanFileReference.loads("lib/0.1@user/channel")
self.client = TestClient()

def _commit_contents(self):
# self.client.runner('svn co "{url}" "{path}"'.format(url=self.repo_url, path=self.client.current_folder))
self.client.runner("svn add *", cwd=self.client.current_folder)
self.client.runner('svn commit -m "commiting"', cwd=self.client.current_folder)

Expand Down
68 changes: 55 additions & 13 deletions conans/test/integration/python_build_test.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import unittest
from conans.test.utils.tools import TestClient, TestServer,\
create_local_git_repo
from conans.paths import CONANFILE, BUILD_INFO
from conans.util.files import load, save
import os
from conans.test.utils.test_files import temp_folder
import unittest

from conans.model.info import ConanInfo
from conans.model.ref import ConanFileReference
from conans.paths import CONANFILE, BUILD_INFO
from conans.test.utils.test_files import temp_folder
from conans.test.utils.tools import TestClient, TestServer, create_local_git_repo
from conans.util.files import load, save


conanfile = """from conans import ConanFile
Expand Down Expand Up @@ -104,8 +104,8 @@ class PkgTest(base.MyConanfileBase):
self.assertIn("Pkg/0.1@lasote/testing: My cool package_info!", client.out)
client.run("remove * -f")
client.run("download Pkg/0.1@lasote/testing")
self.assertIn("Pkg/0.1@lasote/testing: Package installed 5ab84d6acfe1f23c4fae0ab88f26e3a396351ac9",
client.out)
self.assertIn("Pkg/0.1@lasote/testing: Package installed "
"5ab84d6acfe1f23c4fae0ab88f26e3a396351ac9", client.out)

def reuse_version_ranges_test(self):
client = TestClient()
Expand Down Expand Up @@ -138,7 +138,8 @@ def source(self):
self.assertTrue(error)
self.assertIn("ERROR: Pkg/0.1@lasote/testing: Error in source() method, line 4", client.out)
self.assertIn('base = python_requires("MyConanfileBase/1.0@lasote/testing', client.out)
self.assertIn("Invalid use of python_requires(MyConanfileBase/1.0@lasote/testing)", client.out)
self.assertIn("Invalid use of python_requires(MyConanfileBase/1.0@lasote/testing)",
client.out)

def transitive_multiple_reuse_test(self):
client = TestClient()
Expand Down Expand Up @@ -257,8 +258,8 @@ class PkgTest(base.MyConanfileBase):
self.assertIn("Pkg/0.1@lasote/testing: My cool package_info!", client.out)
client.run("remove * -f")
client.run("download Pkg/0.1@lasote/testing")
self.assertIn("Pkg/0.1@lasote/testing: Package installed 5ab84d6acfe1f23c4fae0ab88f26e3a396351ac9",
client.out)
self.assertIn("Pkg/0.1@lasote/testing: Package installed "
"5ab84d6acfe1f23c4fae0ab88f26e3a396351ac9", client.out)

def reuse_scm_test(self):
client = TestClient()
Expand Down Expand Up @@ -383,6 +384,45 @@ def build(self):
client.run("create . Pkg/0.1@user/testing")
self.assertIn("Pkg/0.1@user/testing: HEADER CONTENT!: my header Pkg!!", client.out)

def transitive_imports_conflicts_test(self):
# https://github.com/conan-io/conan/issues/3874
client = TestClient()
conanfile = """from conans import ConanFile
import myhelper
class SourceBuild(ConanFile):
exports = "*.py"
"""
helper = """def myhelp(output):
output.info("MyHelperOutput!")
"""
client.save({"conanfile.py": conanfile,
"myhelper.py": helper})
client.run("export . base1/1.0@user/channel")
client.save({"myhelper.py": helper.replace("MyHelperOutput!", "MyOtherHelperOutput!")})
client.run("export . base2/1.0@user/channel")

conanfile = """from conans import ConanFile, python_requires
base2 = python_requires("base2/1.0@user/channel")
base1 = python_requires("base1/1.0@user/channel")
class MyConanfileBase(ConanFile):
def build(self):
base1.myhelper.myhelp(self.output)
base2.myhelper.myhelp(self.output)
"""
# This should work, even if there is a local "myhelper.py" file, which could be
# accidentaly imported (and it was, it was a bug)
client.save({"conanfile.py": conanfile})
client.run("create . Pkg/0.1@lasote/testing")
self.assertIn("Pkg/0.1@lasote/testing: MyHelperOutput!", client.out)
self.assertIn("Pkg/0.1@lasote/testing: MyOtherHelperOutput!", client.out)

# Now, the same, but with "clean_first=True", should keep working
client.save({"conanfile.py": conanfile}, clean_first=True)
client.run("create . Pkg/0.1@lasote/testing")
self.assertIn("Pkg/0.1@lasote/testing: MyHelperOutput!", client.out)
self.assertIn("Pkg/0.1@lasote/testing: MyOtherHelperOutput!", client.out)


class PythonBuildTest(unittest.TestCase):

Expand Down Expand Up @@ -594,7 +634,8 @@ def package_info(self):
client.run("export . lasote/stable")

# We can't build the package without our PYTHONPATH
self.assertRaises(Exception, client.run, "install conantool/1.0@lasote/stable --build missing")
self.assertRaises(Exception, client.run,
"install conantool/1.0@lasote/stable --build missing")

# But we can inject the PYTHONPATH
client.run("install conantool/1.0@lasote/stable -e PYTHONPATH=['%s']" % external_dir)
Expand Down Expand Up @@ -648,4 +689,5 @@ def external_baz():
client.save({CONANFILE: conanfile_simple})
client.run("export . lasote/stable")
# Should work even if PYTHONPATH is not declared as [], only external resource needed
client.run('install Hello/0.1@lasote/stable --build missing -e PYTHONPATH="%s"' % external_dir)
client.run('install Hello/0.1@lasote/stable --build missing -e PYTHONPATH="%s"'
% external_dir)
5 changes: 5 additions & 0 deletions conans/test/util/tools_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -1331,6 +1331,7 @@ def build(self):
client.run("create . user/channel")


@attr('git')
class GitToolTest(unittest.TestCase):

def test_repo_root(self):
Expand Down Expand Up @@ -1572,6 +1573,7 @@ def build(self):
self.assertIn("specify a branch to checkout", client.out)


@attr('svn')
class SVNToolTestsBasic(SVNLocalRepoTestCase):
def test_clone(self):
project_url, _ = self.create_project(files={'myfile': "contents"})
Expand Down Expand Up @@ -1767,6 +1769,7 @@ def test_branch(self):
self.assertEqual("tags/v12.3.4", svn.get_branch())


@attr('svn')
class SVNToolTestsBasicOldVersion(SVNToolTestsBasic):
def run(self, *args, **kwargs):
try:
Expand All @@ -1781,6 +1784,7 @@ def run(self, *args, **kwargs):
# Do not add tests to this class, all should be compatible with new version of SVN


@attr('svn')
@unittest.skipUnless(SVN.get_version() >= SVN.API_CHANGE_VERSION, "SVN::is_pristine not implemented")
class SVNToolTestsPristine(SVNLocalRepoTestCase):

Expand Down Expand Up @@ -1996,6 +2000,7 @@ def test_ignored_external(self):
self.assertTrue(self.svn.is_pristine())


@attr('svn')
class SVNToolsTestsRecipe(SVNLocalRepoTestCase):

conanfile = """
Expand Down

0 comments on commit b7b90b3

Please sign in to comment.