Quick Solution
If your breakpoints aren’t working and you use pytest-cov, run your tests with:
pytest your_tests.py --no-cov
The Problem
You’re debugging a Django application with pytest, and your breakpoints aren’t stopping where they should. If this is happening to you,
you’re not alone - there’s a known issue between coverage, pytest-cov, and factory_boy that can cause breakpoints to behave
unexpectedly.
Environment and Versions
This issue affects:
coverageversions 6.4.1 and laterpytest-cov(all recent versions)- Python 3.x+
- Django 3.x+
A Real-World Example
Let’s walk through a typical scenario where this issue appears. Consider a simple Django user model with a full_name property:
class User(AbstractUser):
first_name = models.CharField(max_length=30)
last_name = models.CharField(max_length=30)
@property
def full_name(self):
return f"{self.first_name} {self.last_name}"
Using Factory Boy (a fantastic tool for test data generation), we’ve created a factory:
class UserFactory(factory.django.DjangoModelFactory):
first_name = factory.Faker("first_name")
last_name = factory.Faker("last_name")
username = factory.LazyAttributeSequence(
lambda a, n: f"{a.first_name}{a.last_name}{n}".lower()
)
class Meta:
model = User
Now, let’s write a simple test:
class TestUser(TestCase):
def test_full_name_method(self):
"""Test the full_name property returns the expected value"""
user = UserFactory.create(
first_name="Bob",
last_name="Roberts"
)
breakpoint() # This should stop here, but might not!
self.assertEqual(user.full_name, "Bob Roberts")
The Unexpected Behavior
When you run this test with pytest-cov enabled, something strange happens:
- Expected: The debugger should stop at the
breakpoint()line in your test - Actual: The debugger jumps to the
full_nameproperty definition instead
Here’s what you might see:
--Call--
> /path/to/your/app/models.py(XX)full_name()
-> @property
(Pdb) print(user)
*** NameError: name 'user' is not defined
Solutions and Workarounds
1. Disable Coverage During Debugging
The simplest solution is to disable coverage when you need to use breakpoints:
# Option 1: Disable coverage completely
pytest your_tests.py --no-cov
# Option 2: Run specific test with no coverage
pytest your_tests.py::TestUser::test_full_name_method --no-cov
2. PyCharm Configuration
If you’re using PyCharm, you can permanently configure this in your debug settings:
- Go to Run/Debug Configurations
- Add
--no-covto the “Additional Arguments” field - Save the configuration

3. Alternative Debugging Methods
It is worth noting that you could downgrade coverage far enough that the issue goes away - but that is not a practical solution.
If you need to maintain coverage while debugging:
def test_full_name_method(self):
user = UserFactory.create(first_name="Bob", last_name="Roberts")
# Option 1: Use print statements
print(f"Debug: user object = {user}")
print(f"Debug: full name = {user.full_name}")
# Option 2: Use logging
import logging
logging.debug(f"User object: {user}")
self.assertEqual(user.full_name, "Bob Roberts")
Impact on CI/CD
This issue typically only affects local development since you generally don’t use breakpoints in CI/CD pipelines. Your coverage reports in CI/CD should continue to work normally.
Root Cause
The issue stems from how coverage instrumentation interacts with Python’s debugging hooks. When coverage is enabled:
- Coverage instruments your code to track execution
- This instrumentation can interfere with Python’s standard debugging hooks
- The result is that breakpoints may fire at unexpected locations
Related Issues and Discussion
Further Reading
While this issue can be frustrating, the --no-cov workaround provides a reliable solution. Until the underlying interaction between
coverage and debugging is resolved (which may never happen), this remains the most practical approach for local development debugging.
Remember:
- Use
--no-covwhen you need breakpoint debugging - Consider alternative debugging methods if you must maintain coverage
- Keep your CI/CD pipeline configurations unchanged
Happy debugging!
Comments
{0xc0004ec000 0xc00011a728}