Skip to content

Commit

Permalink
Allow --format=json in conan create for python-requires (#14594)
Browse files Browse the repository at this point in the history
* Fix conan create . --format=json for python-requires

* Shameful attemp, just uses the private functions as-is

* Fix up private usage, simplify testings

* Update conans/client/loader.py

Co-authored-by: James <memsharded@gmail.com>

---------

Co-authored-by: James <memsharded@gmail.com>
  • Loading branch information
AbrilRBS and memsharded authored Aug 29, 2023
1 parent d43e7a0 commit c3db0d7
Show file tree
Hide file tree
Showing 4 changed files with 72 additions and 8 deletions.
19 changes: 14 additions & 5 deletions conan/api/subapi/graph.py
Original file line number Diff line number Diff line change
Expand Up @@ -84,11 +84,17 @@ def load_root_test_conanfile(self, path, tested_reference, profile_host, profile
root_node = Node(ref, conanfile, recipe=RECIPE_CONSUMER, context=CONTEXT_HOST, path=path)
return root_node

def _load_root_virtual_conanfile(self, profile_host, profile_build, requires, tool_requires):
if not requires and not tool_requires:
def _load_root_virtual_conanfile(self, profile_host, profile_build, requires, tool_requires,
lockfile, remotes, update, check_updates=False, python_requires=None):
if not python_requires and not requires and not tool_requires:
raise ConanException("Provide requires or tool_requires")
app = ConanApp(self.conan_api.cache_folder)
conanfile = app.loader.load_virtual(requires=requires, tool_requires=tool_requires)
conanfile = app.loader.load_virtual(requires=requires,
tool_requires=tool_requires,
python_requires=python_requires,
graph_lock=lockfile, remotes=remotes,
update=update, check_updates=check_updates)

consumer_definer(conanfile, profile_host, profile_build)
root_node = Node(ref=None, conanfile=conanfile, context=CONTEXT_HOST, recipe=RECIPE_VIRTUAL)
return root_node
Expand All @@ -107,7 +113,7 @@ def _scope_options(profile, requires, tool_requires):
profile.options.scope(tool_requires[0])

def load_graph_requires(self, requires, tool_requires, profile_host, profile_build,
lockfile, remotes, update, check_updates=False):
lockfile, remotes, update, check_updates=False, python_requires=None):
requires = [RecipeReference.loads(r) if isinstance(r, str) else r for r in requires] \
if requires else None
tool_requires = [RecipeReference.loads(r) if isinstance(r, str) else r
Expand All @@ -116,7 +122,10 @@ def load_graph_requires(self, requires, tool_requires, profile_host, profile_bui
self._scope_options(profile_host, requires=requires, tool_requires=tool_requires)
root_node = self._load_root_virtual_conanfile(requires=requires, tool_requires=tool_requires,
profile_host=profile_host,
profile_build=profile_build)
profile_build=profile_build,
lockfile=lockfile, remotes=remotes,
update=update,
python_requires=python_requires)

# check_updates = args.check_updates if "check_updates" in args else False
deps_graph = self.load_graph(root_node, profile_host=profile_host,
Expand Down
10 changes: 8 additions & 2 deletions conan/cli/commands/create.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,14 @@ def create(conan_api, parser, *args):
if args.build is not None and args.build_test is None:
args.build_test = args.build

deps_graph = None
if not is_python_require:
if is_python_require:
deps_graph = conan_api.graph.load_graph_requires([], [],
profile_host=profile_host,
profile_build=profile_build,
lockfile=lockfile,
remotes=remotes, update=args.update,
python_requires=[ref])
else:
requires = [ref] if not args.build_require else None
tool_requires = [ref] if args.build_require else None
# FIXME: Dirty: package type still raw, not processed yet
Expand Down
10 changes: 9 additions & 1 deletion conans/client/loader.py
Original file line number Diff line number Diff line change
Expand Up @@ -244,7 +244,8 @@ def layout(_self):

return conanfile

def load_virtual(self, requires=None, tool_requires=None):
def load_virtual(self, requires=None, tool_requires=None, python_requires=None, graph_lock=None,
remotes=None, update=None, check_updates=None):
# If user don't specify namespace in options, assume that it is
# for the reference (keep compatibility)
conanfile = ConanFile(display_name="cli")
Expand All @@ -256,6 +257,13 @@ def load_virtual(self, requires=None, tool_requires=None):
for reference in requires:
conanfile.requires(repr(reference))

if python_requires:
conanfile.python_requires = [pr.repr_notime() for pr in python_requires]

if self._pyreq_loader:
self._pyreq_loader.load_py_requires(conanfile, self, graph_lock, remotes,
update, check_updates)

conanfile._conan_is_consumer = True
conanfile.generators = [] # remove the default txt generator
return conanfile
Expand Down
41 changes: 41 additions & 0 deletions conans/test/integration/command/create_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -770,3 +770,44 @@ def test_create_both_host_build_require():
# it used to fail, now it works and builds the test_package "tools_requires" in Release
c.assert_listed_binary({"protobuf/0.1": ("efa83b160a55b033c4ea706ddb980cd708e3ba1b", "Build")},
build=True, test_package=True)


def test_python_requires_json_format():
"""Check python requires does not crash when calling conan create . --format=json
See https://github.com/conan-io/conan/issues/14577"""
c = TestClient()
c.save({"conanfile.py": GenConanfile("pyreq", "1.0")
.with_package_type("python-require")})
c.run("create . --format=json", redirect_stdout="output.json")
data = json.loads(load(os.path.join(c.current_folder, "output.json")))
# There's a graph and the python requires is there
assert len(data["graph"]["nodes"]["0"]["python_requires"]) == 1


def test_python_requires_with_test_package():
c = TestClient()
# Code comes from the docs
conanfile = textwrap.dedent("""
from conan import ConanFile
def mynumber():
return 42
class PyReq(ConanFile):
name = "pyreq"
version = "1.0"
package_type = "python-require"
""")
test_conanfile = textwrap.dedent("""
from conan import ConanFile
class Tool(ConanFile):
def test(self):
pyreq = self.python_requires["pyreq"].module
mynumber = pyreq.mynumber()
self.output.info("{}!!!".format(mynumber))
""")
c.save({"conanfile.py": conanfile, "test_package/conanfile.py": test_conanfile})
c.run("create .")
# Ensure that creating a deps graph does not break the testing
assert "pyreq/1.0 (test package): 42!!!" in c.out

0 comments on commit c3db0d7

Please sign in to comment.