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

#123 Custom attributes must be protected #124

Open
wants to merge 8 commits into
base: master
Choose a base branch
from
18 changes: 17 additions & 1 deletion hooks/conan-center.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,15 @@
import sys
from logging import WARNING, ERROR, INFO, DEBUG, NOTSET

from conans import tools, ConanFile

import yaml
from conans import tools
try:
from conans import Settings
except ImportError:
from conans.model.settings import Settings


kb_errors = {"KB-H001": "DEPRECATED GLOBAL CPPSTD",
"KB-H002": "REFERENCE LOWERCASE",
"KB-H003": "RECIPE METADATA",
Expand Down Expand Up @@ -46,6 +48,7 @@
"KB-H031": "CONANDATA.YML REDUCE",
"KB-H032": "SYSTEM REQUIREMENTS",
"KB-H034": "TEST PACKAGE - NO IMPORTS()",
"KB-H035": "CUSTOM ATTRIBUTES",
"KB-H037": "NO AUTHOR",
"KB-H040": "NO TARGET NAME",
"KB-H041": "NO FINAL ENDLINE",
Expand Down Expand Up @@ -421,6 +424,19 @@ def test(out):
if "def imports" in test_package_conanfile:
out.error("The method `imports` is not allowed in test_package/conanfile.py")

@run_test("KB-H035", output)
def test(out):
mock = ConanFile(conanfile.output, None)
valid_attrs = [attr for attr in dir(mock) if not callable(attr)] + ['conan_data', 'python_requires']
Copy link
Contributor

Choose a reason for hiding this comment

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

At least, here we need python_requires_extend too. And for 1.26 we should handle new attributes/functions that could result of this PR conan-io/conan#6945

current_attrs = [attr for attr in dir(conanfile) if not callable(attr)]
invalid_attrs = re.findall(r"(__.*)\s?=", conanfile_content, re.MULTILINE)
for attr in current_attrs:
if not attr.startswith("_") and attr not in valid_attrs:
invalid_attrs.append(attr)
if invalid_attrs:
out.error("Custom attributes must be declared as protected. " \
"The follow attributes are invalid: '{}'".format("', '".join(invalid_attrs)))

@run_test("KB-H037", output)
def test(out):
author = getattr(conanfile, "author", None)
Expand Down
39 changes: 39 additions & 0 deletions tests/test_hooks/conan-center/test_conan-center.py
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@ def test_conanfile(self):
self.assertIn("ERROR: [CONAN CENTER INDEX URL (KB-H027)] The attribute 'url' should " \
"point to: https://github.com/conan-io/conan-center-index", output)
self.assertIn("[CMAKE MINIMUM VERSION (KB-H028)] OK", output)
self.assertIn("[CUSTOM ATTRIBUTES (KB-H035)] OK", output)
self.assertIn("[SYSTEM REQUIREMENTS (KB-H032)] OK", output)
self.assertIn("[SINGLE REQUIRES (KB-H055)] OK", output)

Expand All @@ -141,6 +142,7 @@ def test_conanfile_header_only(self):
"recipe", output)
self.assertIn("[META LINES (KB-H025)] OK", output)
self.assertIn("[CMAKE MINIMUM VERSION (KB-H028)] OK", output)
self.assertIn("[CUSTOM ATTRIBUTES (KB-H035)] OK", output)
self.assertIn("[SYSTEM REQUIREMENTS (KB-H032)] OK", output)

def test_conanfile_header_only_with_settings(self):
Expand All @@ -162,6 +164,7 @@ def test_conanfile_header_only_with_settings(self):
"recipe", output)
self.assertIn("[META LINES (KB-H025)] OK", output)
self.assertIn("[CMAKE MINIMUM VERSION (KB-H028)] OK", output)
self.assertIn("[CUSTOM ATTRIBUTES (KB-H035)] OK", output)
self.assertIn("[SYSTEM REQUIREMENTS (KB-H032)] OK", output)

def test_conanfile_settings_clear_with_settings(self):
Expand Down Expand Up @@ -604,6 +607,42 @@ def system_requirements(self):
self.assertIn("[SYSTEM REQUIREMENTS (KB-H032)] 'libusb' is part of the allowlist.", output)
self.assertNotIn("ERROR: [SYSTEM REQUIREMENTS (KB-H032)]", output)

def test_invalid_recipe_attributes(self):
conanfile = textwrap.dedent("""\
from conans import ConanFile

class AConan(ConanFile):
url = "fake_url.com"
license = "fake_license"
description = "whatever"
homepage = "homepage.com"
topics = ("fake_topic", "another_fake_topic")
exports_sources = "header.h"
options = {"foo": [True, False], "bar": [True, False]}
default_options = {"foo": False, "bar": True}
_source_subfolder = "source_subfolder"
_build_subfolder = "build_subfolder"
__my_private = "secret"
__attribute__ = "foobar"
__qux= "baz"
foobar = "package"
package_subfolder = "package"

def package(self):
self.copy("*", dst="include")

def _foobar(self):
pass

def __private(self):
pass
""")
tools.save('conanfile.py', content=conanfile)
output = self.conan(['create', '.', 'name/version@user/test'])
self.assertIn("ERROR: [CUSTOM ATTRIBUTES (KB-H035)] Custom attributes must be declared as "
"protected. The follow attributes are invalid: '__my_private ', "
"'__attribute__ ', '__qux', 'foobar', 'package_subfolder'", output)

def test_imports_not_allowed(self):
conanfile_tp = textwrap.dedent("""\
from conans import ConanFile, tools
Expand Down