{"id":13419373,"url":"https://github.com/tonybaloney/wily","last_synced_at":"2026-10-19T13:52:31.182Z","repository":{"id":37431080,"uuid":"152661983","full_name":"tonybaloney/wily","owner":"tonybaloney","description":"A Python application for tracking, reporting on timing and complexity in Python code","archived":false,"fork":false,"pushed_at":"2026-10-07T12:28:08.000Z","size":6883,"stargazers_count":1332,"open_issues_count":46,"forks_count":70,"subscribers_count":21,"default_branch":"master","last_synced_at":"2026-10-12T21:27:14.998Z","etag":null,"topics":["complexity","hacktoberfest","hacktoberfest-accepted","python","quality"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/tonybaloney.png","metadata":{"files":{"readme":"README.md","changelog":"HISTORY.md","contributing":"CONTRIBUTING.md","funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":".github/CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":"AGENTS.md","claude":null,"gemini":null,"cursor":null,"copilot":null,"dco":null,"cla":null,"disclosure":null},"funding":{"github":["tonybaloney"]}},"created_at":"2018-10-11T22:12:25.000Z","updated_at":"2026-10-07T14:45:59.000Z","dependencies_parsed_at":"2026-08-26T00:47:08.827Z","dependency_job_id":null,"html_url":"https://github.com/tonybaloney/wily","commit_stats":{"total_commits":769,"total_committers":26,"mean_commits":"29.576923076923077","dds":0.5916775032509753,"last_synced_commit":"2590691d5d29a2872cc175bdb773b1dbf5fde202"},"previous_names":[],"tags_count":40,"template":false,"template_full_name":null,"purl":"pkg:github/tonybaloney/wily","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tonybaloney%2Fwily","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tonybaloney%2Fwily/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tonybaloney%2Fwily/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tonybaloney%2Fwily/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/tonybaloney","download_url":"https://codeload.github.com/tonybaloney/wily/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tonybaloney%2Fwily/sbom","scorecard":{"id":893856,"data":{"date":"2025-08-11","repo":{"name":"github.com/tonybaloney/wily","commit":"2590691d5d29a2872cc175bdb773b1dbf5fde202"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":4.1,"checks":[{"name":"Code-Review","score":8,"reason":"Found 19/23 approved changesets -- score normalized to 8","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Dangerous-Workflow","score":10,"reason":"no dangerous workflow patterns detected","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Token-Permissions","score":0,"reason":"detected GitHub workflow tokens with excessive permissions","details":["Warn: no topLevel permission defined: .github/workflows/ci.yml:1","Info: no jobLevel write permissions found"],"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Pinned-Dependencies","score":0,"reason":"dependency not pinned by hash detected -- score normalized to 0","details":["Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/ci.yml:31: update your workflow using https://app.stepsecurity.io/secureworkflow/tonybaloney/wily/ci.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/ci.yml:32: update your workflow using https://app.stepsecurity.io/secureworkflow/tonybaloney/wily/ci.yml/master?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/ci.yml:43: update your workflow using https://app.stepsecurity.io/secureworkflow/tonybaloney/wily/ci.yml/master?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/ci.yml:47: update your workflow using https://app.stepsecurity.io/secureworkflow/tonybaloney/wily/ci.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/ci.yml:56: update your workflow using https://app.stepsecurity.io/secureworkflow/tonybaloney/wily/ci.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/ci.yml:63: update your workflow using https://app.stepsecurity.io/secureworkflow/tonybaloney/wily/ci.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/ci.yml:64: update your workflow using https://app.stepsecurity.io/secureworkflow/tonybaloney/wily/ci.yml/master?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/ci.yml:72: update your workflow using https://app.stepsecurity.io/secureworkflow/tonybaloney/wily/ci.yml/master?enable=pin","Warn: pipCommand not pinned by hash: .github/workflows/ci.yml:37","Warn: pipCommand not pinned by hash: .github/workflows/ci.yml:38","Warn: pipCommand not pinned by hash: .github/workflows/ci.yml:58","Warn: pipCommand not pinned by hash: .github/workflows/ci.yml:69","Warn: pipCommand not pinned by hash: .github/workflows/ci.yml:70","Info:   0 out of   5 GitHub-owned GitHubAction dependencies pinned","Info:   0 out of   3 third-party GitHubAction dependencies pinned","Info:   0 out of   5 pipCommand dependencies pinned"],"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Info: FSF or OSI recognized license: Apache License 2.0: LICENSE:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":-1,"reason":"internal error: error during branchesHandler.setup: internal error: githubv4.Query: Resource not accessible by integration","details":null,"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"Vulnerabilities","score":5,"reason":"5 existing vulnerabilities detected","details":["Warn: Project is vulnerable to: PYSEC-2024-4 / GHSA-2mqj-m65w-jghx","Warn: Project is vulnerable to: PYSEC-2023-165 / GHSA-cwvm-v4w8-q58c","Warn: Project is vulnerable to: PYSEC-2022-42992 / GHSA-hcpj-qp55-gfph","Warn: Project is vulnerable to: PYSEC-2023-137 / GHSA-pr76-5cm5-w9cj","Warn: Project is vulnerable to: PYSEC-2023-161 / GHSA-wfm5-v35h-vwf4"],"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}},{"name":"SAST","score":0,"reason":"SAST tool is not run on all commits -- score normalized to 0","details":["Warn: 0 commits out of 27 are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}}]},"last_synced_at":"2025-08-24T12:55:25.603Z","repository_id":37431080,"created_at":"2025-08-24T12:55:25.604Z","updated_at":"2025-08-24T12:55:25.604Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":344872684,"owners_count":38357897,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-10-03T21:59:58.778Z","status":"online","status_checked_at":"2026-10-19T02:00:06.414Z","response_time":53,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["complexity","hacktoberfest","hacktoberfest-accepted","python","quality"],"created_at":"2024-07-30T22:01:15.038Z","updated_at":"2026-10-19T13:52:31.174Z","avatar_url":"https://github.com/tonybaloney.png","language":"Python","funding_links":["https://github.com/sponsors/tonybaloney"],"categories":["Python","Debugging \u0026 Profiling \u0026 Tracing","Programming Languages","Code Metrics \u0026 Complexity"],"sub_categories":["For Python"],"readme":"![wily](https://github.com/tonybaloney/wily/raw/master/docs/source/_static/logo.png)\n\nA command-line application for tracking, reporting on complexity of Python tests and applications.\n\n[![Wily](https://img.shields.io/badge/%F0%9F%A6%8A%20wily-passing-brightgreen.svg)](https://wily.readthedocs.io/)\n[![codecov](https://codecov.io/gh/tonybaloney/wily/branch/master/graph/badge.svg)](https://codecov.io/gh/tonybaloney/wily) [![Documentation Status](https://readthedocs.org/projects/wily/badge/?version=latest)](https://wily.readthedocs.io/en/latest/?badge=latest) [![PyPI version](https://badge.fury.io/py/wily.svg)](https://badge.fury.io/py/wily) [![Conda Version](https://img.shields.io/conda/vn/conda-forge/wily.svg)](https://anaconda.org/conda-forge/wily) ![black](https://img.shields.io/badge/code%20style-black-000000.svg) ![PyPI - Downloads](https://img.shields.io/pypi/dm/wily)\n\n```default\nwily [a]:\nquick to think of things, having a very good understanding of situations and possibilities, \nand often willing to use tricks to achieve an aim.\n```\n\nWily uses git to go through each revision (commit) in a branch and run complexity and code-analysis metrics over the code. You can use this to limit your code or report on trends for complexity, length etc.\n\n## Installation\n\nWily can be installed via pip from Python 3.10 and above:\n\n```console\n $ pip install wily\n```\n\nAlternatively, Wily packages are available on conda-forge:\n\n```console\n $ conda install -c conda-forge wily\n```\n\n## Usage\n\nSee the [Documentation Site](https://wily.readthedocs.io/) for full usage guides.\n\nWily can be used via a command line interface, `wily`.\n\n```console\n $ wily --help\n```\n\n![help-screen](https://github.com/tonybaloney/wily/raw/master/docs/source/_static/wily_help.png)\n\n## Demo\n\nHere is a demo of wily analysing a Python project, giving a summary of changes to complexity in the last 10 commits and then showing changes against a specific git revision:\n\n![demo](./docs/source/_static/termtosvg_leo0ur6s.svg)\n\n## Using Wily in a CI/CD pipeline\n\nWily can be used in a CI/CD workflow to compare the complexity of the current files against a particular revision.\n\nBy default, wily will compare against the previous revision (for a git-pre-commit hook) but you can also give a Git ref, for example `HEAD^1` is the commit before the HEAD reference.\n\n```console\n $ wily build src/\n $ wily diff src/ -r HEAD^1\n```\n\nOr, to compare against\n\n```console\n $ wily build src/\n $ wily diff src/ -r master\n```\n\n## pre-commit plugin\n\nYou can install wily as a [pre-commit](http://www.pre-commit.com/) plugin by adding the following to ``.pre-commit-config.yaml``\n\n```yaml\nrepos:\n-   repo: local\n    hooks:\n    -   id: wily\n        name: wily\n        entry: wily diff\n        verbose: true\n        language: python\n        additional_dependencies: [wily]\n```\n\n### Command line usage\n\n#### `wily build`\n\nThe first step to using `wily` is to build a wily cache with the statistics of your project. \n\n```default\nUsage: wily build [OPTIONS] [TARGETS]...\n\n  Build the wily cache\n\nOptions:\n  -n, --max-revisions INTEGER  The maximum number of historical commits to\n                               archive\n  -o, --operators TEXT         List of operators, separated by commas\n  -a, --archiver TEXT          Archiver to use, defaults to git if git repo,\n                               else filesystem\n  --help                       Show this message and exit.\n```\n\nBy default, wily will assume your project folder is a `git` directory. Wily will not build a cache if the working copy is dirty (has changed files not committed).\n\n```console\n $ wily build src/\n ```\n\nLimit the number of revisions (defaults to 50).\n\n![wily-build](https://github.com/tonybaloney/wily/raw/master/docs/source/_static/wily_build.png)\n\n#### `wily report`\n\nShow a specific metric for a given file, requires that `.wily/` exists\n\n`wily report` will print the metric and the delta between each revision.\n\n![wily-report](https://github.com/tonybaloney/wily/raw/master/docs/source/_static/wily_report.png)\n\n#### `wily rank`\n\nShow the ranking for all files in a directory or a single file based on the metric provided, requires that `.wily/` exists\n\n`wily rank` will print a table of files and their metric values.\n\n![wily-rank](https://github.com/tonybaloney/wily/raw/master/docs/source/_static/wily_rank.png)\n\n#### `wily graph`\n\nSimilar to `wily report` but instead of printing in the console, `wily` will print a graph in a browser.\n\n![wily-graph](https://github.com/tonybaloney/wily/raw/master/docs/source/_static/single_metric_graph.png)\n\n#### `wily index`\n\nShow information about the build directory. Requires that `.wily/` exists.\n\n`wily index` will print the configuration to the screen and list all revisions that have been analysed and the operators used.\n\n![wily-graph](https://github.com/tonybaloney/wily/raw/master/docs/source/_static/wily_index.png)\n\n### `wily list-metrics`\n\nList the metrics available in the Wily operators. Each one of the metrics can be used in `wily graph` and `wily report`\n\n```console\n $ wily list-metrics\ncyclomatic operator:\n  complexity  Cyclomatic Complexity (float, AimLow)\nmaintainability operator:\n  rank        Maintainability Ranking (str, Informational)\n  mi          Maintainability Index (float, AimHigh)\nraw operator:\n  loc             Lines of Code (int, Informational)\n  lloc            L Lines of Code (int, AimLow)\n  sloc            S Lines of Code (int, AimLow)\n  comments        Multi-line comments (int, AimHigh)\n  multi           Multi lines (int, Informational)\n  blank           blank lines (int, Informational)\n  single_comments Single comment lines (int, Informational)\nhalstead operator:\n  h1          Unique Operators (int, AimLow)\n  h2          Unique Operands (int, AimLow)\n  N1          Number of Operators (int, AimLow)\n  N2          Number of Operands (int, AimLow)\n  vocabulary  Unique vocabulary (int, AimLow)\n  length      Length of application (int, AimLow)\n  volume      Code volume (float, AimLow)\n  difficulty  Difficulty (float, AimLow)\n  effort      Effort (float, AimLow)\ncognitive operator:\n  cognitive_complexity  Cognitive Complexity (float, AimLow)\n```\n\n## Configuration\n\nYou can put a `wily.cfg` file in your project directory and `wily` will override the runtime settings. Here are the available options:\n\n```ini\n[wily]\n# list of operators, choose from cyclomatic, cognitive, maintainability, halstead and raw\noperators = cyclomatic,raw\n# archiver to use, defaults to git\narchiver = git\n# path to analyse, defaults to .\npath = /path/to/target\n# max revisions to archive, defaults to 50\nmax_revisions = 20\n# override the default cache path\ncache_path = /path/to/cache\n# enable/disable scanning of Jupyter notebooks, defaults to true\ninclude_ipynb = true\n# enable/disable reporting on individual notebook cells, defaults to true\nipynb_cells = true\n```\n\nYou can also override the path to the configuration with the `--config` flag on the command-line.\n\n## IPython/Jupyter Notebooks\n\nWily will detect and scan all Python code in .ipynb files automatically. \n\nYou can disable this behaviour if you require by setting `include_ipynb = false` in the configuration.\nYou can also disable the behaviour of reporting on individual cells by setting `ipynb_cells = false`.\n\n# Credits\n\n## Contributors\n\n- @wcooley (Wil Cooley)\n- @DahlitzFlorian (Florian Dahlitz)\n- @alegonz\n- @DanielChabrowski\n- @jwattier\n- @skarzi\n\n\"cute animal doing dabbing\" [Designed by Freepik](https://www.freepik.com/free-vector/cute-animal-doing-dabbing_2462508.htm)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftonybaloney%2Fwily","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftonybaloney%2Fwily","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftonybaloney%2Fwily/lists"}