Skip to content

Commit 0270eaa

Browse files
authored
Merge pull request #8 from mutating/develop
0.0.8
2 parents edfdd70 + 1f73052 commit 0270eaa

16 files changed

Lines changed: 1063 additions & 38 deletions

File tree

README.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,12 @@ for file in crawler:
6767

6868
> ↑ This recursively prints all files in the current directory, including files in nested directories. At each iteration, we get a new [`Path` object](https://docs.python.org/3/library/pathlib.html#basic-use).
6969
70+
By default, crawlers iterate over files only. If you need every filesystem entity found under the base directory, pass `only_files=False`:
71+
72+
```python
73+
crawler = Crawler('.', only_files=False)
74+
```
75+
7076

7177
## Applying a Function to Each Path
7278

@@ -98,6 +104,8 @@ To set the file extensions you are interested in, use the `extensions` parameter
98104
crawler = Crawler('.', extensions=['.txt']) # Iterate only on .txt files.
99105
```
100106

107+
> ⓘ The `extensions` parameter is available only in the default file-only mode, so it cannot be combined with `only_files=False`. `PythonCrawler` is always file-only.
108+
101109
Also, if you only need Python files, you can use a special class to bypass them only, without specifying extensions:
102110

103111
```python

dirstree/__init__.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,6 @@
22
from dirstree.crawlers.python_crawler import (
33
PythonCrawler as PythonCrawler,
44
)
5+
from dirstree.errors import (
6+
IncompatibleCrawlerOptionsError as IncompatibleCrawlerOptionsError,
7+
)

dirstree/crawlers/crawler.py

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
from sigmatch import PossibleCallMatcher
88

99
from dirstree.crawlers.abstract import AbstractCrawler
10+
from dirstree.errors import IncompatibleCrawlerOptionsError
1011

1112

1213
# TODO: add typing tests
@@ -37,7 +38,14 @@ def __init__(
3738
exclude: Optional[List[str]] = None,
3839
filter: Optional[Callable[[Path], bool]] = None, # noqa: A002
3940
token: AbstractToken = DefaultToken(), # noqa: B008
41+
only_files: bool = True,
4042
) -> None:
43+
if extensions is not None and not only_files:
44+
raise IncompatibleCrawlerOptionsError(
45+
'The "extensions" and "only_files=False" options are incompatible: '
46+
'extensions can be applied only when the crawler yields files, '
47+
'because non-file filesystem entities do not have meaningful file extensions.',
48+
)
4149
if extensions is not None:
4250
for extension in extensions:
4351
if not extension.startswith('.'):
@@ -52,6 +60,7 @@ def __init__(
5260
self.exclude = exclude if exclude is not None else []
5361
self.filter = filter
5462
self.token = token
63+
self.only_files = only_files
5564

5665
self.addictional_repr_filters: Dict[str, Callable[[Any], bool]] = {}
5766

@@ -61,6 +70,7 @@ def __repr__(self) -> str:
6170
'exclude': lambda x: bool(x),
6271
'filter': not_none,
6372
'token': lambda x: not isinstance(x, DefaultToken),
73+
'only_files': lambda x: x is False,
6474
}
6575
filters.update(self.addictional_repr_filters)
6676

@@ -72,6 +82,7 @@ def __repr__(self) -> str:
7282
'exclude': self.exclude,
7383
'filter': self.filter,
7484
'token': self.token,
85+
'only_files': self.only_files,
7586
},
7687
filters=filters, # type: ignore[arg-type]
7788
)
@@ -86,8 +97,11 @@ def go(self, token: AbstractToken = DefaultToken()) -> Generator[Path, None, Non
8697
if token:
8798
for child_path in base_path.rglob('*'):
8899
if (
89-
child_path.is_file()
90-
and not excludes_spec.match_file(child_path)
100+
(not self.only_files or child_path.is_file())
101+
and not (
102+
excludes_spec.match_file(child_path)
103+
or (child_path.is_dir() and excludes_spec.match_file(f'{child_path}/'))
104+
)
91105
and (self.extensions is None or child_path.suffix in self.extensions)
92106
and (self.filter is None or self.filter(child_path))
93107
):

dirstree/errors.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
class DirstreeError(Exception):
2+
pass
3+
4+
5+
class IncompatibleCrawlerOptionsError(DirstreeError):
6+
pass

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
44

55
[project]
66
name = "dirstree"
7-
version = "0.0.7"
7+
version = "0.0.8"
88
authors = [{ name = "Evgeniy Blinov", email = "zheni-b@yandex.ru" }]
99
description = 'Another library for iterating through the contents of a directory'
1010
readme = "README.md"

tests/conftest.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,8 @@ def crawl_directory_path(request):
1212
@pytest.fixture(params=[str, Path])
1313
def second_crawl_directory_path(request):
1414
return request.param(os.path.join('tests', 'test_files', 'walk_it_2'))
15+
16+
17+
@pytest.fixture(params=[str, Path])
18+
def all_entities_directory_path(request):
19+
return request.param(os.path.join('tests', 'test_files', 'all_entities'))

0 commit comments

Comments
 (0)