Repository: garyd203/xraysink (language: python)

Issue:
Add more style checking
* [x] find a good tool
* [x] configure for python and run in CI
* [x] configure for yaml and run in CI
* [x] enforce a good import order

Add more style checking
* [x] find a good tool
* [x] configure for python and run in CI
* [x] configure for yaml and run in CI
* [x] enforce a good import order

Add more style checking
* [x] find a good tool
* [x] configure for python and run in CI
* [x] configure for yaml and run in CI
* [x] enforce a good import order

Add more style checking
* [x] find a good tool
* [x] configure for python and run in CI
* [x] configure for yaml and run in CI
* [x] enforce a good import order

Add more style checking
* [x] find a good tool
* [x] configure for python and run in CI
* [x] configure for yaml and run in CI
* [x] enforce a good import order

Add more style checking
* [x] find a good tool
* [x] configure for python and run in CI
* [x] configure for yaml and run in CI
* [x] enforce a good import order

Add more style checking
* [x] find a good tool
* [x] configure for python and run in CI
* [x] configure for yaml and run in CI
* [x] enforce a good import order



Discussion / hints:

Fix patch:
diff --git a/.github/workflows/validation.yaml b/.github/workflows/validation.yaml
index cf2c26e..00a6799 100644
--- a/.github/workflows/validation.yaml
+++ b/.github/workflows/validation.yaml
@@ -30,10 +30,14 @@ jobs:
         poetry-version: ${{ env.POETRY_VERSION }}
     - name: Install Dependencies
       run: |
-        poetry install -E stylecheck
+        poetry install --no-dev -E stylecheck
     - name: Check Formatting
       run: |
+        # NB: Format before style check
         poetry run black --check src tests
+    - name: General Style Checks (Flake8)
+      run: |
+        poetry run flake8 --benchmark
 
   test:
     name: Test (${{ matrix.extra-test-title }}Py${{ matrix.python-version }} ${{ matrix.os-family }} - XRay v${{ matrix.aws-xray-sdk-version }})
diff --git a/poetry.lock b/poetry.lock
index 6ac2dd2..3e54b84 100644
--- a/poetry.lock
+++ b/poetry.lock
@@ -52,6 +52,14 @@ doc = ["packaging", "sphinx-rtd-theme", "sphinx-autodoc-typehints (>=1.2.0)"]
 test = ["coverage[toml] (>=4.5)", "hypothesis (>=4.0)", "pytest (>=6.0)", "pytest-mock (>=3.6.1)", "trustme", "contextlib2", "uvloop (<0.15)", "mock (>=4)", "uvloop (>=0.15)"]
 trio = ["trio (>=0.16)"]
 
+[[package]]
+name = "astor"
+version = "0.8.1"
+description = "Read/rewrite/write Python ASTs"
+category = "main"
+optional = true
+python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,>=2.7"
+
 [[package]]
 name = "async-asgi-testclient"
 version = "1.4.9"
@@ -93,17 +101,17 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
 
 [[package]]
 name = "attrs"
-version = "21.4.0"
+version = "20.3.0"
 description = "Classes Without Boilerplate"
-category = "dev"
+category = "main"
 optional = false
-python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
+python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
 
 [package.extras]
-dev = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins", "zope.interface", "furo", "sphinx", "sphinx-notfound-page", "pre-commit", "cloudpickle"]
-docs = ["furo", "sphinx", "zope.interface", "sphinx-notfound-page"]
-tests = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins", "zope.interface", "cloudpickle"]
-tests_no_zope = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins", "cloudpickle"]
+dev = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "zope.interface", "furo", "sphinx", "pre-commit"]
+docs = ["furo", "sphinx", "zope.interface"]
+tests = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "zope.interface"]
+tests_no_zope = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six"]
 
 [[package]]
 name = "aws-xray-sdk"
@@ -224,6 +232,14 @@ category = "main"
 optional = false
 python-versions = ">=3.6, <3.7"
 
+[[package]]
+name = "eradicate"
+version = "2.0.0"
+description = "Removes commented-out code."
+category = "main"
+optional = true
+python-versions = "*"
+
 [[package]]
 name = "fastapi"
 version = "0.73.0"
