pytest-neon 2.3.1__tar.gz → 3.0.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. {pytest_neon-2.3.1 → pytest_neon-3.0.0}/.gitignore +3 -0
  2. pytest_neon-3.0.0/CLAUDE.md +167 -0
  3. pytest_neon-3.0.0/PKG-INFO +348 -0
  4. pytest_neon-3.0.0/README.md +302 -0
  5. {pytest_neon-2.3.1 → pytest_neon-3.0.0}/pyproject.toml +1 -1
  6. {pytest_neon-2.3.1 → pytest_neon-3.0.0}/src/pytest_neon/__init__.py +3 -3
  7. pytest_neon-3.0.0/src/pytest_neon/plugin.py +1143 -0
  8. {pytest_neon-2.3.1 → pytest_neon-3.0.0}/tests/conftest.py +3 -36
  9. {pytest_neon-2.3.1 → pytest_neon-3.0.0}/tests/test_branch_lifecycle.py +60 -67
  10. {pytest_neon-2.3.1 → pytest_neon-3.0.0}/tests/test_branch_name_prefix.py +63 -113
  11. {pytest_neon-2.3.1 → pytest_neon-3.0.0}/tests/test_integration.py +37 -67
  12. pytest_neon-3.0.0/tests/test_migrations.py +194 -0
  13. pytest_neon-3.0.0/tests/test_reset_behavior.py +255 -0
  14. pytest_neon-3.0.0/tests/test_xdist_worker_support.py +161 -0
  15. {pytest_neon-2.3.1 → pytest_neon-3.0.0}/uv.lock +1 -1
  16. pytest_neon-2.3.1/CLAUDE.md +0 -120
  17. pytest_neon-2.3.1/PKG-INFO +0 -650
  18. pytest_neon-2.3.1/README.md +0 -604
  19. pytest_neon-2.3.1/src/pytest_neon/plugin.py +0 -2087
  20. pytest_neon-2.3.1/tests/test_dirty_isolated_fixtures.py +0 -400
  21. pytest_neon-2.3.1/tests/test_migrations.py +0 -156
  22. pytest_neon-2.3.1/tests/test_readwrite_readonly_fixtures.py +0 -385
  23. pytest_neon-2.3.1/tests/test_reset_behavior.py +0 -581
  24. pytest_neon-2.3.1/tests/test_xdist_worker_support.py +0 -238
  25. {pytest_neon-2.3.1 → pytest_neon-3.0.0}/.config/wt.toml +0 -0
  26. {pytest_neon-2.3.1 → pytest_neon-3.0.0}/.env.example +0 -0
  27. {pytest_neon-2.3.1 → pytest_neon-3.0.0}/.github/workflows/release.yml +0 -0
  28. {pytest_neon-2.3.1 → pytest_neon-3.0.0}/.github/workflows/tests.yml +0 -0
  29. {pytest_neon-2.3.1 → pytest_neon-3.0.0}/.neon +0 -0
  30. {pytest_neon-2.3.1 → pytest_neon-3.0.0}/LICENSE +0 -0
  31. {pytest_neon-2.3.1 → pytest_neon-3.0.0}/src/pytest_neon/py.typed +0 -0
  32. {pytest_neon-2.3.1 → pytest_neon-3.0.0}/tests/test_cli_options.py +0 -0
  33. {pytest_neon-2.3.1 → pytest_neon-3.0.0}/tests/test_default_branch_safety.py +0 -0
  34. {pytest_neon-2.3.1 → pytest_neon-3.0.0}/tests/test_env_var.py +0 -0
  35. {pytest_neon-2.3.1 → pytest_neon-3.0.0}/tests/test_fixture_errors.py +0 -0
  36. {pytest_neon-2.3.1 → pytest_neon-3.0.0}/tests/test_service_classes.py +0 -0
  37. {pytest_neon-2.3.1 → pytest_neon-3.0.0}/tests/test_skip_behavior.py +0 -0
@@ -37,3 +37,6 @@ htmlcov/
37
37
  # OS
38
38
  .DS_Store
39
39
  Thumbs.db
