flake8-expression-complexity
flake8-expression-complexity is an extension for Flake8 that enforces limits on the complexity of individual expressions within Python code. It works by analyzing abstract syntax tree (AST) nodes to score expressions and reports an `ECE001` error when a configurable threshold is exceeded. The current version is 0.0.11, and it maintains a moderate release cadence, with updates addressing new features and bug fixes.
Warnings
- gotcha Chained method calls can result in unexpectedly high complexity scores. The plugin's calculation might consider each method call in a chain as contributing significantly to expression complexity (e.g., `obj.method1().method2().method3()` could be flagged as complex), even if it appears readable.
- gotcha The default `max-expression-complexity` is 7, which may be too strict or too lenient depending on your project's coding style and requirements.
- gotcha This plugin specifically targets expression complexity (ECE001), which is distinct from the cyclomatic complexity of functions (C901) checked by Flake8's built-in `mccabe` plugin. Users often confuse these two, leading to misinterpretations of the reported errors.
- gotcha For projects utilizing Django ORM, queries can naturally become long and appear complex, triggering `ECE001` errors despite being semantically straightforward.
Install
-
pip install flake8-expression-complexity
Imports
- Automatic Plugin Discovery
This plugin is automatically discovered by Flake8 once installed. No direct Python import is needed; it integrates directly with the `flake8` command-line tool.
Quickstart
import datetime
class User:
def __init__(self, is_authorized, credits, subscriptions):
self.is_authorized = is_authorized
self.total_credits_added = credits
self.subscriptions = subscriptions
class Subscription:
def __init__(self, start_date, end_date):
self.start_date = start_date
self.end_date = end_date
def exists(self):
today = datetime.date.today()
return self.start_date < today and self.end_date > today
class Check:
def __init__(self, user, price):
self.user = user
self.price = price
@staticmethod
def objects_filter_aggregate_sum(user_obj):
# Simulate a complex ORM query result for demonstration
# In a real scenario, this would involve database interaction
if user_obj.is_authorized: # simplified logic
return {'check__sum': 100}
return {'check__sum': 0}
class UserAction:
def __init__(self, datetime_val):
self.datetime = datetime_val
@staticmethod
def objects_filter_last_datetime(user_obj):
# Simulate fetching last action datetime
# In a real scenario, this would involve database interaction
return UserAction(datetime.datetime.now())
def example_function(user):
today = datetime.date.today()
# This expression will likely exceed the default complexity threshold
if (
(user and user.is_authorized)
and user.subscriptions.exists() # Simplified to use Subscription.exists
and (
user.total_credits_added - Check.objects_filter_aggregate_sum(user)['check__sum'] # Simulate aggregate
)
and UserAction.objects_filter_last_datetime(user).datetime > datetime.datetime.now() - datetime.timedelta(days=10)
):
print("User meets complex conditions.")
# To run flake8 with this plugin, save the above code to 'test_complexity.py'
# and execute in your terminal:
# flake8 --max-expression-complexity=3 test_complexity.py