Skip to content

Commit 68a0a51

Browse files
authored
Merge pull request #277 from 15r10nk/fix-config-path
fix!: change how tests directory is located
2 parents 38a1f0f + 3de81cd commit 68a0a51

33 files changed

+244
-175
lines changed
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
### Changed
2+
3+
- You now have to specify `test-dir` in your pyproject.toml when you save your tests in a folder other than `tests/` in your project root (#272).
4+
5+
### Fixed
6+
7+
- `pyproject.toml` is now also located based on the current directory and the `pytest-root`, which solves problems when you use inline-snapshot with uv-workspaces (#272).

docs/configuration.md

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ fix=["create","fix"]
6262
```
6363

6464
=== "no command (default)"
65-
inline-snapshot will format only the snapshot values with black when you specified no format command but needs black installed with `inline-snapshot[black]`.
65+
inline-snapshot will format only the snapshot values with black when you specify no format command, but requires black to be installed with `inline-snapshot[black]`.
6666

6767
The placeholder `{filename}` can be used to specify the filename if it is needed to find the correct formatting options for this file.
6868

@@ -71,11 +71,12 @@ fix=["create","fix"]
7171

7272
* **show-updates:**[](){#show-updates} shows updates in reviews and reports.
7373

74-
75-
* **default-storage:**[](){#default-storage} defines the default storage protocol to be used when creating snapshots without an explicit storage protocol (e.g. like `external()`).
74+
* **default-storage:**[](){#default-storage} defines the default storage protocol to be used when creating snapshots without an explicit storage protocol, such as `external()`.
7675
Possible values are `hash` and `uuid`.
77-
external snapshots created by `outsource()` do not currently support this setting due to some internal limitations and will always use the old `hash` protocol.
76+
External snapshots created by `outsource()` do not currently support this setting due to some internal limitations and will always use the old `hash` protocol.
7877

79-
* **tests-dir:** can be used to define where your tests are located.
80-
The default is `<pytest_config_dir>/tests` if it exists or `<pytest_config_dir>` if you have no tests directory,
78+
* **test-dir:** can be used to define where your tests are located.
79+
The default is `<pytest_config_dir>/tests` if it exists,
8180
where `<pytest_config_dir>` is replaced by the directory containing the Pytest configuration file, if any.
81+
This directory is used to search through all test files for `external()` calls and to check whether the currently saved external objects are still used in the source.
82+
It is therefore required if you want to *trim* unused externals.

pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,7 @@ version = "command: cz bump --get-next"
216216

217217
[tool.pytest.ini_options]
218218
markers=["no_rewriting: marks tests which need no code rewriting and can be used with pypy"]
219+
testpaths="tests"
219220

220221
[tool.isort]
221222
profile="black"

src/inline_snapshot/_config.py

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -83,14 +83,6 @@ def read_path(name):
8383
):
8484
config.tests_dir = test_dir
8585

86-
if (
87-
config.tests_dir is None
88-
and path.exists()
89-
and (test_dir := path.parent).exists()
90-
and test_dir.is_dir()
91-
):
92-
config.tests_dir = test_dir
93-
9486
config.default_storage = tool_config.get("default-storage", "uuid")
9587

9688
if config.default_storage not in ("uuid", "hash"):

src/inline_snapshot/_external/_external_location.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,7 @@ def __str__(self) -> str:
143143
except ValueError:
144144
pass
145145

146-
return str(p)
146+
return p.as_posix()
147147

148148
@contextmanager
149149
def load(self) -> Generator[Path]:

src/inline_snapshot/pytest_plugin.py

Lines changed: 69 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -125,20 +125,43 @@ def is_implementation_supported():
125125
return sys.implementation.name == "cpython"
126126

127127

128-
def pytest_configure(config):
129-
enter_snapshot_context()
128+
def is_relative_to(base, relative):
129+
try:
130+
relative.relative_to(base)
131+
except ValueError:
132+
return False
133+
return True
130134

131-
directory = config.rootpath
132-
while not (pyproject := directory / "pyproject.toml").exists():
135+
136+
def find_pyproject(pytest_root, cwd):
137+
if is_relative_to(pytest_root, Path.cwd()):
138+
directory = Path.cwd()
139+
else:
140+
directory = pytest_root
141+
142+
while not (pyproject_pytest := directory / "pyproject.toml").exists():
133143
if directory == directory.parent:
134144
break
135145
directory = directory.parent
146+
else:
147+
return pyproject_pytest
148+
149+
150+
def pytest_configure(config):
151+
enter_snapshot_context()
152+
153+
pyproject = find_pyproject(config.rootpath, Path.cwd())
136154

137155
if is_pytest_compatible():
138156
state().config.default_flags_tui = ["create", "review"]
139157
state().config.default_flags = ["report"]
140158

141-
_config.read_config(pyproject, state().config)
159+
if pyproject is not None:
160+
_config.read_config(pyproject, state().config)
161+
162+
if state().config.tests_dir is None:
163+
if (tests_dir := Path.cwd() / "tests").exists() and tests_dir.is_dir():
164+
state().config.tests_dir = tests_dir
142165

143166
console = Console()
144167
if is_ci_run():
@@ -417,7 +440,7 @@ def header():
417440
console().print(
418441
Panel(
419442
Syntax(diff, "diff", theme="ansi_light", word_wrap=True),
420-
title=str(name),
443+
title=name.as_posix(),
421444
box=(
422445
box.ASCII
423446
if os.environ.get("TERM", "") == "unknown"
@@ -527,40 +550,47 @@ def console():
527550
apply_all(used_changes, cr)
528551
changed_files = {Path(f.filename): f for f in cr.files()}
529552

530-
all_files = {
531-
*map(Path, state().files_with_snapshots),
532-
}
533-
534553
test_dir = state().config.tests_dir
535-
if test_dir:
536-
all_files |= set(test_dir.rglob("*.py"))
537-
538-
used = []
539-
540-
for file in all_files:
541-
if file in changed_files:
542-
content = changed_files[file].new_code()
543-
check_import = False
544-
else:
545-
content = file.read_text("utf-8")
546-
check_import = True
547-
548-
for e in used_externals_in(content, check_import=check_import):
549-
try:
550-
location = ExternalLocation.from_name(e)
551-
used.append(location)
552-
except ValueError:
553-
pass
554-
555-
changes = {f: [] for f in Flags.all()}
556-
557-
for name, storage in state().all_storages.items():
558-
for external_change in storage.sync_used_externals(
559-
[e for e in used if e.storage == name]
560-
):
561-
changes[external_change.flag].append(external_change)
562-
563-
used_changes += filter_changes(changes, snapshot_changes, console)
554+
if not test_dir:
555+
console().print(
556+
"INFO: inline-snasphot can not trim your external snapshots,"
557+
" because there is no [i]tests/[/] folder in your repository root"
558+
" and no [i]test-dir[/] defined in your pyproject.toml."
559+
)
560+
else:
561+
562+
all_files = {
563+
*map(Path, state().files_with_snapshots),
564+
*test_dir.rglob("*.py"),
565+
}
566+
567+
used = []
568+
569+
for file in all_files:
570+
if file in changed_files:
571+
content = changed_files[file].new_code()
572+
check_import = False
573+
else:
574+
content = file.read_text("utf-8")
575+
check_import = True
576+
577+
for e in used_externals_in(content, check_import=check_import):
578+
try:
579+
location = ExternalLocation.from_name(e)
580+
except ValueError:
581+
pass
582+
else:
583+
used.append(location)
584+
585+
changes = {f: [] for f in Flags.all()}
586+
587+
for name, storage in state().all_storages.items():
588+
for external_change in storage.sync_used_externals(
589+
[e for e in used if e.storage == name]
590+
):
591+
changes[external_change.flag].append(external_change)
592+
593+
used_changes += filter_changes(changes, snapshot_changes, console)
564594

565595
report_problems(console)
566596

src/inline_snapshot/testing/_example.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,7 @@ def __init__(self, files: str | dict[str, str | bytes]):
135135
or just a string which will be saved as *test_something.py*.
136136
"""
137137
if isinstance(files, str):
138-
files = {"test_something.py": files}
138+
files = {"tests/test_something.py": files}
139139

140140
self.files = files
141141

@@ -266,7 +266,7 @@ def run_inline(
266266

267267
try:
268268
tests_found = False
269-
for filename in tmp_path.glob("*.py"):
269+
for filename in tmp_path.rglob("test_*.py"):
270270
globals: dict[str, Any] = {}
271271
print("run> pytest-inline", filename)
272272
exec(

tests/adapter/test_change_types.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,8 @@ def test_change():
4949
Example(code(a, b)).run_inline(
5050
["--inline-snapshot=fix,update"],
5151
changed_files=(
52-
{"test_something.py": code(a, code_repr(a))} if code_repr(a) != b else {}
52+
{"tests/test_something.py": code(a, code_repr(a))}
53+
if code_repr(a) != b
54+
else {}
5355
),
5456
)

tests/adapter/test_dataclass.py

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ def test_something():
2222
["--inline-snapshot=fix"],
2323
changed_files=snapshot(
2424
{
25-
"test_something.py": """\
25+
"tests/test_something.py": """\
2626
from inline_snapshot import snapshot,Is
2727
from dataclasses import dataclass
2828
@@ -64,7 +64,7 @@ def test_something():
6464
["--inline-snapshot=fix"],
6565
changed_files=snapshot(
6666
{
67-
"test_something.py": """\
67+
"tests/test_something.py": """\
6868
from inline_snapshot import snapshot,Is
6969
from dataclasses import dataclass
7070
@@ -102,7 +102,7 @@ def test_something():
102102
["--inline-snapshot=update"],
103103
changed_files=snapshot(
104104
{
105-
"test_something.py": """\
105+
"tests/test_something.py": """\
106106
from inline_snapshot import snapshot,Is
107107
from dataclasses import dataclass,field
108108
@@ -141,7 +141,7 @@ def test_something():
141141
["--inline-snapshot=update"],
142142
changed_files=snapshot(
143143
{
144-
"test_something.py": """\
144+
"tests/test_something.py": """\
145145
from inline_snapshot import snapshot,Is
146146
from dataclasses import dataclass,field
147147
@@ -181,7 +181,7 @@ def test_something():
181181
["--inline-snapshot=fix"],
182182
changed_files=snapshot(
183183
{
184-
"test_something.py": """\
184+
"tests/test_something.py": """\
185185
from inline_snapshot import snapshot,Is
186186
import attrs
187187
@@ -203,7 +203,7 @@ def test_something():
203203
["--inline-snapshot=update"],
204204
changed_files=snapshot(
205205
{
206-
"test_something.py": """\
206+
"tests/test_something.py": """\
207207
from inline_snapshot import snapshot,Is
208208
import attrs
209209
@@ -241,7 +241,7 @@ def test_something():
241241
["--inline-snapshot=fix"],
242242
changed_files=snapshot(
243243
{
244-
"test_something.py": """\
244+
"tests/test_something.py": """\
245245
from inline_snapshot import snapshot,Is
246246
import attrs
247247
@@ -277,7 +277,7 @@ def test():
277277
["--inline-snapshot=create"],
278278
changed_files=snapshot(
279279
{
280-
"test_something.py": """\
280+
"tests/test_something.py": """\
281281
from inline_snapshot import snapshot
282282
import attrs
283283
@@ -403,7 +403,7 @@ def test_something():
403403
["--inline-snapshot=fix"],
404404
changed_files=snapshot(
405405
{
406-
"test_something.py": """\
406+
"tests/test_something.py": """\
407407
from inline_snapshot import snapshot
408408
from dataclasses import dataclass
409409
@@ -495,7 +495,7 @@ def test_L3():
495495
["--inline-snapshot=fix"],
496496
changed_files=snapshot(
497497
{
498-
"test_something.py": """\
498+
"tests/test_something.py": """\
499499
from inline_snapshot import snapshot
500500
501501
from inline_snapshot._adapter.generic_call_adapter import GenericCallAdapter,Argument
@@ -557,7 +557,7 @@ def test_tuple():
557557
["--inline-snapshot=fix"],
558558
changed_files=snapshot(
559559
{
560-
"test_something.py": """\
560+
"tests/test_something.py": """\
561561
from inline_snapshot import snapshot
562562
from collections import namedtuple
563563
@@ -588,7 +588,7 @@ def test_tuple():
588588
["--inline-snapshot=fix"],
589589
changed_files=snapshot(
590590
{
591-
"test_something.py": """\
591+
"tests/test_something.py": """\
592592
from inline_snapshot import snapshot
593593
from collections import defaultdict
594594
@@ -623,7 +623,7 @@ def test():
623623
["--inline-snapshot=create"],
624624
changed_files=snapshot(
625625
{
626-
"test_something.py": """\
626+
"tests/test_something.py": """\
627627
from inline_snapshot import snapshot
628628
from dataclasses import dataclass,field
629629
@@ -659,7 +659,7 @@ def test_list():
659659
["--inline-snapshot=update"],
660660
changed_files=snapshot(
661661
{
662-
"test_something.py": """\
662+
"tests/test_something.py": """\
663663
from inline_snapshot import snapshot,Is
664664
from dataclasses import dataclass,field
665665

tests/adapter/test_dict.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ def test_list():
1616
["--inline-snapshot=update"],
1717
changed_files=snapshot(
1818
{
19-
"test_something.py": """\
19+
"tests/test_something.py": """\
2020
from inline_snapshot import snapshot,Is
2121
2222
def test_list():

0 commit comments

Comments
 (0)