Skip to content

Commit

Permalink
More changes to move towards a library-friendly call system
Browse files Browse the repository at this point in the history
- Removes printing from the library-callable function
- Removes needing a file to be read-in to run the linter
  - TODO: I fear there are more of these hidden
  • Loading branch information
schuylermartin45 committed Jan 10, 2024
1 parent 4df3a8e commit f0ed3b7
Show file tree
Hide file tree
Showing 3 changed files with 48 additions and 31 deletions.
5 changes: 2 additions & 3 deletions .pytest.ini
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
# This surpresses deprecation `pytest` warnings related to using `conda.*` packages.
# TODO Future: remove/upgrade deprecated packages
[pytest]
filterwarnings =
ignore:conda.* is pending deprecation:PendingDeprecationWarning
ignore:conda.* is deprecated:DeprecationWarning
ignore::DeprecationWarning
ignore::PendingDeprecationWarning
66 changes: 39 additions & 27 deletions anaconda_linter/run.py
Original file line number Diff line number Diff line change
Expand Up @@ -134,33 +134,40 @@ def check_path(value) -> str:

def execute_linter(
recipe: str,
config: Optional[utils.RecipeConfigType] = None,
variant_config_files: Optional[list[str]] = None,
exclusive_config_files: Optional[list[str]] = None,
subdirs: Optional[list[str]] = None,
severity: lint.Severity = lint.SEVERITY_MIN_DEFAULT,
fix_flag: bool = False,
verbose_flag: bool = False,
) -> ReturnCode:
) -> tuple[ReturnCode, str]:
"""
Contains the primary execution code that would be in `main()`. This gives us a few benefits:
- Allows us to easily wrap and control return codes in unexpected failure cases.
- Allows us to execute the linter work as a library call in another Python project.
:param recipe: Path to the target feedstock (where `recipe/meta.yaml` can be found)
:param variant_config_files: (Optional)
:param exclusive_config_files: (Optional)
:param subdirs: (Optional)
:param severity: (Optional)
:param fix_flag: (Optional)
:param verbose_flag: (Optional)
:return: One of
:param config: (Optional) Defaults to the contents of the default config file provided in `config.yaml`.
:param variant_config_files: (Optional) Configuration files for recipe variants
:param exclusive_config_files: (Optional) Configuration files for exclusive recipe variants
:param subdirs: (Optional) Target recipe architectures/platforms
:param severity: (Optional) Minimum severity level of linting messages to report
:param fix_flag: (Optional) If set to true, the linter will automatically attempt to make changes to the target
recipe file.
:param verbose_flag: (Optional) Enables verbose debugging output.
:returns: The appropriate error code and the final text report containing linter results.
"""
# We want to remove our reliance on external files when the project is run as a library.
if config is None:
config = {
"requirements": "requirements.txt",
"blocklists": ["build-fail-blocklist"],
"channels": ["defaults"],
}

if subdirs is None:
subdirs = DEFAULT_SUBDIRS

# load global configuration
config_file = os.path.abspath(os.path.dirname(__file__) + "/config.yaml")
config = utils.load_config(config_file)

# set up linter
linter = lint.Linter(config=config, verbose=verbose_flag, exclude=None, nocatch=True, severity_min=severity)

Expand All @@ -175,15 +182,15 @@ def execute_linter(
overall_result = result
messages = messages | set(linter.get_messages())

# print report
print(lint.Linter.get_report(messages, verbose_flag))
# Calculate the final report
report: Final[str] = lint.Linter.get_report(messages, verbose_flag)

# Return appropriate error code.
if overall_result == lint.Severity.WARNING:
return ReturnCode.EXIT_LINTING_WARNINGS
return ReturnCode.EXIT_LINTING_WARNINGS, report
elif overall_result >= lint.Severity.ERROR:
return ReturnCode.EXIT_LINTING_ERRORS
return ReturnCode.EXIT_SUCCESS
return ReturnCode.EXIT_LINTING_ERRORS, report
return ReturnCode.EXIT_SUCCESS, report


def main() -> None:
Expand All @@ -193,18 +200,23 @@ def main() -> None:
args, _ = _lint_parser().parse_known_args()
severity: Final[lint.Severity] = _convert_severity(args.severity)

# load global configuration
config_file: Final[str] = os.path.abspath(os.path.dirname(__file__) + "/config.yaml")
config: Final[utils.RecipeConfigType] = utils.load_config(config_file)

try:
sys.exit(
execute_linter(
recipe=args.recipe,
variant_config_files=args.variant_config_files,
exclusive_config_files=args.exclusive_config_files,
subdirs=args.subdirs,
severity=severity,
fix_flag=args.fix,
verbose_flag=args.verbose,
)
return_code, report = execute_linter(
recipe=args.recipe,
config=config,
variant_config_files=args.variant_config_files,
exclusive_config_files=args.exclusive_config_files,
subdirs=args.subdirs,
severity=severity,
fix_flag=args.fix,
verbose_flag=args.verbose,
)
print(report)
sys.exit(return_code)
except Exception: # pylint: disable=broad-exception-caught
traceback.print_exc()
sys.exit(ReturnCode.EXIT_UNCAUGHT_EXCEPTION)
Expand Down
8 changes: 7 additions & 1 deletion anaconda_linter/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,11 @@
check_url_cache: URLCache = {}


# TODO: Confirm this is correct
# Represents a recipe's "config" or "cbc.yaml" file
RecipeConfigType = dict[str, str | list[str]]


def validate_config(path: str) -> None:
"""
Validate config against schema
Expand All @@ -46,7 +51,8 @@ def validate_config(path: str) -> None:
validate(config, schema)


def load_config(path: str):
# TODO determine type of "value"
def load_config(path: str) -> RecipeConfigType:
"""
Parses config file, building paths to relevant block-lists.
TODO Future: determine if this config file is necessary and if we can just get away with constants in this file
Expand Down

0 comments on commit f0ed3b7

Please sign in to comment.