Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
47b6239
Add disclaimer about the `writeable` parameter of `fs.open_fs`
althonos Mar 25, 2021
8e7a2e9
Add a loader for doctests to the unittest suite
althonos Mar 25, 2021
64ba8ce
Fix docstrings of various `fs` submodules to pass the doctests
althonos Mar 25, 2021
b95adcb
Add some more examples opening a FTPFS in `fs.ftpfs` module
althonos Mar 25, 2021
69fb190
Add `TempFS.close` docstring with a warning about the `auto_clean` pa…
althonos Mar 25, 2021
9291f78
Remove unused imports in `fs.path` and `tests.test_doctest`
althonos Mar 25, 2021
8388a02
Remove empty line from `fs.walk.Walk.bind` docstring
althonos Mar 25, 2021
3404061
Add a workaround for `pytest` not supporting the `load_tests` protocol
althonos Mar 25, 2021
3ea23b5
Fix type annotation and docs of `temp_fs` parameter of archive FS
althonos Mar 25, 2021
f640b9c
Document some exceptions expected on edge cases of `fs.base.FS` methods
althonos Mar 25, 2021
61db5b0
Ignore type-checking branches when measuring coverage
althonos Mar 25, 2021
b5cc24f
Add overloaded annotations of `epoch_to_datetime` to `fs.time`
althonos Mar 25, 2021
5bc93ef
Remove compatibility code from `tests.test_doctest`
althonos Mar 25, 2021
902362d
Add some examples showing how to build a `TempFS`
althonos Mar 26, 2021
9a576d8
Rewrite docstrings of some private helpers in `doctest` format so the…
althonos Mar 26, 2021
7dbeb88
Improve `Info.is_writable` to document the `_write` key of every name…
althonos Mar 26, 2021
55d2b37
Standardize behaviour of `removetree("/")` and add test case to `FSTe…
althonos Mar 27, 2021
97056de
Fix `WrapFS.removetree` so that it respects the root path semantics
althonos Mar 27, 2021
65ad3f7
Explicitly check the *basic* namespace is always returned by `FS.geti…
althonos Mar 27, 2021
53f6e14
Deprecate `FS.getbasic` since it is superseded by `FS.getinfo`
althonos Mar 27, 2021
7fe529b
Document more of the expected exceptions in `fs.base.FS` interface
althonos Mar 27, 2021
41fd7ef
Illustrate how to use a proxy server in `FTPFS`
althonos Mar 27, 2021
41bbe3c
Update `CHANGELOG.md` with changes introduced in #467
althonos Mar 27, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 13 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
[#449](https://github.com/PyFilesystem/pyfilesystem2/pull/449).
- `PathError` now supports wrapping an exception using the `exc` argument.
Closes [#453](https://github.com/PyFilesystem/pyfilesystem2/issues/453).
- Better documentation of the `writable` parameter of `fs.open_fs`, and
hint about using `fs.wrap.read_only` when a read-only filesystem is
required. Closes [#441](https://github.com/PyFilesystem/pyfilesystem2/issues/441).

### Changed

Expand All @@ -28,7 +31,13 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
- `FSTestCases` now builds the large data required for `upload` and `download` tests only
once in order to reduce the total testing time.
- `MemoryFS.move` and `MemoryFS.movedir` will now avoid copying data.
Closes [#452](https://github.com/PyFilesystem/pyfilesystem2/issues/452).
Closes [#452](https://github.com/PyFilesystem/pyfilesystem2/issues/452).
- `FS.removetree("/")` behaviour has been standardized in all filesystems, and
is expected to clear the contents of the root folder without deleting it.
Closes [#471](https://github.com/PyFilesystem/pyfilesystem2/issues/471).
- `FS.getbasic` is now deprecated, as it is redundant with `FS.getinfo`,
and `FS.getinfo` is now explicitly expected to return the *basic* info
namespace unconditionally. Closes [#469](https://github.com/PyFilesystem/pyfilesystem2/issues/469).

### Fixed

Expand All @@ -40,8 +49,10 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
- `WrapCachedDir.isdir` and `WrapCachedDir.isfile` raising a `ResourceNotFound` error on non-existing path ([#470](https://github.com/PyFilesystem/pyfilesystem2/pull/470)).
- `FTPFS` not listing certain entries with sticky/SUID/SGID permissions set by Linux server ([#473](https://github.com/PyFilesystem/pyfilesystem2/pull/473)).
Closes [#451](https://github.com/PyFilesystem/pyfilesystem2/issues/451).
- `scandir` iterator not being closed explicitly in `OSFS.scandir`, occasionally causing a `ResourceWarning`
- `scandir` iterator not being closed explicitly in `OSFS.scandir`, occasionally causing a `ResourceWarning`
to be thrown. Closes [#311](https://github.com/PyFilesystem/pyfilesystem2/issues/311).
- Incomplete type annotations for the `temp_fs` parameter of `WriteTarFS` and `WriteZipFS`.
Closes [#410](https://github.com/PyFilesystem/pyfilesystem2/issues/410).


## [2.4.12] - 2021-01-14
Expand Down
35 changes: 27 additions & 8 deletions fs/_ftp_parse.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,9 +56,7 @@


def get_decoders():
"""
Returns all available FTP LIST line decoders with their matching regexes.
"""
"""Return all available FTP LIST line decoders with their matching regexes."""
decoders = [
(RE_LINUX, decode_linux),
(RE_WINDOWSNT, decode_windowsnt),
Expand Down Expand Up @@ -149,13 +147,34 @@ def _decode_windowsnt_time(mtime):


def decode_windowsnt(line, match):
"""
Decodes a Windows NT FTP LIST line like one of these:
"""Decode a Windows NT FTP LIST line.

Examples:
Decode a directory line::

>>> line = "11-02-18 02:12PM <DIR> images"
>>> match = RE_WINDOWSNT.match(line)
>>> pprint(decode_windowsnt(line, match))
{'basic': {'is_dir': True, 'name': 'images'},
'details': {'modified': 1518358320.0, 'type': 1},
'ftp': {'ls': '11-02-18 02:12PM <DIR> images'}}

Decode a file line::

>>> line = "11-02-18 03:33PM 9276 logo.gif"
>>> match = RE_WINDOWSNT.match(line)
>>> pprint(decode_windowsnt(line, match))
{'basic': {'is_dir': False, 'name': 'logo.gif'},
'details': {'modified': 1518363180.0, 'size': 9276, 'type': 2},
'ftp': {'ls': '11-02-18 03:33PM 9276 logo.gif'}}

Alternatively, the time might also be present in 24-hour format::

`11-02-18 02:12PM <DIR> images`
`11-02-18 03:33PM 9276 logo.gif`
>>> line = "11-02-18 15:33 9276 logo.gif"
>>> match = RE_WINDOWSNT.match(line)
>>> decode_windowsnt(line, match)["details"]["modified"]
1518363180.0

Alternatively, the time (02:12PM) might also be present in 24-hour format (14:12).
"""
is_dir = match.group("size") == "<DIR>"

Expand Down
2 changes: 1 addition & 1 deletion fs/_repr.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ def make_repr(class_name, *args, **kwargs):
>>> MyClass('Will')
MyClass('foo', name='Will')
>>> MyClass(None)
MyClass()
MyClass('foo')

"""
arguments = [repr(arg) for arg in args]
Expand Down
30 changes: 17 additions & 13 deletions fs/_url_tools.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,15 @@

def url_quote(path_snippet):
# type: (Text) -> Text
"""
On Windows, it will separate drive letter and quote windows
path alone. No magic on Unix-alie path, just pythonic
`pathname2url`
"""Quote a URL without quoting the Windows drive letter, if any.

On Windows, it will separate drive letter and quote Windows
path alone. No magic on Unix-like path, just pythonic
`~urllib.request.pathname2url`.

Arguments:
path_snippet: a file path, relative or absolute.
path_snippet (str): a file path, relative or absolute.

"""
if _WINDOWS_PLATFORM and _has_drive_letter(path_snippet):
drive_letter, path = path_snippet.split(":", 1)
Expand All @@ -34,17 +36,19 @@ def url_quote(path_snippet):

def _has_drive_letter(path_snippet):
# type: (Text) -> bool
"""
The following path will get True
D:/Data
C:\\My Dcouments\\ test
"""Check whether a path contains a drive letter.

And will get False
Arguments:
path_snippet (str): a file path, relative or absolute.

/tmp/abc:test
Example:
>>> _has_drive_letter("D:/Data")
True
>>> _has_drive_letter(r"C:\\System32\\ test")
True
>>> _has_drive_letter("/tmp/abc:test")
False

Arguments:
path_snippet: a file path, relative or absolute.
"""
windows_drive_pattern = ".:[/\\\\].*$"
return re.match(windows_drive_pattern, path_snippet) is not None
Loading