Repository: PyFilesystem/pyfilesystem2 (python)

Issue:
fs/_ftp_parse.py fails when parsing directory listing on NT format if folder or filename contains AM or PM
The regex pattern used to parse the directory listing for NT servers uses a greedy (default) pattern when parsing the modified date column. This causes the `(<modified>)` capture group to capture until the last AM or PM, which could be in the file name.

Example file listing that fails:
```
01-29-20  04:11AM       <DIR>          Clock at AM or PM
```
This fails with the following trace
```
  File ".venv\lib\site-packages\fs\ftpfs.py", line 746, in scandir
    if not self.supports_mlst and not self.getinfo(path).is_dir:
  File ".venv\lib\site-packages\fs\ftpfs.py", line 614, in getinfo
    directory = self._read_dir(dir_name)
  File ".venv\lib\site-packages\fs\ftpfs.py", line 495, in _read_dir
    _list = [Info(raw_info) for raw_info in ftp_parse.parse(lines)]
  File ".venv\lib\site-packages\fs\_ftp_parse.py", line 70, in parse
    raw_info = parse_line(line)
  File ".venv\lib\site-packages\fs\_ftp_parse.py", line 81, in parse_line
    return decode_callable(line, match)
  File ".venv\lib\site-packages\fs\_ftp_parse.py", line 163, in decode_windowsnt
    raw_info["details"]["size"] = int(match.group("size"))
ValueError: invalid literal for int() with base 10: ''
```



Pull request description:
Use a non-greedy pattern when capturing modified (#395)
By making this capture pattern non-greedy it will no longer
capture until the last AM or PM in a directory listing line.

## Type of changes

- [x] Bug fix
- [ ] New feature
- [ ] Documentation / docstrings
- [ ] Tests
- [ ] Other

## Checklist

- [x] I've run the latest [black](https://github.com/ambv/black) with default args on new code.
- [x] I've updated CHANGELOG.md and CONTRIBUTORS.md where appropriate.
- [x] I've added tests for new code.
- [x] I accept that @willmcgugan may be pedantic in the code review.

## Description

Fixes #395 by using a non-greedy pattern for capturing the modified time from a NT directory listing (similar as is done for Linux)

Updated the WindowsNT test to catch a regression for this in the future.

```
 coverage run -m pytest --cov-append .\tests\test_ftp_parse.py
=============================================================================== test session starts =============================================================================== 
platform win32 -- Python 3.7.2, pytest-4.6.5, py-1.8.1, pluggy-0.13.1
Using --randomly-seed=1589597818
rootdir: C:\dev\pyfilesystem2, inifile: setup.cfg
plugins: cov-2.7.1, randomly-3.0.0
collected 5 items                                                                                                                                                                   

tests\test_ftp_parse.py .....                                                                                                                                                [100%] 

============================================================================ 5 passed in 0.20 seconds ============================================================================= ```


Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 0449d14..7cec240 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -16,6 +16,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
   ensuring `conftest.py` is present, fixes [#364](https://github.com/PyFilesystem/pyfilesystem2/issues/364).
 - Stop patching copy with Python 3.8+ because it already uses sendfile.
 - Fixed crash when CPython's -OO flag is used
+- Fixed error when parsing timestamps from a FTP directory served from a WindowsNT FTP Server, fixes [#395](https://github.com/PyFilesystem/pyfilesystem2/issues/395).
 
 ## [2.4.11] - 2019-09-07
 
diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md
index de54b66..3b3e8c2 100644
--- a/CONTRIBUTORS.md
+++ b/CONTRIBUTORS.md
@@ -11,3 +11,4 @@ Many thanks to the following developers for contributing to this project:
 - [Martin Larralde](https://github.com/althonos)
 - [Will McGugan](https://github.com/willmcgugan)
 - [Zmej Serow](https://github.com/zmej-serow)
+- [Morten Engelhardt Olsen](https://github.com/xoriath)
diff --git a/fs/_ftp_parse.py b/fs/_ftp_parse.py
index b50f75e..b503d73 100644
--- a/fs/_ftp_parse.py
+++ b/fs/_ftp_parse.py
@@ -41,7 +41,7 @@ RE_LINUX = re.compile(
 RE_WINDOWSNT = re.compile(
     r"""
     ^
-    (?P<modified>.*(AM|PM))
+    (?P<modified>.*?(AM|PM))
     \s*
     (?P<size>(<DIR>|\d*))
     \s*


Test patch:
diff --git a/tests/test_ftp_parse.py b/tests/test_ftp_parse.py
index c649a1f..d0abc05 100644
--- a/tests/test_ftp_parse.py
+++ b/tests/test_ftp_parse.py
@@ -166,6 +166,7 @@ drwxr-xr-x   2 foo-user foo-group         0 Jan  5 11:59 240485
         directory = """\
 11-02-17  02:00AM       <DIR>          docs
 11-02-17  02:12PM       <DIR>          images
+11-02-17  02:12PM       <DIR>          AM to PM
 11-02-17  03:33PM                 9276 logo.gif
 """
         expected = [
@@ -183,6 +184,13 @@ drwxr-xr-x   2 foo-user foo-group         0 Jan  5 11:59 240485
                     "ls": "11-02-17  02:12PM       <DIR>          images"
                 },
             },
+            {
+                "basic": {"is_dir": True, "name": "AM to PM"},
+                "details": {"modified": 1486822320.0, "type": 1},
+                "ftp": {
+                    "ls": "11-02-17  02:12PM       <DIR>          AM to PM"
+                },
+            },
             {
                 "basic": {"is_dir": False, "name": "logo.gif"},
                 "details": {"modified": 1486827180.0, "size": 9276, "type": 2},