Skip to content

Commit 387f3bd

Browse files
committed
Merge branch 'main' into egg-metadata-work
2 parents 812db6f + 5811d73 commit 387f3bd

File tree

3 files changed

+141
-18
lines changed

3 files changed

+141
-18
lines changed

tests/_path.py

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
# from jaraco.path 3.5
2+
3+
import functools
4+
import pathlib
5+
from typing import Dict, Union
6+
7+
try:
8+
from typing import Protocol, runtime_checkable
9+
except ImportError: # pragma: no cover
10+
# Python 3.7
11+
from typing_extensions import Protocol, runtime_checkable # type: ignore
12+
13+
14+
FilesSpec = Dict[str, Union[str, bytes, 'FilesSpec']] # type: ignore
15+
16+
17+
@runtime_checkable
18+
class TreeMaker(Protocol):
19+
def __truediv__(self, *args, **kwargs):
20+
... # pragma: no cover
21+
22+
def mkdir(self, **kwargs):
23+
... # pragma: no cover
24+
25+
def write_text(self, content, **kwargs):
26+
... # pragma: no cover
27+
28+
def write_bytes(self, content):
29+
... # pragma: no cover
30+
31+
32+
def _ensure_tree_maker(obj: Union[str, TreeMaker]) -> TreeMaker:
33+
return obj if isinstance(obj, TreeMaker) else pathlib.Path(obj) # type: ignore
34+
35+
36+
def build(
37+
spec: FilesSpec,
38+
prefix: Union[str, TreeMaker] = pathlib.Path(), # type: ignore
39+
):
40+
"""
41+
Build a set of files/directories, as described by the spec.
42+
43+
Each key represents a pathname, and the value represents
44+
the content. Content may be a nested directory.
45+
46+
>>> spec = {
47+
... 'README.txt': "A README file",
48+
... "foo": {
49+
... "__init__.py": "",
50+
... "bar": {
51+
... "__init__.py": "",
52+
... },
53+
... "baz.py": "# Some code",
54+
... }
55+
... }
56+
>>> target = getfixture('tmp_path')
57+
>>> build(spec, target)
58+
>>> target.joinpath('foo/baz.py').read_text(encoding='utf-8')
59+
'# Some code'
60+
"""
61+
for name, contents in spec.items():
62+
create(contents, _ensure_tree_maker(prefix) / name)
63+
64+
65+
@functools.singledispatch
66+
def create(content: Union[str, bytes, FilesSpec], path):
67+
path.mkdir(exist_ok=True)
68+
build(content, prefix=path) # type: ignore
69+
70+
71+
@create.register
72+
def _(content: bytes, path):
73+
path.write_bytes(content)
74+
75+
76+
@create.register
77+
def _(content: str, path):
78+
path.write_text(content, encoding='utf-8')
79+
80+
81+
class Recording:
82+
"""
83+
A TreeMaker object that records everything that would be written.
84+
85+
>>> r = Recording()
86+
>>> build({'foo': {'foo1.txt': 'yes'}, 'bar.txt': 'abc'}, r)
87+
>>> r.record
88+
['foo/foo1.txt', 'bar.txt']
89+
"""
90+
91+
def __init__(self, loc=pathlib.PurePosixPath(), record=None):
92+
self.loc = loc
93+
self.record = record if record is not None else []
94+
95+
def __truediv__(self, other):
96+
return Recording(self.loc / other, self.record)
97+
98+
def write_text(self, content, **kwargs):
99+
self.record.append(str(self.loc))
100+
101+
write_bytes = write_text
102+
103+
def mkdir(self, **kwargs):
104+
return

tests/fixtures.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@
1111
from .py39compat import FS_NONASCII
1212
from typing import Dict, Union
1313

14+
from . import _path
15+
16+
1417
try:
1518
from importlib import resources # type: ignore
1619

@@ -359,6 +362,16 @@ def build_files(file_defs, prefix=pathlib.Path()):
359362
f.write(DALS(contents))
360363

361364

365+
def build_record(file_defs):
366+
return ''.join(f'{name},,\n' for name in record_names(file_defs))
367+
368+
369+
def record_names(file_defs):
370+
recording = _path.Recording()
371+
_path.build(file_defs, recording)
372+
return recording.record
373+
374+
362375
class FileBuilder:
363376
def unicode_filename(self):
364377
return FS_NONASCII or self.skip("File system does not support non-ascii.")

tests/test_main.py

Lines changed: 24 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import unittest
44
import importlib
55
import importlib_metadata
6+
import itertools
67
import pyfakefs.fake_filesystem_unittest as ffs
78

89
from . import fixtures
@@ -338,25 +339,30 @@ def test_packages_distributions_all_module_types(self):
338339
Test top-level modules detected on a package without 'top-level.txt'.
339340
"""
340341
suffixes = importlib.machinery.all_suffixes()
341-
fixtures.build_files(
342-
{
343-
'all_distributions-1.0.0.dist-info': {
344-
'METADATA': """
345-
Name: all_distributions
346-
Version: 1.0.0
347-
""",
348-
'RECORD': 'all_distributions-1.0.0.dist-info/METADATA\n'
349-
+ ''.join(
350-
f'importable-name {i}{suffix},,\n'
351-
f'in_namespace_{i}/mod{suffix},,\n'
352-
f'in_package_{i}/__init__.py,,\n'
353-
f'in_package_{i}/mod{suffix},,\n'
354-
for i, suffix in enumerate(suffixes)
355-
),
356-
},
357-
},
358-
prefix=self.site_dir,
342+
metadata = dict(
343+
METADATA="""
344+
Name: all_distributions
345+
Version: 1.0.0
346+
""",
359347
)
348+
files = {
349+
'all_distributions-1.0.0.dist-info': metadata,
350+
}
351+
for i, suffix in enumerate(suffixes):
352+
files.update(
353+
{
354+
f'importable-name {i}{suffix}': '',
355+
f'in_namespace_{i}': {
356+
f'mod{suffix}': '',
357+
},
358+
f'in_package_{i}': {
359+
'__init__.py': '',
360+
f'mod{suffix}': '',
361+
},
362+
}
363+
)
364+
metadata.update(RECORD=fixtures.build_record(files))
365+
fixtures.build_files(files, prefix=self.site_dir)
360366

361367
distributions = packages_distributions()
362368

0 commit comments

Comments
 (0)