40
+
41
+ # bv (beads viewer) local config and caches
42
+ .bv/
@@ -0,0 +1,167 @@
1
+ # Claude Code Instructions for pytest-neon
2
+
3
+ ## Understanding the Plugin
4
+
5
+ Read `README.md` for complete documentation on how to use this plugin, including fixtures, configuration options, and migration support.
6
+
7
+ ## Project Overview
8
+
9
+ This is a pytest plugin that provides Neon database branches for integration testing. All tests share a single branch per session.
10
+
11
+ ## Key Architecture
12
+
13
+ - **Entry point**: `src/pytest_neon/plugin.py` - Contains all fixtures and pytest hooks
14
+ - **Test branch fixture**: `_neon_test_branch` - Session-scoped, single branch for all tests
15
+ - **User migration hook**: `neon_apply_migrations` - Session-scoped no-op, users override to run migrations
16
+ - **Main fixture**: `neon_branch` - Session-scoped, shared branch for all tests
17
+ - **Convenience fixtures**: `neon_connection`, `neon_connection_psycopg`, `neon_engine` - Optional, require extras
18
+
19
+ ## Branch Hierarchy
20
+
21
+ ```
22
+ Parent Branch (configured or project default)
23
+ └── Test Branch (session-scoped, 10-min expiry)
24
+ ↑ migrations run here ONCE, all tests share this
25
+ ```
26
+
27
+ ## Dependencies
28
+
29
+ - Core: `pytest`, `neon-api`, `requests`, `filelock`
30
+ - Optional extras: `psycopg2`, `psycopg`, `sqlalchemy` - for convenience fixtures
31
+
32
+ ## Important Patterns
33
+
34
+ ### Modular Architecture
35
+
36
+ The plugin uses a service-oriented architecture for testability:
37
+
38
+ - **NeonConfig**: Dataclass for configuration extraction from pytest config
39
+ - **NeonBranchManager**: Manages Neon API operations (branch create/delete)
40
+ - **XdistCoordinator**: Handles worker synchronization with file locks and JSON caching
41
+ - **EnvironmentManager**: Manages DATABASE_URL environment variable lifecycle
42
+
43
+ ### Fixture Scopes
44
+ - `_neon_config`: `scope="session"` - Configuration extracted from pytest config
45
+ - `_neon_branch_manager`: `scope="session"` - Branch lifecycle manager
46
+ - `_neon_xdist_coordinator`: `scope="session"` - Worker synchronization
47
+ - `_neon_test_branch`: `scope="session"` - Internal, creates branch, yields (branch, is_creator)
48
+ - `neon_apply_migrations`: `scope="session"` - User overrides to run migrations
49
+ - `neon_branch`: `scope="session"` - User-facing, shared branch for all tests
50
+ - Connection fixtures: `scope="function"` - Fresh connection per test
51
+
52
+ ### Environment Variable Handling
53
+ The `EnvironmentManager` class handles `DATABASE_URL` lifecycle:
54
+ - Sets environment variable when fixture starts
55
+ - Saves original value for restoration
56
+ - Restores original value (or removes) when fixture ends
57
+
58
+ ### xdist Worker Synchronization
59
+ The `XdistCoordinator` handles sharing resources across workers:
60
+ - Uses file locks (`filelock`) for coordination
61
+ - Stores shared resource data in JSON files
62
+ - `coordinate_resource()` ensures only one worker creates shared resources
63
+ - `wait_for_signal()` / `send_signal()` for migration synchronization
64
+ - All workers share ONE branch (no per-worker branches)
65
+
66
+ ### Error Messages
67
+ Convenience fixtures use `pytest.fail()` with detailed, formatted error messages when dependencies are missing. Keep this pattern - users need clear guidance on how to fix import errors.
68
+
69
+ ## Test Isolation
70
+
71
+ Since all tests share the same branch, users should implement their own isolation:
72
+ 1. **Transaction rollback** - Recommended for most cases
73
+ 2. **Table truncation** - For cases where transactions aren't suitable
74
+ 3. **Unique identifiers** - Use UUIDs to avoid conflicts
75
+
76
+ ## Documentation
77
+
78
+ Important help text should be documented in BOTH:
79
+ 1. **README.md** - Full user-facing documentation
80
+ 2. **Module/fixture docstrings** - So `help(pytest_neon)` shows useful info
81
+
82
+ The module docstring in `plugin.py` should include key usage notes. Keep docstrings and README in sync.
83
+
84
+ ## Commit Messages
85
+ - Do NOT add Claude attribution or Co-Authored-By lines
86
+ - Keep commits clean and descriptive
87
+
88
+ ## Testing
89
+
90
+ Run tests with:
91
+ ```bash
92
+ uv run pytest tests/ -v
93
+ ```
94
+
95
+ Tests in `tests/` use `pytester` for testing pytest plugins. The plugin itself can be tested without a real Neon connection by mocking `NeonAPI`.
96
+
97
+ ## Publishing
98
+
99
+ **Always use the GitHub Actions release workflow** - do not manually bump versions:
100
+ 1. Go to Actions → Release → Run workflow
101
+ 2. Choose patch/minor/major
102
+ 3. Workflow bumps version, commits, tags, and publishes to PyPI
103
+
104
+ Package name on PyPI: `pytest-neon`
105
+
106
+ <!-- bv-agent-instructions-v1 -->
107
+
108
+ ---
109
+
110
+ ## Beads Workflow Integration
111
+
112
+ This project uses [beads_viewer](https://github.com/Dicklesworthstone/beads_viewer) for issue tracking. Issues are stored in `.beads/` and tracked in git.
113
+
114
+ ### Essential Commands
115
+
116
+ ```bash
117
+ # View issues (launches TUI - avoid in automated sessions)
118
+ bv
119
+
120
+ # CLI commands for agents (use these instead)
121
+ bd ready # Show issues ready to work (no blockers)
122
+ bd list --status=open # All open issues
123
+ bd show <id> # Full issue details with dependencies
124
+ bd create --title="..." --type=task --priority=2
125
+ bd update <id> --status=in_progress
126
+ bd close <id> --reason="Completed"
127
+ bd close <id1> <id2> # Close multiple issues at once
128
+ bd sync # Commit and push changes
129
+ ```
130
+
131
+ ### Workflow Pattern
132
+
133
+ 1. **Start**: Run `bd ready` to find actionable work
134
+ 2. **Claim**: Use `bd update <id> --status=in_progress`
135
+ 3. **Work**: Implement the task
136
+ 4. **Complete**: Use `bd close <id>`
137
+ 5. **Sync**: Always run `bd sync` at session end
138
+
139
+ ### Key Concepts
140
+
141
+ - **Dependencies**: Issues can block other issues. `bd ready` shows only unblocked work.
142
+ - **Priority**: P0=critical, P1=high, P2=medium, P3=low, P4=backlog (use numbers, not words)
143
+ - **Types**: task, bug, feature, epic, question, docs
144
+ - **Blocking**: `bd dep add <issue> <depends-on>` to add dependencies
145
+
146
+ ### Session Protocol
147
+
148
+ **Before ending any session, run this checklist:**
149
+
150
+ ```bash
151
+ git status # Check what changed
152
+ git add <files> # Stage code changes
153
+ bd sync # Commit beads changes
154
+ git commit -m "..." # Commit code
155
+ bd sync # Commit any new beads changes
156
+ git push # Push to remote
157
+ ```
158
+
159
+ ### Best Practices
160
+
161
+ - Check `bd ready` at session start to find available work
162
+ - Update status as you work (in_progress → closed)
163
+ - Create new issues with `bd create` when you discover tasks
164
+ - Use descriptive titles and set appropriate priority/type
165
+ - Always `bd sync` before ending session
166
+
167
+ <!-- end-bv-agent-instructions -->
@@ -0,0 +1,348 @@
1
+ Metadata-Version: 2.4
2
+ Name: pytest-neon
3
+ Version: 3.0.0
4
+ Summary: Pytest plugin for Neon database branch isolation in tests
5
+ Project-URL: Homepage, https://github.com/ZainRizvi/pytest-neon
6
+ Project-URL: Repository, https://github.com/ZainRizvi/pytest-neon
7
+ Project-URL: Issues, https://github.com/ZainRizvi/pytest-neon/issues
8
+ Author: Zain Rizvi
9
+ License-Expression: MIT
10
+ License-File: LICENSE
11
+ Keywords: branching,database,neon,postgres,pytest,testing
12
+ Classifier: Development Status :: 4 - Beta
13
+ Classifier: Framework :: Pytest
14
+ Classifier: Intended Audience :: Developers
15
+ Classifier: License :: OSI Approved :: MIT License
16
+ Classifier: Operating System :: OS Independent
17
+ Classifier: Programming Language :: Python :: 3
18
+ Classifier: Programming Language :: Python :: 3.9
19
+ Classifier: Programming Language :: Python :: 3.10
20
+ Classifier: Programming Language :: Python :: 3.11
21
+ Classifier: Programming Language :: Python :: 3.12
22
+ Classifier: Programming Language :: Python :: 3.13
23
+ Classifier: Programming Language :: Python :: 3.14
24
+ Classifier: Topic :: Database
25
+ Classifier: Topic :: Software Development :: Testing
26
+ Requires-Python: >=3.9
27
+ Requires-Dist: filelock>=3.0
28
+ Requires-Dist: neon-api>=0.1.0
29
+ Requires-Dist: pytest>=7.0
30
+ Requires-Dist: requests>=2.20
31
+ Provides-Extra: dev
32
+ Requires-Dist: mypy>=1.0; extra == 'dev'
33
+ Requires-Dist: psycopg2-binary>=2.9; extra == 'dev'
34
+ Requires-Dist: psycopg[binary]>=3.1; extra == 'dev'
35
+ Requires-Dist: pytest-cov>=4.0; extra == 'dev'
36
+ Requires-Dist: pytest-mock>=3.0; extra == 'dev'
37
+ Requires-Dist: ruff>=0.8; extra == 'dev'
38
+ Requires-Dist: sqlalchemy>=2.0; extra == 'dev'
39
+ Provides-Extra: psycopg
40
+ Requires-Dist: psycopg[binary]>=3.1; extra == 'psycopg'
41
+ Provides-Extra: psycopg2
42
+ Requires-Dist: psycopg2-binary>=2.9; extra == 'psycopg2'
43
+ Provides-Extra: sqlalchemy
44
+ Requires-Dist: sqlalchemy>=2.0; extra == 'sqlalchemy'
45
+ Description-Content-Type: text/markdown
46
+
47
+ # pytest-neon
48
+
49
+ [![Tests](https://github.com/ZainRizvi/pytest-neon/actions/workflows/tests.yml/badge.svg)](https://github.com/ZainRizvi/pytest-neon/actions/workflows/tests.yml)
50
+
51
+ A pytest plugin that provides Neon database branches for integration testing.
52
+
53
+ ## Features
54
+
55
+ - **Automatic branch management**: Creates a test branch at session start, deletes at end
56
+ - **Branch expiry**: Auto-cleanup via 10-minute expiry (crash-safe)
57
+ - **Migration support**: Run migrations once, all tests share the migrated schema
58
+ - **pytest-xdist support**: All workers share a single branch
59
+ - **Minimal API calls**: Single branch creation reduces rate limiting issues
60
+
61
+ ## Installation
62
+
63
+ ```bash
64
+ pip install pytest-neon
65
+
66
+ # With optional database drivers
67
+ pip install pytest-neon[psycopg] # psycopg v3 support
68
+ pip install pytest-neon[psycopg2] # psycopg2 support
69
+ pip install pytest-neon[sqlalchemy] # SQLAlchemy engine support
70
+ ```
71
+
72
+ ## Quick Start
73
+
74
+ 1. Set environment variables:
75
+ ```bash
76
+ export NEON_API_KEY="your-api-key"
77
+ export NEON_PROJECT_ID="your-project-id"
78
+ ```
79
+
80
+ 2. Use the `neon_branch` fixture in your tests:
81
+ ```python
82
+ def test_query_users(neon_branch):
83
+ import psycopg
84
+ with psycopg.connect(neon_branch.connection_string) as conn:
85
+ result = conn.execute("SELECT * FROM users").fetchall()
86
+ assert len(result) >= 0
87
+ ```
88
+
89
+ The `DATABASE_URL` environment variable is automatically set when the fixture is active.
90
+
91
+ ## Fixtures
92
+
93
+ ### `neon_branch` (session-scoped)
94
+
95
+ The main fixture providing a shared Neon branch for all tests.
96
+
97
+ ```python
98
+ def test_example(neon_branch):
99
+ # neon_branch.branch_id - Neon branch ID
100
+ # neon_branch.project_id - Neon project ID
101
+ # neon_branch.connection_string - PostgreSQL connection string
102
+ # neon_branch.host - Database host
103
+ pass
104
+ ```
105
+
106
+ **Important**: All tests share the same branch. Data written by one test is visible to subsequent tests. See [Test Isolation](#test-isolation) for patterns to handle this.
107
+
108
+ ### `neon_apply_migrations` (session-scoped)
109
+
110
+ Override this fixture to run migrations before tests:
111
+
112
+ ```python
113
+ # conftest.py
114
+ @pytest.fixture(scope="session")
115
+ def neon_apply_migrations(_neon_test_branch):
116
+ """Run database migrations."""
117
+ import subprocess
118
+ subprocess.run(["alembic", "upgrade", "head"], check=True)
119
+ ```
120
+
121
+ Or with Django:
122
+ ```python
123
+ @pytest.fixture(scope="session")
124
+ def neon_apply_migrations(_neon_test_branch):
125
+ from django.core.management import call_command
126
+ call_command("migrate", "--noinput")
127
+ ```
128
+
129
+ Or with raw SQL:
130
+ ```python
131
+ @pytest.fixture(scope="session")
132
+ def neon_apply_migrations(_neon_test_branch):
133
+ import psycopg
134
+ branch, is_creator = _neon_test_branch
135
+ with psycopg.connect(branch.connection_string) as conn:
136
+ with open("schema.sql") as f:
137
+ conn.execute(f.read())
138
+ conn.commit()
139
+ ```
140
+
141
+ ### Connection Fixtures (Optional)
142
+
143
+ These require extra dependencies:
144
+
145
+ **`neon_connection`** - psycopg2 connection (requires `pytest-neon[psycopg2]`)
146
+ ```python
147
+ def test_insert(neon_connection):
148
+ cur = neon_connection.cursor()
149
+ cur.execute("INSERT INTO users (name) VALUES (%s)", ("test",))
150
+ neon_connection.commit()
151
+ ```
152
+
153
+ **`neon_connection_psycopg`** - psycopg v3 connection (requires `pytest-neon[psycopg]`)
154
+ ```python
155
+ def test_insert(neon_connection_psycopg):
156
+ with neon_connection_psycopg.cursor() as cur:
157
+ cur.execute("INSERT INTO users (name) VALUES ('test')")
158
+ neon_connection_psycopg.commit()
159
+ ```
160
+
161
+ **`neon_engine`** - SQLAlchemy engine (requires `pytest-neon[sqlalchemy]`)
162
+ ```python
163
+ def test_query(neon_engine):
164
+ from sqlalchemy import text
165
+ with neon_engine.connect() as conn:
166
+ result = conn.execute(text("SELECT 1"))
167
+ ```
168
+
169
+ ## Test Isolation
170
+
171
+ Since all tests share a single branch, you may need to handle test isolation yourself. Here are recommended patterns:
172
+
173
+ ### Transaction Rollback (Recommended)
174
+
175
+ ```python
176
+ @pytest.fixture
177
+ def db_transaction(neon_branch):
178
+ """Provide a database transaction that rolls back after each test."""
179
+ import psycopg
180
+ conn = psycopg.connect(neon_branch.connection_string)
181
+ conn.execute("BEGIN")
182
+ yield conn
183
+ conn.execute("ROLLBACK")
184
+ conn.close()
185
+
186
+ def test_insert(db_transaction):
187
+ db_transaction.execute("INSERT INTO users (name) VALUES ('test')")
188
+ # Automatically rolled back - next test won't see this
189
+ ```
190
+
191
+ ### Table Truncation
192
+
193
+ ```python
194
+ @pytest.fixture(autouse=True)
195
+ def clean_tables(neon_branch):
196
+ """Clean up test data after each test."""
197
+ yield
198
+ import psycopg
199
+ with psycopg.connect(neon_branch.connection_string) as conn:
200
+ conn.execute("TRUNCATE users, orders CASCADE")
201
+ conn.commit()
202
+ ```
203
+
204
+ ### Unique Identifiers
205
+
206
+ ```python
207
+ import uuid
208
+
209
+ def test_create_user(neon_branch):
210
+ unique_id = uuid.uuid4().hex[:8]
211
+ email = f"test_{unique_id}@example.com"
212
+ # Create user with unique email - no conflicts with other tests
213
+ ```
214
+
215
+ ## Configuration
216
+
217
+ ### Environment Variables
218
+
219
+ | Variable | Description |
220
+ |----------|-------------|
221
+ | `NEON_API_KEY` | Neon API key (required) |
222
+ | `NEON_PROJECT_ID` | Neon project ID (required) |
223
+ | `NEON_PARENT_BRANCH_ID` | Parent branch to create test branches from |
224
+ | `NEON_DATABASE` | Database name (default: `neondb`) |
225
+ | `NEON_ROLE` | Database role (default: `neondb_owner`) |
226
+
227
+ ### Command Line Options
228
+
229
+ ```bash
230
+ pytest --neon-api-key=KEY --neon-project-id=ID
231
+ pytest --neon-parent-branch=BRANCH_ID
232
+ pytest --neon-database=mydb --neon-role=myrole
233
+ pytest --neon-keep-branches # Don't delete branches (for debugging)
234
+ pytest --neon-branch-expiry=600 # Branch expiry in seconds (default: 600)
235
+ pytest --neon-env-var=CUSTOM_URL # Use custom env var instead of DATABASE_URL
236
+ ```
237
+
238
+ ### pytest.ini / pyproject.toml
239
+
240
+ ```ini
241
+ [pytest]
242
+ neon_api_key = your-api-key
243
+ neon_project_id = your-project-id
244
+ neon_parent_branch = br-parent-123
245
+ neon_database = mydb
246
+ neon_role = myrole
247
+ neon_keep_branches = false
248
+ neon_branch_expiry = 600
249
+ neon_env_var = DATABASE_URL
250
+ ```
251
+
252
+ ## Architecture
253
+
254
+ ```
255
+ Parent Branch (configured or project default)
256
+ └── Test Branch (session-scoped, 10-min expiry)
257
+ ↑ migrations run here ONCE, all tests share this
258
+ ```
259
+
260
+ The plugin creates exactly **one branch per test session**:
261
+ 1. First test triggers branch creation with auto-expiry
262
+ 2. Migrations run once (if `neon_apply_migrations` is overridden)
263
+ 3. All tests share the same branch
264
+ 4. Branch deleted at session end (plus auto-expiry as safety net)
265
+
266
+ ### pytest-xdist Support
267
+
268
+ When running with pytest-xdist, all workers share the same branch:
269
+ - First worker creates the branch and runs migrations
270
+ - Other workers wait for migrations to complete
271
+ - All workers see the same database state
272
+
273
+ ```bash
274
+ pytest -n 4 # 4 workers, all sharing one branch
275
+ ```
276
+
277
+ ## Branch Naming
278
+
279
+ Branches are automatically named to help identify their source:
280
+
281
+ ```
282
+ pytest-[git-branch]-[random]-test
283
+ ```
284
+
285
+ **Examples:**
286
+ - `pytest-main-a1b2-test` - Test branch from `main`
287
+ - `pytest-feature-auth-c3d4-test` - Test branch from `feature/auth`
288
+ - `pytest-a1b2-test` - When not in a git repo
289
+
290
+ The git branch name is sanitized (only `a-z`, `0-9`, `-`, `_` allowed) and truncated to 15 characters.
291
+
292
+ ## Upgrading from v2.x
293
+
294
+ Version 3.0 simplifies the plugin significantly. If you're upgrading from v2.x:
295
+
296
+ ### Removed Fixtures
297
+
298
+ These fixtures have been removed:
299
+ - `neon_branch_readonly` → use `neon_branch`
300
+ - `neon_branch_readwrite` → use `neon_branch`
301
+ - `neon_branch_isolated` → use `neon_branch` + transaction rollback
302
+ - `neon_branch_dirty` → use `neon_branch`
303
+ - `neon_branch_shared` → use `neon_branch`
304
+
305
+ ### Migration Hook Change
306
+
307
+ The migration hook now uses `_neon_test_branch` instead of `_neon_migration_branch`:
308
+
309
+ ```python
310
+ # Before (v2.x)
311
+ @pytest.fixture(scope="session")
312
+ def neon_apply_migrations(_neon_migration_branch):
313
+ ...
314
+
315
+ # After (v3.x)
316
+ @pytest.fixture(scope="session")
317
+ def neon_apply_migrations(_neon_test_branch):
318
+ ...
319
+ ```
320
+
321
+ ### No Per-Test Reset
322
+
323
+ The v2.x `neon_branch_isolated` fixture reset the branch after each test. In v3.x, there's no automatic reset. Use transaction rollback or cleanup fixtures for test isolation.
324
+
325
+ ## Troubleshooting
326
+
327
+ ### Rate Limiting
328
+
329
+ The plugin includes automatic retry with exponential backoff for Neon API rate limits. If you're hitting rate limits:
330
+ - The plugin creates only 1-2 API calls per session (create + delete)
331
+ - Consider increasing `--neon-branch-expiry` to reduce cleanup calls
332
+
333
+ ### Stale Connections (SQLAlchemy)
334
+
335
+ If using SQLAlchemy with connection pooling, use `pool_pre_ping=True`:
336
+ ```python
337
+ engine = create_engine(DATABASE_URL, pool_pre_ping=True)
338
+ ```
339
+
340
+ This is a best practice for any cloud database where connections can be terminated externally.
341
+
342
+ ### Branch Not Deleted
343
+
344
+ If a test run crashes, the branch auto-expires after 10 minutes (configurable). You can also use `--neon-keep-branches` to prevent deletion for debugging.
345
+
346
+ ## License
347
+
348
+ MIT