{"id":13735005,"url":"https://github.com/jamescooke/flake8-aaa","last_synced_at":"2026-01-14T16:11:10.546Z","repository":{"id":45087385,"uuid":"122377463","full_name":"jamescooke/flake8-aaa","owner":"jamescooke","description":"A Flake8 plugin that checks Python tests follow the Arrange-Act-Assert pattern","archived":false,"fork":false,"pushed_at":"2025-10-24T23:10:26.000Z","size":731,"stargazers_count":72,"open_issues_count":9,"forks_count":6,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-10-24T23:15:58.186Z","etag":null,"topics":["arrange-act-assert","code-quality","flake8-plugin","linter","python","tdd","test-driven-development","testing"],"latest_commit_sha":null,"homepage":"https://flake8-aaa.readthedocs.io/","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/jamescooke.png","metadata":{"files":{"readme":"README.rst","changelog":"CHANGELOG.rst","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":"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}},"created_at":"2018-02-21T18:41:28.000Z","updated_at":"2025-10-24T22:51:22.000Z","dependencies_parsed_at":"2023-09-24T15:30:20.647Z","dependency_job_id":"9c97ad21-1664-4e18-ba21-65179539822c","html_url":"https://github.com/jamescooke/flake8-aaa","commit_stats":{"total_commits":671,"total_committers":3,"mean_commits":"223.66666666666666","dds":"0.010432190760059634","last_synced_commit":"f81917ca937bd8bc93117f010bcf20d89a2a05d7"},"previous_names":[],"tags_count":31,"template":false,"template_full_name":null,"purl":"pkg:github/jamescooke/flake8-aaa","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jamescooke%2Fflake8-aaa","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jamescooke%2Fflake8-aaa/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jamescooke%2Fflake8-aaa/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jamescooke%2Fflake8-aaa/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jamescooke","download_url":"https://codeload.github.com/jamescooke/flake8-aaa/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jamescooke%2Fflake8-aaa/sbom","scorecard":{"id":503708,"data":{"date":"2025-08-11","repo":{"name":"github.com/jamescooke/flake8-aaa","commit":"a9d1a4897f6c6e8cfdd548711c26b2e158d157c2"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":3.8,"checks":[{"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":"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":"Code-Review","score":0,"reason":"Found 0/30 approved changesets -- score normalized to 0","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":"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":"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":"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":"Token-Permissions","score":0,"reason":"detected GitHub workflow tokens with excessive permissions","details":["Warn: no topLevel permission defined: .github/workflows/build.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":"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/build.yml:18: update your workflow using https://app.stepsecurity.io/secureworkflow/jamescooke/flake8-aaa/build.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/build.yml:21: update your workflow using https://app.stepsecurity.io/secureworkflow/jamescooke/flake8-aaa/build.yml/master?enable=pin","Warn: pipCommand not pinned by hash: .github/workflows/build.yml:28","Warn: pipCommand not pinned by hash: .github/workflows/build.yml:29","Info:   0 out of   2 GitHub-owned GitHubAction dependencies pinned","Info:   0 out of   2 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":"Vulnerabilities","score":10,"reason":"0 existing vulnerabilities detected","details":null,"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}},{"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: MIT License: 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":"SAST","score":0,"reason":"SAST tool is not run on all commits -- score normalized to 0","details":["Warn: 0 commits out of 30 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-19T22:42:46.528Z","repository_id":45087385,"created_at":"2025-08-19T22:42:46.528Z","updated_at":"2025-08-19T22:42:46.528Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28425617,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-14T15:24:48.085Z","status":"ssl_error","status_checked_at":"2026-01-14T15:23:41.940Z","response_time":107,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"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":["arrange-act-assert","code-quality","flake8-plugin","linter","python","tdd","test-driven-development","testing"],"created_at":"2024-08-03T03:01:02.023Z","updated_at":"2026-01-14T16:11:10.538Z","avatar_url":"https://github.com/jamescooke.png","language":"Python","funding_links":[],"categories":["Testing"],"sub_categories":[],"readme":"Flake8-AAA\n==========\n\n.. image:: https://img.shields.io/github/actions/workflow/status/jamescooke/flake8-aaa/build.yml?branch=master\n    :alt: GitHub Workflow Status\n    :target: https://github.com/jamescooke/flake8-aaa/actions?query=branch%3Amaster\n\n.. image:: https://img.shields.io/readthedocs/flake8-aaa.svg\n    :alt: Read the Docs\n    :target: https://flake8-aaa.readthedocs.io/\n\n.. image:: https://img.shields.io/pypi/v/flake8-aaa.svg\n    :alt: PyPI\n    :target: https://pypi.org/project/flake8-aaa/\n\n.. image:: https://img.shields.io/pypi/dm/flake8-aaa\n    :alt: PyPI monthly downloads\n    :target: https://pypistats.org/packages/flake8-aaa\n\n.. image:: https://img.shields.io/pypi/pyversions/flake8-aaa.svg\n    :alt: PyPI - Python Version\n    :target: https://pypi.org/project/flake8-aaa/\n\n.. image:: https://img.shields.io/github/license/jamescooke/flake8-aaa.svg\n    :alt: flake8-aaa is licensed under the MIT License\n    :target: https://github.com/jamescooke/flake8-aaa/blob/master/LICENSE\n\n..\n\nA Flake8 plugin that checks Python tests follow the Arrange-Act-Assert pattern.\n\n----------\n\n📝 Table of Contents\n--------------------\n\n* `About \u003c#-about\u003e`_\n* `Getting Started \u003c#-getting-started\u003e`_\n* `Usage \u003c#-usage\u003e`_\n* `Compatibility \u003c#-compatibility\u003e`_\n* `Resources \u003c#-resources\u003e`_\n\n🧐 About\n--------\n\nWhat is the Arrange-Act-Assert pattern?\n.......................................\n\n\"Arrange-Act-Assert\" is a testing pattern that focuses each test on a single\nobject's behaviour. It's also known as \"AAA\" and \"3A\".\n\nAs the name suggests each test is broken down into three distinct parts\nseparated by blank lines:\n\n* **Arrange:** Set up the object to be tested.\n\n* **Act**: Carry out an action on the object.\n\n* **Assert**: Check the expected results have occurred.\n\nFor example, a simple test on the behaviour of add ``+``:\n\n.. code-block:: python\n\n    def test() -\u003e None:\n       x = 1\n       y = 1\n\n       result = x + y\n\n       assert result == 2\n\nAs you can see, the Act block starts with ``result =`` and is separated from\nthe Arrange and Assert blocks by blank lines. The test is focused - it only\ncontains one add operation and no further additions occur.\n\nUsing AAA consistently makes it easier to find the Action in a test. It's\ntherefore always easy to see the object behaviour each test is focused on.\n\nFurther reading:\n\n* `Arrange-Act-Assert: A Pattern for Writing Good Tests\n  \u003chttps://automationpanda.com/2020/07/07/arrange-act-assert-a-pattern-for-writing-good-tests/\u003e`_\n  - a great introduction to AAA from a Python perspective.\n\n* `Anatomy of a test\n  \u003chttps://docs.pytest.org/en/latest/explanation/anatomy.html\u003e`_ - a\n  description of Arrange Act Assert in the Pytest documentation.\n\n* `Arrange Act Assert pattern for Python developers\n  \u003chttps://jamescooke.info/arrange-act-assert-pattern-for-python-developers.html\u003e`_\n  - information about the pattern and each part of a test.\n\n* `Our \"good\" example files\n  \u003chttps://github.com/jamescooke/flake8-aaa/tree/master/examples/good\u003e`_ -\n  test examples used in the Flake8-AAA test suite.\n\nWhat is Flake8?\n...............\n\nFlake8 is a command line utility for enforcing style consistency across Python\nprojects. It wraps multiple style checking tools and also runs third-party\nchecks provided by plugins, of which Flake8-AAA is one.\n\nFurther reading:\n\n* `Flake8's documentation \u003chttps://flake8.pycqa.org/en/latest/\u003e`_.\n\n* `Awesome Flake8 Extensions\n  \u003chttps://github.com/DmytroLitvinov/awesome-flake8-extensions/\u003e`_ - a curated\n  list of Flake8 plugins.\n\nWhat does Flake8-AAA do?\n........................\n\nFlake8-AAA extends Flake8 to check your Python tests match the AAA pattern.\n\nIt does this by adding the following checks to Flake8:\n\n* Every test has a single clear Act block.\n\n* Every Act block is distinguished from the code around it with a blank line\n  above and below.\n\n* Arrange and Assert blocks do not contain additional blank lines.\n\nIn the future, Flake8-AAA will check that no test has become too complicated\nand that Arrange blocks do not contain assertions.\n\nChecking your code with these simple formatting rules helps you write simple,\nconsistently formatted tests that match the AAA pattern. They are most helpful\nif you call Flake8 regularly, for example when you save a file or before you\nrun a test suite.\n\nFurther reading:\n\n* `Error codes documentation\n  \u003chttps://flake8-aaa.readthedocs.io/en/stable/error_codes/all.html\u003e`_: A list\n  of error codes raised by Flake8-AAA when a test doesn't match the AAA\n  pattern.\n\n🏁 Getting Started\n------------------\n\nInstallation\n............\n\nInstall ``flake8-aaa``:\n\n.. code-block:: shell\n\n    pip install flake8-aaa\n\nThis will install Flake8-AAA and its dependencies, which include Flake8.\n\nYou can confirm that Flake8 recognises the plugin by checking its version\nstring:\n\n.. code-block:: shell\n\n    flake8 --version\n\n.. code-block::\n\n    7.3.0 (flake8-aaa: 0.17.2, mccabe: 0.7.0, pycodestyle: 2.14.0, pyflakes: 3.4.0) CPython 3.14.0 on Linux\n\nThe ``flake8-aaa: 0.17.2`` part tells you that Flake8-AAA was installed\nsuccessfully and its checks will be used by Flake8.\n\nFurther reading:\n\n* `Flake8 installation instructions\n  \u003chttps://flake8.pycqa.org/en/latest/index.html#installation-guide\u003e`_.\n\nFirst run\n.........\n\nLet's check the good example from above. We expect Flake8 to return no errors:\n\n.. code-block:: shell\n\n    curl https://raw.githubusercontent.com/jamescooke/flake8-aaa/master/examples/good/test_example.py \u003e test_example.py\n    flake8 test_example.py\n\nSilence - just what we wanted.\n\nNow let's see a failure from Flake8-AAA. We can use a bad example:\n\n.. code-block:: shell\n\n    curl https://raw.githubusercontent.com/jamescooke/flake8-aaa/master/examples/bad/test.py \u003e test.py\n    flake8 test.py\n\n.. code-block::\n\n    test.py:4:1: AAA01 no Act block found in test\n\n🎈 Usage\n--------\n\nSince Flake8-AAA is a Flake8 plugin, the majority of its usage is\ndependent on how you use Flake8. In general you can point it at your source\ncode and test suite:\n\n.. code-block:: shell\n\n    flake8 src tests\n\nIf you're not already using Flake8 then you might consider:\n\n* Adding a hook to your code editor to run Flake8 when you save a file.\n\n* Adding a pre-commit hook to your source code manager to run Flake8 before you\n  commit.\n\n* Running Flake8 before you execute your test suite - locally or in CI.\n\nIf you just want Flake8-AAA error messages you can filter errors returned by\nFlake8 with ``--select``:\n\n.. code-block:: shell\n\n    flake8 --select AAA tests\n\nFurther reading:\n\n* `Flake8-AAA options and configuration\n  \u003chttps://flake8-aaa.readthedocs.io/en/stable/options.html\u003e`_.\n\n* `Using Flake8 \u003chttps://flake8.pycqa.org/en/stable/user/index.html\u003e`_.\n\n⛏️ Compatibility\n----------------\n\nFlake8-AAA works with:\n\n* Pytest and unittest test suites.\n\n* Black and yapf formatted code.\n\n* Mypy and type-annotated code.\n\n* Active versions of Python 3 as listed on the `python.org downloads page\n  \u003chttps://www.python.org/downloads/\u003e`_.\n\nFurther reading:\n\n* `Full compatibility list\n  \u003chttps://flake8-aaa.readthedocs.io/en/stable/compatibility.html\u003e`_ - includes\n  how to configure Flake8-AAA to work with Black and information on support for\n  older versions of Python.\n\n📕 Resources\n------------\n\n* `Documentation on ReadTheDocs \u003chttps://flake8-aaa.readthedocs.io/\u003e`_\n\n* `Package on PyPI \u003chttps://pypi.org/project/flake8-aaa/\u003e`_\n\n* `Source code on GitHub \u003chttps://github.com/jamescooke/flake8-aaa\u003e`_\n\n* `Licensed on MIT \u003chttps://github.com/jamescooke/flake8-aaa/blob/master/LICENSE\u003e`_\n\n* `Changelog \u003chttps://github.com/jamescooke/flake8-aaa/blob/master/CHANGELOG.rst\u003e`_\n\n* `#flake8_aaa hashtag on Mastodon \u003chttps://fosstodon.org/tags/flake8_aaa\u003e`_\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjamescooke%2Fflake8-aaa","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjamescooke%2Fflake8-aaa","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjamescooke%2Fflake8-aaa/lists"}