Skip to content

Commit 9e4d4b9

Browse files
authored
implementation of glob (#209)
* implementation of glob * typing, count and remove * count lines * Add tests * tests * Refactor iter * docs * docs and refactor * polish * doc fix * doc * doc fix * fix and docs * version bump
1 parent 2f305b8 commit 9e4d4b9

File tree

17 files changed

+525
-30
lines changed

17 files changed

+525
-30
lines changed

CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,12 @@ All notable changes to this project will be documented in this file.
44
The format is based on [Keep a Changelog](http://keepachangelog.com/)
55
and this project adheres to [Semantic Versioning](http://semver.org/).
66

7+
## [2.1.0] - 2018-08-12
8+
9+
### Added
10+
11+
- fs.glob support
12+
713
## [2.0.27] - 2018-08-05
814

915
### Fixed
@@ -159,6 +165,7 @@ No changes, pushed wrong branch to PyPi.
159165
## [2.0.8] - 2017-08-13
160166

161167
### Added
168+
162169
- Lstat info namespace
163170
- Link info namespace
164171
- FS.islink method

docs/source/conf.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -302,3 +302,5 @@
302302

303303
# If true, do not generate a @detailmenu in the "Top" node's menu.
304304
#texinfo_no_detailmenu = False
305+
306+
napoleon_include_special_with_doc = True

docs/source/globbing.rst

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
.. _globbing:
2+
3+
Globbing
4+
========
5+
6+
Globbing is the process of matching paths according to the rules used
7+
by the Unix shell.
8+
9+
Generally speaking, you can think of a glob pattern as a path containing
10+
one or more wildcard patterns, separated by forward slashes.
11+
12+
13+
Matching Files and Directories
14+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
15+
16+
In a glob pattern, A ``*`` means match anything text in a filename. A ``?``
17+
matches any single character. A ``**`` matches any number of subdirectories,
18+
making the glob *recusrive*. If the glob pattern ends in a ``/``, it will
19+
only match directory paths, otherwise it will match files and directories.
20+
21+
.. note::
22+
A recursive glob requires that PyFilesystem scan a lot of files,
23+
and can potentially be slow for large (or network based) filesystems.
24+
25+
Here's a summary of glob patterns:
26+
27+
``*``
28+
Matches all files in the current directory.
29+
``*.py``
30+
Matches all .py file in the current directory.
31+
``*.py?``
32+
Matches all .py files and .pyi, .pyc etc in the currenct directory.
33+
``project/*.py``
34+
Matches all .py files in a directory called ``project``.
35+
``*/*.py``
36+
Matches all .py files in any sub directory.
37+
``**/*.py``
38+
Recursively matches all .py files.
39+
``**/.git/``
40+
Recursively matches all the git directories.
41+
42+
43+
Interface
44+
~~~~~~~~~
45+
46+
PyFilesystem supports globbing via the ``glob`` attribute on every FS
47+
instance, which is an instance of :class:`~fs.glob.BoundGlobber`. Here's
48+
how you might use it to find all the Python files in your filesystem::
49+
50+
for match in my_fs.glob("**/*.py"):
51+
print(f"{match.path} is {match.info.size} bytes long")
52+
53+
Calling ``.glob`` with a pattern will return an iterator of
54+
:class:`~fs.glob.GlobMatch` named tuples for each matching file or
55+
directory. A glob match contains two attributes; ``path`` which is the
56+
full path in the filesystem, and ``info`` which is an
57+
:class:`fs.info.Info` info object for the matched resource.
58+
59+
60+
Batch Methods
61+
~~~~~~~~~~~~~
62+
63+
In addition to iterating over the results, you can also call methods on
64+
the :class:`~fs.glob.Globber` which apply to every matched path.
65+
66+
For instance, here is how you can use glob to remove all ``.pyc`` files
67+
from a project directory::
68+
69+
>>> import fs
70+
>>> fs.open_fs('~/projects/my_project').glob('**/*.pyc').remove()
71+
29
72+

docs/source/guide.rst

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,20 @@ The ``walk`` attribute on FS objects is instance of a :class:`~fs.walk.BoundWalk
196196

197197
See :ref:`walking` for more information on walking directories.
198198

199+
Globbing
200+
~~~~~~~~
201+
202+
Closely related to walking a filesystem is *globbing*, which is a slightly higher level way of scanning filesystems. Paths can be filtered by a *glob* pattern, which is similar to a wildcard (such as ``*.py``), but can match multiple levels of a directory structure.
203+
204+
Here's an example of globbing, which removes all the ``.pyc`` files in your project directory::
205+
206+
>>> from fs import open_fs
207+
>>> open_fs('~/project').glob('**/*.pyc').remove()
208+
62
209+
210+
See :ref:`globbing` for more information.
211+
212+
199213
Moving and Copying
200214
~~~~~~~~~~~~~~~~~~
201215

docs/source/index.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ Contents:
1717
info.rst
1818
openers.rst
1919
walking.rst
20+
globbing.rst
2021
builtin.rst
2122
implementers.rst
2223
extension.rst

docs/source/reference.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ Reference
99
reference/copy.rst
1010
reference/enums.rst
1111
reference/errors.rst
12+
reference/glob.rst
1213
reference/info_objects.rst
1314
reference/filesize.rst
1415
reference/mirror.rst

docs/source/reference/glob.rst

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
fs.glob
2+
=======
3+
4+
.. automodule:: fs.glob
5+
:members:

fs/_version.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
"""Version, used in module and setup.py.
22
"""
3-
__version__ = "2.0.27"
3+
__version__ = "2.1.0"

fs/base.py

Lines changed: 12 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -6,34 +6,23 @@
66
77
"""
88

9-
from __future__ import absolute_import
10-
from __future__ import print_function
11-
from __future__ import unicode_literals
9+
from __future__ import absolute_import, print_function, unicode_literals
1210

1311
import abc
12+
import itertools
1413
import os
1514
import threading
1615
import time
1716
import typing
18-
from functools import partial
19-
2017
from contextlib import closing
21-
import itertools
18+
from functools import partial
2219

2320
import six
2421

25-
from . import copy
26-
from . import errors
27-
from . import fsencode
28-
from . import iotools
29-
from . import move
30-
from . import tools
31-
from . import walk
32-
from . import wildcard
22+
from . import copy, errors, fsencode, iotools, move, tools, walk, wildcard
23+
from .glob import BoundGlobber
3324
from .mode import validate_open_mode
34-
from .path import abspath
35-
from .path import join
36-
from .path import normpath
25+
from .path import abspath, join, normpath
3726
from .time import datetime_to_epoch
3827
from .walk import Walker
3928

@@ -108,6 +97,12 @@ def __exit__(
10897
"""
10998
self.close()
11099

100+
@property
101+
def glob(self):
102+
"""`~fs.glob.BoundGlobber`: a globber object..
103+
"""
104+
return BoundGlobber(self)
105+
111106
@property
112107
def walk(self):
113108
# type: (_F) -> BoundWalker[_F]

fs/copy.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ def copy_fs_if_newer(
7171
on_copy (callable):A function callback called after a single file copy
7272
is executed. Expected signature is ``(src_fs, src_path, dst_fs,
7373
dst_path)``.
74-
workers (int): Use `worker` threads to copy data, or ``0`` (default) for
74+
workers (int): Use ``worker`` threads to copy data, or ``0`` (default) for
7575
a single-threaded copy.
7676
7777
"""
@@ -269,7 +269,7 @@ def copy_dir(
269269
on_copy (callable, optional): A function callback called after
270270
a single file copy is executed. Expected signature is
271271
``(src_fs, src_path, dst_fs, dst_path)``.
272-
workers (int): Use `worker` threads to copy data, or ``0`` (default) for
272+
workers (int): Use ``worker`` threads to copy data, or ``0`` (default) for
273273
a single-threaded copy.
274274
275275
"""
@@ -330,7 +330,7 @@ def copy_dir_if_newer(
330330
on_copy (callable, optional): A function callback called after
331331
a single file copy is executed. Expected signature is
332332
``(src_fs, src_path, dst_fs, dst_path)``.
333-
workers (int): Use `worker` threads to copy data, or ``0`` (default) for
333+
workers (int): Use ``worker`` threads to copy data, or ``0`` (default) for
334334
a single-threaded copy.
335335
336336
"""

0 commit comments

Comments
 (0)