@@ -242,6 +258,188 @@ dev = ["python-jose[cryptography] (>=3.3.0,<4.0.0)", "passlib[bcrypt] (>=1.7.2,<
 doc = ["mkdocs (>=1.1.2,<2.0.0)", "mkdocs-material (>=8.1.4,<9.0.0)", "mdx-include (>=1.4.1,<2.0.0)", "mkdocs-markdownextradata-plugin (>=0.1.7,<0.3.0)", "typer-cli (>=0.0.12,<0.0.13)", "pyyaml (>=5.3.1,<6.0.0)"]
 test = ["pytest (>=6.2.4,<7.0.0)", "pytest-cov (>=2.12.0,<4.0.0)", "mypy (==0.910)", "flake8 (>=3.8.3,<4.0.0)", "black (==21.9b0)", "isort (>=5.0.6,<6.0.0)", "requests (>=2.24.0,<3.0.0)", "httpx (>=0.14.0,<0.19.0)", "email_validator (>=1.1.1,<2.0.0)", "sqlalchemy (>=1.3.18,<1.5.0)", "peewee (>=3.13.3,<4.0.0)", "databases[sqlite] (>=0.3.2,<0.6.0)", "orjson (>=3.2.1,<4.0.0)", "ujson (>=4.0.1,<5.0.0)", "python-multipart (>=0.0.5,<0.0.6)", "flask (>=1.1.2,<3.0.0)", "anyio[trio] (>=3.2.1,<4.0.0)", "types-ujson (==0.1.1)", "types-orjson (==3.6.0)", "types-dataclasses (==0.1.7)"]
 
+[[package]]
+name = "flake8"
+version = "4.0.1"
+description = "the modular source code checker: pep8 pyflakes and co"
+category = "main"
+optional = true
+python-versions = ">=3.6"
+
+[package.dependencies]
+importlib-metadata = {version = "<4.3", markers = "python_version < \"3.8\""}
+mccabe = ">=0.6.0,<0.7.0"
+pycodestyle = ">=2.8.0,<2.9.0"
+pyflakes = ">=2.4.0,<2.5.0"
+
+[[package]]
+name = "flake8-bugbear"
+version = "22.1.11"
+description = "A plugin for flake8 finding likely bugs and design problems in your program. Contains warnings that don't belong in pyflakes and pycodestyle."
+category = "main"
+optional = true
+python-versions = ">=3.6"
+
+[package.dependencies]
+attrs = ">=19.2.0"
+flake8 = ">=3.0.0"
+
+[package.extras]
+dev = ["coverage", "hypothesis", "hypothesmith (>=0.2)", "pre-commit"]
+
+[[package]]
+name = "flake8-builtins"
+version = "1.5.3"
+description = "Check for python builtins being used as variables or parameters."
+category = "main"
+optional = true
+python-versions = "*"
+
+[package.dependencies]
+flake8 = "*"
+
+[package.extras]
+test = ["coverage", "coveralls", "mock", "pytest", "pytest-cov"]
+
+[[package]]
+name = "flake8-comprehensions"
+version = "3.8.0"
+description = "A flake8 plugin to help you write better list/set/dict comprehensions."
+category = "main"
+optional = true
+python-versions = ">=3.7"
+
+[package.dependencies]
+flake8 = ">=3.0,<3.2.0 || >3.2.0"
+importlib-metadata = {version = "*", markers = "python_version < \"3.8\""}
+
+[[package]]
+name = "flake8-eradicate"
+version = "1.2.0"
+description = "Flake8 plugin to find commented out code"
+category = "main"
+optional = true
+python-versions = ">=3.6,<4.0"
+
+[package.dependencies]
+attrs = "*"
+eradicate = ">=2.0,<3.0"
+flake8 = ">=3.5,<5"
+
+[[package]]
+name = "flake8-executable"
+version = "2.1.1"
+description = "A Flake8 plugin for checking executable permissions and shebangs."
+category = "main"
+optional = true
+python-versions = ">=3.6"
+
+[package.dependencies]
+flake8 = ">=3.0.0"
+
+[[package]]
+name = "flake8-implicit-str-concat"
+version = "0.2.0"
+description = "Flake8 plugin to encourage correct string literal concatenation."
+category = "main"
+optional = true
+python-versions = "~=3.6"
+
+[package.dependencies]
+attrs = ">=19.3,<21"
+more-itertools = ">=8.0.2,<9"
+
+[[package]]
+name = "flake8-import-order"
+version = "0.18.1"
+description = "Flake8 and pylama plugin that checks the ordering of import statements."
+category = "main"
+optional = true
+python-versions = "*"
+
+[package.dependencies]
+pycodestyle = "*"
+
+[[package]]
+name = "flake8-logging-format"
+version = "0.6.0"
+description = "Flake8 extension to validate (lack of) logging format strings"
+category = "main"
+optional = true
+python-versions = "*"
+
+[[package]]
+name = "flake8-plugin-utils"
+version = "1.3.2"
+description = "The package provides base classes and utils for flake8 plugin writing"
+category = "main"
+optional = true
+python-versions = ">=3.6,<4.0"
+
+[[package]]
+name = "flake8-print"
+version = "4.0.0"
+description = "print statement checker plugin for flake8"
+category = "main"
+optional = true
+python-versions = ">=3.6"
+
+[package.dependencies]
+flake8 = ">=3.0"
+pycodestyle = "*"
+six = "*"
+
+[[package]]
+name = "flake8-pytest-style"
+version = "1.6.0"
+description = "A flake8 plugin checking common style issues or inconsistencies with pytest-based tests."
+category = "main"
+optional = true
+python-versions = ">=3.6.2,<4.0.0"
+
+[package.dependencies]
+flake8-plugin-utils = ">=1.3.2,<2.0.0"
+
+[[package]]
+name = "flake8-simplify"
+version = "0.18.0"
+description = "flake8 plugin which checks for code that can be simplified"
+category = "main"
+optional = true
+python-versions = ">=3.6.1"
+
+[package.dependencies]
+astor = ">=0.1"
+flake8 = ">=3.7"
+importlib-metadata = {version = ">=0.9", markers = "python_version < \"3.8\""}
+
+[[package]]
+name = "flake8-string-format"
+version = "0.3.0"
+description = "string format checker, plugin for flake8"
+category = "main"
+optional = true
+python-versions = "*"
+
+[package.dependencies]
+flake8 = "*"
+
+[[package]]
+name = "flake8-use-fstring"
+version = "1.3"
+description = "Flake8 plugin for string formatting style."
+category = "main"
+optional = true
+python-versions = ">=3.6"
+
+[package.dependencies]
+flake8 = ">=3"
+
+[package.extras]
+ci = ["coverage (>=4.0.0,<5.0.0)", "pytest (>=4)", "pytest-cov (>=2)", "flake8-builtins", "flake8-commas", "flake8-fixme", "flake8-print", "flake8-quotes", "flake8-todo", "coveralls"]
+dev = ["coverage (>=4.0.0,<5.0.0)", "pytest (>=4)", "pytest-cov (>=2)", "flake8-builtins", "flake8-commas", "flake8-fixme", "flake8-print", "flake8-quotes", "flake8-todo"]
+test = ["coverage (>=4.0.0,<5.0.0)", "pytest (>=4)", "pytest-cov (>=2)", "flake8-builtins", "flake8-commas", "flake8-fixme", "flake8-print", "flake8-quotes", "flake8-todo"]
+
 [[package]]
 name = "frozenlist"
 version = "1.2.0"
@@ -293,7 +491,7 @@ test = ["flake8 (>=3.8.4,<3.9.0)", "pycodestyle (>=2.6.0,<2.7.0)", "mypy (>=0.91
 
 [[package]]
 name = "importlib-metadata"
-version = "4.8.3"
+version = "4.2.0"
 description = "Read metadata from Python packages"
 category = "main"
 optional = false
@@ -305,8 +503,7 @@ zipp = ">=0.5"
 
 [package.extras]
 docs = ["sphinx", "jaraco.packaging (>=8.2)", "rst.linker (>=1.9)"]
-perf = ["ipython"]
-testing = ["pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest-cov", "pytest-enabler (>=1.0.1)", "packaging", "pep517", "pyfakefs", "flufl.flake8", "pytest-perf (>=0.9.2)", "pytest-black (>=0.3.7)", "pytest-mypy", "importlib-resources (>=1.3)"]
+testing = ["pytest (>=4.6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest-cov", "pytest-enabler (>=1.0.1)", "packaging", "pep517", "pyfakefs", "flufl.flake8", "pytest-black (>=0.3.7)", "pytest-mypy", "importlib-resources (>=1.3)"]
 
 [[package]]
 name = "iniconfig"
@@ -324,6 +521,22 @@ category = "main"
 optional = false
 python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*"
 
+[[package]]
+name = "mccabe"
+version = "0.6.1"
+description = "McCabe checker, plugin for flake8"
+category = "main"
+optional = true
+python-versions = "*"
+
+[[package]]
+name = "more-itertools"
+version = "8.12.0"
+description = "More routines for operating on iterables, beyond itertools"
+category = "main"
+optional = true
+python-versions = ">=3.5"
+
 [[package]]
 name = "multidict"
 version = "5.2.0"
@@ -394,6 +607,14 @@ category = "dev"
 optional = false
 python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
 
+[[package]]
+name = "pycodestyle"
+version = "2.8.0"
+description = "Python style guide checker"
+category = "main"
+optional = true
+python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
+
 [[package]]
 name = "pydantic"
 version = "1.9.0"
@@ -410,6 +631,14 @@ typing-extensions = ">=3.7.4.3"
 dotenv = ["python-dotenv (>=0.10.4)"]
 email = ["email-validator (>=1.0.3)"]
 
+[[package]]
+name = "pyflakes"
+version = "2.4.0"
+description = "passive checker of Python programs"
+category = "main"
+optional = true
+python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
+
 [[package]]
 name = "pyparsing"
 version = "3.0.7"
@@ -579,6 +808,19 @@ idna = ">=2.0"
 multidict = ">=4.0"
 typing-extensions = {version = ">=3.7.4", markers = "python_version < \"3.8\""}
 
+[[package]]
+name = "zimports"
+version = "0.5.0"
+description = "Yet another import fixing tool"
+category = "main"
+optional = true
+python-versions = ">=3.7"
+
+[package.dependencies]
+flake8-import-order = "*"
+pyflakes = "*"
+tomli = "*"
+
 [[package]]
 name = "zipp"
 version = "3.6.0"
@@ -592,12 +834,12 @@ docs = ["sphinx", "jaraco.packaging (>=8.2)", "rst.linker (>=1.9)"]
 testing = ["pytest (>=4.6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest-cov", "pytest-enabler (>=1.0.1)", "jaraco.itertools", "func-timeout", "pytest-black (>=0.3.7)", "pytest-mypy"]
 
 [extras]
-stylecheck = ["black"]
+stylecheck = ["black", "flake8", "flake8-bugbear", "flake8-builtins", "flake8-comprehensions", "flake8-eradicate", "flake8-executable", "flake8-implicit-str-concat", "flake8-import-order", "flake8-logging-format", "flake8-print", "flake8-pytest-style", "flake8-simplify", "flake8-string-format", "flake8-use-fstring", "zimports"]
 
 [metadata]
 lock-version = "1.1"
 python-versions = "^3.6.2"
-content-hash = "9e9ce17a6dd02a023cf083a701a92380c617efb217660027f657d8bab7aa2a59"
+content-hash = "6c0a5a04c40e332051741495f31a02b7242dd27f4332fd6233b70598c0431c00"
 
 [metadata.files]
 aiohttp = [
@@ -682,6 +924,10 @@ anyio = [
     {file = "anyio-3.5.0-py3-none-any.whl", hash = "sha256:b5fa16c5ff93fa1046f2eeb5bbff2dad4d3514d6cda61d02816dba34fa8c3c2e"},
     {file = "anyio-3.5.0.tar.gz", hash = "sha256:a0aeffe2fb1fdf374a8e4b471444f0f3ac4fb9f5a5b542b48824475e0042a5a6"},
 ]
+astor = [
+    {file = "astor-0.8.1-py2.py3-none-any.whl", hash = "sha256:070a54e890cefb5b3739d19f30f5a5ec840ffc9c50ffa7d23cc9fc1a38ebbfc5"},
+    {file = "astor-0.8.1.tar.gz", hash = "sha256:6a6effda93f4e1ce9f618779b2dd1d9d84f1e32812c23a29b3fff6fd7f63fa5e"},
+]
 async-asgi-testclient = [
     {file = "async-asgi-testclient-1.4.9.tar.gz", hash = "sha256:ae507f44a53699611cff81ad548090dad24055fba02cce398e1ca9b84d1e1288"},
 ]
@@ -698,8 +944,8 @@ atomicwrites = [
     {file = "atomicwrites-1.4.0.tar.gz", hash = "sha256:ae70396ad1a434f9c7046fd2dd196fc04b12f9e91ffb859164193be8b6168a7a"},
 ]
 attrs = [
-    {file = "attrs-21.4.0-py2.py3-none-any.whl", hash = "sha256:2d27e3784d7a565d36ab851fe94887c5eccd6a463168875832a1be79c82828b4"},
-    {file = "attrs-21.4.0.tar.gz", hash = "sha256:626ba8234211db98e869df76230a137c4c40a12d72445c45d5f5b716f076e2fd"},
+    {file = "attrs-20.3.0-py2.py3-none-any.whl", hash = "sha256:31b2eced602aa8423c2aea9c76a724617ed67cf9513173fd3a4f03e3a929c7e6"},
+    {file = "attrs-20.3.0.tar.gz", hash = "sha256:832aa3cde19744e49938b91fea06d69ecb9e649c93ba974535d08ad92164f700"},
 ]
 aws-xray-sdk = [
     {file = "aws-xray-sdk-2.9.0.tar.gz", hash = "sha256:b0cd972db218d4d8f7b53ad806fc6184626b924c4997ae58fc9f2a8cd1281568"},
@@ -761,10 +1007,71 @@ dataclasses = [
     {file = "dataclasses-0.8-py3-none-any.whl", hash = "sha256:0201d89fa866f68c8ebd9d08ee6ff50c0b255f8ec63a71c16fda7af82bb887bf"},
     {file = "dataclasses-0.8.tar.gz", hash = "sha256:8479067f342acf957dc82ec415d355ab5edb7e7646b90dc6e2fd1d96ad084c97"},
 ]
+eradicate = [
+    {file = "eradicate-2.0.0.tar.gz", hash = "sha256:27434596f2c5314cc9b31410c93d8f7e8885747399773cd088d3adea647a60c8"},
+]
 fastapi = [
     {file = "fastapi-0.73.0-py3-none-any.whl", hash = "sha256:f0a618aff5f6942862f2d3f20f39b1c037e33314d1b8207fd1c3a2cca76dfd8c"},
     {file = "fastapi-0.73.0.tar.gz", hash = "sha256:dcfee92a7f9a72b5d4b7ca364bd2b009f8fc10d95ed5769be20e94f39f7e5a15"},
 ]
+flake8 = [
+    {file = "flake8-4.0.1-py2.py3-none-any.whl", hash = "sha256:479b1304f72536a55948cb40a32dce8bb0ffe3501e26eaf292c7e60eb5e0428d"},
+    {file = "flake8-4.0.1.tar.gz", hash = "sha256:806e034dda44114815e23c16ef92f95c91e4c71100ff52813adf7132a6ad870d"},
+]
+flake8-bugbear = [
+    {file = "flake8-bugbear-22.1.11.tar.gz", hash = "sha256:4c2a4136bd4ecb8bf02d5159af302ffc067642784c9d0488b33ce4610da825ee"},
+    {file = "flake8_bugbear-22.1.11-py3-none-any.whl", hash = "sha256:ce7ae44aaaf67ef192b8a6de94a5ac617144e1675ad0654fdea556f48dc18d9b"},
+]
+flake8-builtins = [
+    {file = "flake8-builtins-1.5.3.tar.gz", hash = "sha256:09998853b2405e98e61d2ff3027c47033adbdc17f9fe44ca58443d876eb00f3b"},
+    {file = "flake8_builtins-1.5.3-py2.py3-none-any.whl", hash = "sha256:7706babee43879320376861897e5d1468e396a40b8918ed7bccf70e5f90b8687"},
+]
+flake8-comprehensions = [
+    {file = "flake8-comprehensions-3.8.0.tar.gz", hash = "sha256:8e108707637b1d13734f38e03435984f6b7854fa6b5a4e34f93e69534be8e521"},
+    {file = "flake8_comprehensions-3.8.0-py3-none-any.whl", hash = "sha256:9406314803abe1193c064544ab14fdc43c58424c0882f6ff8a581eb73fc9bb58"},
+]
+flake8-eradicate = [
+    {file = "flake8-eradicate-1.2.0.tar.gz", hash = "sha256:acaa1b6839ff00d284b805c432fdfa6047262bd15a5504ec945797e87b4de1fa"},
+    {file = "flake8_eradicate-1.2.0-py3-none-any.whl", hash = "sha256:51dc660d0c1c1ed93af0f813540bbbf72ab2d3466c14e3f3bac371c618b6042f"},
+]
+flake8-executable = [
+    {file = "flake8-executable-2.1.1.tar.gz", hash = "sha256:c6230a089ad49dbeef049d8e1e89591d9823f06c829cd9d6b1ca83b4b1d7f54f"},
+    {file = "flake8_executable-2.1.1-py3-none-any.whl", hash = "sha256:c1df78bf4eff1b75bff0a3d29609d096d61ccfd703a4a9485019af9a640d6e2b"},
+]
+flake8-implicit-str-concat = [
+    {file = "flake8_implicit_str_concat-0.2.0-py2.py3-none-any.whl", hash = "sha256:ea856c22cd8dbd4ecb8d091e92784ce09a3083f1763df895693bf887d21acef5"},
+    {file = "flake8_implicit_str_concat-0.2.0.tar.gz", hash = "sha256:a662364c0389a14f5c94a807eda3ac81ab545ba8d75aa244c022af4a7b121eec"},
+]
+flake8-import-order = [
+    {file = "flake8-import-order-0.18.1.tar.gz", hash = "sha256:a28dc39545ea4606c1ac3c24e9d05c849c6e5444a50fb7e9cdd430fc94de6e92"},
+    {file = "flake8_import_order-0.18.1-py2.py3-none-any.whl", hash = "sha256:90a80e46886259b9c396b578d75c749801a41ee969a235e163cfe1be7afd2543"},
+]
+flake8-logging-format = [
+    {file = "flake8-logging-format-0.6.0.tar.gz", hash = "sha256:ca5f2b7fc31c3474a0aa77d227e022890f641a025f0ba664418797d979a779f8"},
+]
+flake8-plugin-utils = [
+    {file = "flake8-plugin-utils-1.3.2.tar.gz", hash = "sha256:20fa2a8ca2decac50116edb42e6af0a1253ef639ad79941249b840531889c65a"},
+    {file = "flake8_plugin_utils-1.3.2-py3-none-any.whl", hash = "sha256:1fe43e3e9acf3a7c0f6b88f5338cad37044d2f156c43cb6b080b5f9da8a76f06"},
+]
+flake8-print = [
+    {file = "flake8-print-4.0.0.tar.gz", hash = "sha256:5afac374b7dc49aac2c36d04b5eb1d746d72e6f5df75a6ecaecd99e9f79c6516"},
+    {file = "flake8_print-4.0.0-py3-none-any.whl", hash = "sha256:6c0efce658513169f96d7a24cf136c434dc711eb00ebd0a985eb1120103fe584"},
+]
+flake8-pytest-style = [
+    {file = "flake8-pytest-style-1.6.0.tar.gz", hash = "sha256:c1175713e9e11b78cd1a035ed0bca0d1e41d09c4af329a952750b61d4194ddac"},
+    {file = "flake8_pytest_style-1.6.0-py3-none-any.whl", hash = "sha256:5fedb371a950e9fe0e0e6bfc854be7d99151271208f34cd2cc517681ece27780"},
+]
+flake8-simplify = [
+    {file = "flake8_simplify-0.18.0-py3-none-any.whl", hash = "sha256:051977c37f4b5e2e63409987749f4f53a591aa8cfbc95619dcbb826636fdd72c"},
+    {file = "flake8_simplify-0.18.0.tar.gz", hash = "sha256:da05be5b90033b2eedb13f47af7c430be36a70d47659e8f9f069fcce12183d8e"},
+]
+flake8-string-format = [
+    {file = "flake8-string-format-0.3.0.tar.gz", hash = "sha256:65f3da786a1461ef77fca3780b314edb2853c377f2e35069723348c8917deaa2"},
+    {file = "flake8_string_format-0.3.0-py2.py3-none-any.whl", hash = "sha256:812ff431f10576a74c89be4e85b8e075a705be39bc40c4b4278b5b13e2afa9af"},
+]
+flake8-use-fstring = [
+    {file = "flake8-use-fstring-1.3.tar.gz", hash = "sha256:1bd4a409adbb93e64e711fdd26b88759c33792e3899f174edc68ddf7307e81b6"},
+]
 frozenlist = [
     {file = "frozenlist-1.2.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:977a1438d0e0d96573fd679d291a1542097ea9f4918a8b6494b06610dfeefbf9"},
     {file = "frozenlist-1.2.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:a8d86547a5e98d9edd47c432f7a14b0c5592624b496ae9880fb6332f34af1edc"},
@@ -879,8 +1186,8 @@ immutables = [
     {file = "immutables-0.16.tar.gz", hash = "sha256:d67e86859598eed0d926562da33325dac7767b7b1eff84e232c22abea19f4360"},
 ]
 importlib-metadata = [
-    {file = "importlib_metadata-4.8.3-py3-none-any.whl", hash = "sha256:65a9576a5b2d58ca44d133c42a241905cc45e34d2c06fd5ba2bafa221e5d7b5e"},
-    {file = "importlib_metadata-4.8.3.tar.gz", hash = "sha256:766abffff765960fcc18003801f7044eb6755ffae4521c8e8ce8e83b9c9b0668"},
+    {file = "importlib_metadata-4.2.0-py3-none-any.whl", hash = "sha256:057e92c15bc8d9e8109738a48db0ccb31b4d9d5cfbee5a8670879a30be66304b"},
+    {file = "importlib_metadata-4.2.0.tar.gz", hash = "sha256:b7e52a1f8dec14a75ea73e0891f3060099ca1d8e6a462a4dff11c3e119ea1b31"},
 ]
 iniconfig = [
     {file = "iniconfig-1.1.1-py2.py3-none-any.whl", hash = "sha256:011e24c64b7f47f6ebd835bb12a743f2fbe9a26d4cecaa7f53bc4f35ee9da8b3"},
@@ -890,6 +1197,14 @@ jmespath = [
     {file = "jmespath-0.10.0-py2.py3-none-any.whl", hash = "sha256:cdf6525904cc597730141d61b36f2e4b8ecc257c420fa2f4549bac2c2d0cb72f"},
     {file = "jmespath-0.10.0.tar.gz", hash = "sha256:b85d0567b8666149a93172712e68920734333c0ce7e89b78b3e987f71e5ed4f9"},
 ]
+mccabe = [
+    {file = "mccabe-0.6.1-py2.py3-none-any.whl", hash = "sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42"},
+    {file = "mccabe-0.6.1.tar.gz", hash = "sha256:dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f"},
+]
+more-itertools = [
+    {file = "more-itertools-8.12.0.tar.gz", hash = "sha256:7dc6ad46f05f545f900dd59e8dfb4e84a4827b97b3cfecb175ea0c7d247f6064"},
+    {file = "more_itertools-8.12.0-py3-none-any.whl", hash = "sha256:43e6dd9942dffd72661a2c4ef383ad7da1e6a3e968a927ad7a6083ab410a688b"},
+]
 multidict = [
     {file = "multidict-5.2.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:3822c5894c72e3b35aae9909bef66ec83e44522faf767c0ad39e0e2de11d3b55"},
     {file = "multidict-5.2.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:28e6d883acd8674887d7edc896b91751dc2d8e87fbdca8359591a13872799e4e"},
@@ -988,6 +1303,10 @@ py = [
     {file = "py-1.11.0-py2.py3-none-any.whl", hash = "sha256:607c53218732647dff4acdfcd50cb62615cedf612e72d1724fb1a0cc6405b378"},
     {file = "py-1.11.0.tar.gz", hash = "sha256:51c75c4126074b472f746a24399ad32f6053d1b34b68d2fa41e558e6f4a98719"},
 ]
+pycodestyle = [
+    {file = "pycodestyle-2.8.0-py2.py3-none-any.whl", hash = "sha256:720f8b39dde8b293825e7ff02c475f3077124006db4f440dcbc9a20b76548a20"},
+    {file = "pycodestyle-2.8.0.tar.gz", hash = "sha256:eddd5847ef438ea1c7870ca7eb78a9d47ce0cdb4851a5523949f2601d0cbbe7f"},
+]
 pydantic = [
     {file = "pydantic-1.9.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:cb23bcc093697cdea2708baae4f9ba0e972960a835af22560f6ae4e7e47d33f5"},
     {file = "pydantic-1.9.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:1d5278bd9f0eee04a44c712982343103bba63507480bfd2fc2790fa70cd64cf4"},
@@ -1025,6 +1344,10 @@ pydantic = [
     {file = "pydantic-1.9.0-py3-none-any.whl", hash = "sha256:085ca1de245782e9b46cefcf99deecc67d418737a1fd3f6a4f511344b613a5b3"},
     {file = "pydantic-1.9.0.tar.gz", hash = "sha256:742645059757a56ecd886faf4ed2441b9c0cd406079c2b4bee51bcc3fbcd510a"},
 ]
+pyflakes = [
+    {file = "pyflakes-2.4.0-py2.py3-none-any.whl", hash = "sha256:3bb3a3f256f4b7968c9c788781e4ff07dce46bdf12339dcda61053375426ee2e"},
+    {file = "pyflakes-2.4.0.tar.gz", hash = "sha256:05a85c2872edf37a4ed30b0cce2f6093e1d0581f8c19d7393122da7e25b2b24c"},
+]
 pyparsing = [
     {file = "pyparsing-3.0.7-py3-none-any.whl", hash = "sha256:a6c06a88f252e6c322f65faf8f418b16213b51bdfaece0524c1c1bc30c63c484"},
     {file = "pyparsing-3.0.7.tar.gz", hash = "sha256:18ee9022775d270c55187733956460083db60b37d0d0fb357445f3094eed3eea"},
@@ -1222,6 +1545,10 @@ yarl = [
     {file = "yarl-1.7.2-cp39-cp39-win_amd64.whl", hash = "sha256:797c2c412b04403d2da075fb93c123df35239cd7b4cc4e0cd9e5839b73f52c58"},
     {file = "yarl-1.7.2.tar.gz", hash = "sha256:45399b46d60c253327a460e99856752009fcee5f5d3c80b2f7c0cae1c38d56dd"},
 ]
+zimports = [
+    {file = "zimports-0.5.0-py3-none-any.whl", hash = "sha256:cb9bff86e44489082dca97c5a62de49c9d84e7afb937fcd0f92e6b1dc5311faa"},
+    {file = "zimports-0.5.0.tar.gz", hash = "sha256:ce1d4cf7b9c642c2391d24b7075fcd29f40348440c9c74e371b4dfefd405e04f"},
+]
 zipp = [
     {file = "zipp-3.6.0-py3-none-any.whl", hash = "sha256:9fe5ea21568a0a70e50f273397638d39b03353731e6cbbb3fd8502a33fec40bc"},
     {file = "zipp-3.6.0.tar.gz", hash = "sha256:71c644c5369f4a6e07636f0aa966270449561fcea2e3d6747b8d23efaa9d7832"},
diff --git a/pyproject.toml b/pyproject.toml
index 89d7b37..fe57244 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -3,6 +3,11 @@ line-length = 88
 target-version = ["py36", "py37", "py38", "py39", "py310"]
 skip-magic-trailing-comma = true
 
+
+[tool.zimports]
+black-line-length = 88
+
+
 [tool.poetry]
 name = "xraysink"
 version = "1.5.0-beta"
@@ -42,7 +47,22 @@ packages = [
 python = "^3.6.2"
 aws_xray_sdk = "~2"
 black = { version = "==22.1.0", optional = true }
+flake8 = { version = "~4", optional = true }
 wrapt = "^1.11"
+flake8-bugbear = { version = ">=22.1.11", optional = true }
+flake8-builtins = { version = "~1.5", optional = true }
+flake8-comprehensions = { version = "~3.8", markers = "python_version >= '3.7'", optional = true }
+flake8-eradicate = { version = "~1.2", optional = true }
+flake8-executable = { version = "~2.1", optional = true }
+flake8-implicit-str-concat = { version = "~0.2", optional = true }
+flake8-import-order = { version = "~0.18", optional = true }
+flake8-logging-format = { version = "~0.6", optional = true }
+flake8-pytest-style = { version = "~1.6", optional = true }
+flake8-print = { version = "~4", optional = true }
+flake8-simplify = { version = "~0.18", optional = true }
+flake8-string-format = { version = "~0.3", optional = true }
+flake8-use-fstring = { version = "~1.3", optional = true }
+zimports = { version = "~0.5", markers = "python_version >= '3.7'", optional = true }
 
 [tool.poetry.dev-dependencies]
 pytest = "^7"
@@ -54,6 +74,21 @@ fastapi = "^0.73"
 [tool.poetry.extras]
 stylecheck = [
     "black",
+    "flake8",
+    "flake8-bugbear",
+    "flake8-builtins",
+    "flake8-comprehensions",
+    "flake8-eradicate",
+    "flake8-executable",
+    "flake8-implicit-str-concat",
+    "flake8-import-order",
+    "flake8-logging-format",
+    "flake8-print",
+    "flake8-pytest-style",
+    "flake8-simplify",
+    "flake8-string-format",
+    "flake8-use-fstring",
+    "zimports",
 ]
 
 [build-system]
diff --git a/setup.cfg b/setup.cfg
new file mode 100644
index 0000000..cd8925e
--- /dev/null
+++ b/setup.cfg
@@ -0,0 +1,44 @@
+[flake8]
+
+# List the desired plugins to avoid mistakes with installation
+require-plugins = \
+    flake8-bugbear
+    flake8-builtins
+    flake8-comprehensions
+    flake8-eradicate
+    flake8-executable
+    flake8-implicit-str-concat
+    flake8-import-order
+    flake8-logging-format
+    flake8-print
+    flake8-pytest-style
+    flake8-simplify
+    flake8-string-format
+    flake8-use-fstring
+
+# Fine grained control of errors
+extend-select = \
+    # Opt-in to bugbear's opinionated warnings
+    B9
+
+ignore = \
+    # Warnings ignored by default in flake8 v4.0
+    E121
+    E123
+    E126
+    E226
+    W503
+    W504
+
+# Exclude unhelpful directories so we can run with no file argument at all
+exclude =
+    .pytest_cache
+    venv*
+
+# If we're going to care about long lines, let's be reasonable about it
+max-line-length = 99
+max-doc-length = 99
+
+# Imports
+import-order-style = pycharm
+application-import-names = xraysink
diff --git a/src/xraysink/context.py b/src/xraysink/context.py
index 4af87e6..e34da38 100644
--- a/src/xraysink/context.py
+++ b/src/xraysink/context.py
@@ -30,7 +30,7 @@ def _context_aware_task_factory(loop, coro):
         # ordered subsegments). We don't want to share the same entity stack
         # amongst concurrent tasks, because that's just wrong.
         new_context = {"entities": list(current_task.context.get("entities", []))}
-        setattr(task, "context", new_context)
+        task.context = new_context
 
     return task
 
diff --git a/src/xraysink/tasks.py b/src/xraysink/tasks.py
index 3305f12..6510e56 100644
--- a/src/xraysink/tasks.py
+++ b/src/xraysink/tasks.py
@@ -17,7 +17,7 @@
 TASK_SCHEME: str = "task"
 
 #: Format string for the synthetic URL's used by background tasks.
-TASK_URL_FORMAT: str = TASK_SCHEME + "://localhost/{task_path}"
+TASK_URL_FORMAT: str = TASK_SCHEME + "://localhost/{task_path}"  # noqa: FS003
 
 
 def xray_task_async(*, _url_path: Optional[str] = None):
diff --git a/src/xraysink/util.py b/src/xraysink/util.py
index 88b3b2b..f7fe1d9 100644
--- a/src/xraysink/util.py
+++ b/src/xraysink/util.py
@@ -10,6 +10,5 @@ def has_current_trace() -> bool:
     This is like calling xray_recorder.get_trace_entity(), but without the
     annoying error handling.
     """
-    # See authoritative implementation in
-    # aws_xray_sdk.core.context.Context.get_trace_entity()
+    # See authoritative implementation in aws_xray_sdk.core.context.Context.get_trace_entity()
     return bool(getattr(xray_recorder.context._local, "entities", None))


Test patch:
diff --git a/tests/asgi/middleware/_aiohttp.py b/tests/asgi/middleware/_aiohttp.py
index 3cfd829..8100df9 100644
--- a/tests/asgi/middleware/_aiohttp.py
+++ b/tests/asgi/middleware/_aiohttp.py
@@ -2,7 +2,6 @@
 
 import asyncio
 
-import pytest
 from aiohttp import web
 from aiohttp.web_exceptions import HTTPUnauthorized
 from aiohttp.web_exceptions import HTTPUnprocessableEntity
@@ -10,7 +9,7 @@
 from xraysink.asgi.middleware import xray_middleware
 
 
-class AioHttpServerFactory(object):
+class AioHttpServerFactory:
     """
     Factory for an xray-instrumented aiohttp Application's
     that implements our test endpoints.
diff --git a/tests/asgi/middleware/test_middleware.py b/tests/asgi/middleware/test_middleware.py
index c02e0f7..e6bb976 100644
--- a/tests/asgi/middleware/test_middleware.py
+++ b/tests/asgi/middleware/test_middleware.py
@@ -8,6 +8,7 @@
 import aiohttp.web_app
 import pytest
 import requests
+from aiohttp.pytest_plugin import aiohttp_client  # noqa: F401
 from async_asgi_testclient import TestClient
 from aws_xray_sdk import global_sdk_config
 from aws_xray_sdk.core.models import http
@@ -20,22 +21,22 @@
 from ._aiohttp import AioHttpServerFactory
 from ._fastapi import fastapi_native_middleware_factory
 
+
 pytestmark = pytest.mark.asyncio
 
 
-# Import just the client helper fixture from aiohttp, without polluting our
+# aiohttp Testing
+# ---------------
+#
+# We import just the client helper fixture from aiohttp, without polluting our
 # fixture namespace with all the cray-cray in the `pytest-aiohttp` pytest
 # plugin (like yet another `loop`).
 #
-# noinspection PyUnresolvedReferences
-from aiohttp.pytest_plugin import aiohttp_client
-
-
-# Inject a `loop` fixture based on the normal `event_loop` fixture,
+# We also have to inject a `loop` fixture based on the normal `event_loop` fixture,
 # since aiohttp_client has this as a fixture dependency
-@pytest.fixture
+@pytest.fixture()
 async def loop(event_loop):
-    yield event_loop
+    return event_loop
 
 
 @pytest.fixture(
@@ -44,7 +45,7 @@ async def loop(event_loop):
         pytest.param(fastapi_native_middleware_factory, id="fastapi"),
     ]
 )
-async def client(request, aiohttp_client):
+async def client(request, aiohttp_client):  # noqa: F811
     """Get a client for each of the server frameworks under test."""
     appfactory = request.param
     app = appfactory()
@@ -77,7 +78,7 @@ async def _verify_http_status(
         elif hasattr(response, "status_code"):
             assert response.status_code == status, response.text
         else:
-            assert False, "Unknown response object type"
+            pytest.fail("Unknown response object type")
 
     def _verify_xray_request(
         self,
@@ -136,7 +137,7 @@ async def test_should_use_segmentid_in_http_header(self, client, recorder):
 
         # Verify
         segment = recorder.emitter.pop()
-        expected_root = "Root=%s" % segment.trace_id
+        expected_root = f"Root={segment.trace_id}"
 
         xray_header = server_response.headers[http.XRAY_HEADER]
         assert expected_root in xray_header
diff --git a/tests/conftest.py b/tests/conftest.py
index ecb4758..de2b530 100644
--- a/tests/conftest.py
+++ b/tests/conftest.py
@@ -9,14 +9,16 @@
 from .xray_util import get_new_stubbed_recorder
 
 
-@pytest.fixture
+@pytest.fixture()
 def caplog(caplog):
-    """Override the standard caplog fixture to provide a more sensible default level on the root logger."""
+    """
+    Override the standard caplog fixture to have a more sensible default level on the root logger.
+    """
     caplog.set_level(logging.DEBUG)
     return caplog
 
 
-@pytest.fixture
+@pytest.fixture()
 def recorder(event_loop) -> AsyncAWSXRayRecorder:
     """An X-Ray recorder with local-only, stubbed, segment collection."""
     xray_recorder = get_new_stubbed_recorder()
diff --git a/tests/test_asyncio_tasks.py b/tests/test_asyncio_tasks.py
index 58024ef..014643d 100644
--- a/tests/test_asyncio_tasks.py
+++ b/tests/test_asyncio_tasks.py
@@ -3,7 +3,6 @@
 from asyncio import sleep
 
 import pytest
-from pytest import approx
 
 from xraysink.context import AsyncContext
 
@@ -46,19 +45,19 @@ async def broken_task(name: str):
 
     assert (
         subsegments["short-task"].end_time - subsegments["long-task"].start_time
-    ) == approx(0.01, abs=0.2)
+    ) == pytest.approx(0.01, abs=0.2)
     assert not getattr(subsegments["short-task"], "error", False)
     assert not getattr(subsegments["short-task"], "fault", False)
 
     assert (
         subsegments["medium-task"].end_time - subsegments["long-task"].start_time
-    ) == approx(0.5, abs=0.2)
+    ) == pytest.approx(0.5, abs=0.2)
     assert not getattr(subsegments["medium-task"], "error", False)
     assert not getattr(subsegments["medium-task"], "fault", False)
 
     assert (
         subsegments["long-task"].end_time - subsegments["long-task"].start_time
-    ) == approx(2.0, abs=0.2)
+    ) == pytest.approx(2.0, abs=0.2)
     assert not getattr(subsegments["long-task"], "error", False)
     assert not getattr(subsegments["long-task"], "fault", False)
 
diff --git a/tests/test_tasks.py b/tests/test_tasks.py
index 1ee7201..7fad1ad 100644
--- a/tests/test_tasks.py
+++ b/tests/test_tasks.py
@@ -152,7 +152,7 @@ async def do_something():
             raise ValueError(42)
 
         # Exercise
-        with pytest.raises(ValueError):
+        with pytest.raises(ValueError):  # noqa: PT011
             await do_something()
 
         # Verify
@@ -168,11 +168,11 @@ async def do_something():
 class TestXrayTaskAsyncNested(BaseXrayTaskTests):
     """Test the xray_task_async() decorator when nested inside an existing segment."""
 
-    @pytest.fixture
+    @pytest.fixture()
     def recorder(self, recorder) -> AsyncAWSXRayRecorder:
         # Nested tasks will only work if we are using a well-behaved context
         recorder.configure(context=AsyncContext())
-        yield recorder
+        return recorder
 
     async def _verify_nested_segment(self, segments, initial_name: str, task_name):
         """Verify the X-Ray entities created by a nested task."""
diff --git a/tests/xray_util.py b/tests/xray_util.py
index 0028e64..17ea364 100644
--- a/tests/xray_util.py
+++ b/tests/xray_util.py
@@ -1,7 +1,6 @@
 # From https://github.com/aws/aws-xray-sdk-python/blob/master/tests/util.py
 
 import json
-import threading
 
 from aws_xray_sdk.core.emitters.udp_emitter import UDPEmitter
 from aws_xray_sdk.core.recorder import AWSXRayRecorder