diff --git a/CHANGELOG.md b/CHANGELOG.md index 857a9476..752ed141 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,13 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/) and this project adheres to [Semantic Versioning](http://semver.org/). +## [2.4.3] - 2019-02-23 + +### Fixed + +- Fixed broken "case_insensitive" check +- Fixed Windows test fails + ## [2.4.2] - 2019-02-22 ### Fixed diff --git a/appveyor.yml b/appveyor.yml index 2124bf6a..6cdb3773 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -5,24 +5,25 @@ environment: # The list here is complete (excluding Python 2.6, which # isn't covered by this document) at the time of writing. - - PYTHON: "C:\\Python27" - - PYTHON: "C:\\Python33" - - PYTHON: "C:\\Python34" - - PYTHON: "C:\\Python35" - - PYTHON: "C:\\Python27-x64" - - PYTHON: "C:\\Python33-x64" - DISTUTILS_USE_SDK: "1" - - PYTHON: "C:\\Python34-x64" - DISTUTILS_USE_SDK: "1" - - PYTHON: "C:\\Python35-x64" + # - PYTHON: "C:\\Python27" + # - PYTHON: "C:\\Python33" + # - PYTHON: "C:\\Python34" + # - PYTHON: "C:\\Python35" + # - PYTHON: "C:\\Python27-x64" + # - PYTHON: "C:\\Python33-x64" + # DISTUTILS_USE_SDK: "1" + # - PYTHON: "C:\\Python34-x64" + # DISTUTILS_USE_SDK: "1" + # - PYTHON: "C:\\Python35-x64" - PYTHON: "C:\\Python36-x64" + - PYTHON: "C:\\Python37-x64" install: # We need wheel installed to build wheels - - "%PYTHON%\\python.exe -m pip install nose pyftpdlib mock" + - "%PYTHON%\\python.exe -m pip install nose psutil pyftpdlib mock" - "%PYTHON%\\python.exe setup.py install" build: off test_script: - - "%PYTHON%\\python.exe -m nose tests" + - "%PYTHON%\\python.exe -m nose tests -v" diff --git a/fs/_version.py b/fs/_version.py index d2bcc700..96b96f17 100644 --- a/fs/_version.py +++ b/fs/_version.py @@ -1,3 +1,3 @@ """Version, used in module and setup.py. """ -__version__ = "2.4.2" +__version__ = "2.4.3" diff --git a/fs/osfs.py b/fs/osfs.py index e10ebc12..20dee97c 100644 --- a/fs/osfs.py +++ b/fs/osfs.py @@ -47,7 +47,7 @@ from .permissions import Permissions from .error_tools import convert_os_errors from .mode import Mode, validate_open_mode -from .errors import NoURL +from .errors import FileExpected, NoURL if False: # typing.TYPE_CHECKING from typing import ( @@ -134,7 +134,7 @@ def __init__( raise errors.CreateFailed("root path does not exist") _meta = self._meta = { - "case_insensitive": os.path.normcase("Aa") != "aa", + "case_insensitive": os.path.normcase("Aa") == "aa", "network": False, "read_only": False, "supports_rename": True, @@ -245,12 +245,17 @@ def _get_type_from_stat(cls, _stat): def _gettarget(self, sys_path): # type: (Text) -> Optional[Text] - try: - target = os.readlink(fsencode(sys_path)) - except OSError: - return None - else: - return target + if hasattr(os, "readlink"): + try: + if _WINDOWS_PLATFORM: # pragma: no cover + target = os.readlink(sys_path) + else: + target = os.readlink(fsencode(sys_path)) + except OSError: + pass + else: + return target + return None def _make_link_info(self, sys_path): # type: (Text) -> Dict[Text, object] @@ -328,6 +333,8 @@ def openbin(self, path, mode="r", buffering=-1, **options): _mode.validate_bin() self.check() _path = self.validatepath(path) + if _path == "/": + raise errors.FileExpected(path) sys_path = self._to_sys_path(_path) with convert_os_errors("openbin", path): if six.PY2 and _mode.exclusive: @@ -454,7 +461,12 @@ def _scandir(self, path, namespaces=None): self.check() namespaces = namespaces or () _path = self.validatepath(path) - sys_path = self._to_sys_path(_path) + if _WINDOWS_PLATFORM: + sys_path = os.path.join( + self._root_path, path.lstrip("/").replace("/", os.sep) + ) + else: + sys_path = self._to_sys_path(_path) with convert_os_errors("scandir", path, directory=True): for dir_entry in scandir(sys_path): info = { @@ -595,6 +607,8 @@ def open( validate_open_mode(mode) self.check() _path = self.validatepath(path) + if _path == "/": + raise FileExpected(path) sys_path = self._to_sys_path(_path) with convert_os_errors("open", path): if six.PY2 and _mode.exclusive: diff --git a/tests/test_archives.py b/tests/test_archives.py index 1873718b..c0bfff3b 100644 --- a/tests/test_archives.py +++ b/tests/test_archives.py @@ -86,9 +86,10 @@ def test_getinfo(self): except errors.NoSysPath: pass else: - self.assertEqual( - top.permissions.mode, stat.S_IMODE(os.stat(source_syspath).st_mode) - ) + if top.has_namespace("access"): + self.assertEqual( + top.permissions.mode, stat.S_IMODE(os.stat(source_syspath).st_mode) + ) self.assertEqual(top.get("details", "type"), ResourceType.file) diff --git a/tests/test_encoding.py b/tests/test_encoding.py index 6c15f7e9..0cd91d4c 100644 --- a/tests/test_encoding.py +++ b/tests/test_encoding.py @@ -12,43 +12,48 @@ from fs.osfs import OSFS -@unittest.skipIf(platform.system() == "Darwin", "Bad unicode not possible on OSX") -class TestEncoding(unittest.TestCase): - - TEST_FILENAME = b"foo\xb1bar" - TEST_FILENAME_UNICODE = fs.fsdecode(TEST_FILENAME) - - def setUp(self): - dir_path = self.dir_path = tempfile.mkdtemp() - if six.PY2: - with open(os.path.join(dir_path, self.TEST_FILENAME), "wb") as f: - f.write(b"baz") - else: - with open(os.path.join(dir_path, self.TEST_FILENAME_UNICODE), "wb") as f: - f.write(b"baz") - - def tearDown(self): - shutil.rmtree(self.dir_path) - - def test_open(self): - with OSFS(self.dir_path) as test_fs: - self.assertTrue(test_fs.exists(self.TEST_FILENAME_UNICODE)) - self.assertTrue(test_fs.isfile(self.TEST_FILENAME_UNICODE)) - self.assertFalse(test_fs.isdir(self.TEST_FILENAME_UNICODE)) - with test_fs.open(self.TEST_FILENAME_UNICODE, "rb") as f: - self.assertEqual(f.read(), b"baz") - self.assertEqual(test_fs.readtext(self.TEST_FILENAME_UNICODE), "baz") - test_fs.remove(self.TEST_FILENAME_UNICODE) - self.assertFalse(test_fs.exists(self.TEST_FILENAME_UNICODE)) - - def test_listdir(self): - with OSFS(self.dir_path) as test_fs: - dirlist = test_fs.listdir("/") - self.assertEqual(dirlist, [self.TEST_FILENAME_UNICODE]) - self.assertEqual(test_fs.readtext(dirlist[0]), "baz") - - def test_scandir(self): - with OSFS(self.dir_path) as test_fs: - for info in test_fs.scandir("/"): - self.assertIsInstance(info.name, six.text_type) - self.assertEqual(info.name, self.TEST_FILENAME_UNICODE) +if platform.system() != "Windows": + + @unittest.skipIf(platform.system() == "Darwin", "Bad unicode not possible on OSX") + class TestEncoding(unittest.TestCase): + + TEST_FILENAME = b"foo\xb1bar" + # fsdecode throws error on Windows + TEST_FILENAME_UNICODE = fs.fsdecode(TEST_FILENAME) + + def setUp(self): + dir_path = self.dir_path = tempfile.mkdtemp() + if six.PY2: + with open(os.path.join(dir_path, self.TEST_FILENAME), "wb") as f: + f.write(b"baz") + else: + with open( + os.path.join(dir_path, self.TEST_FILENAME_UNICODE), "wb" + ) as f: + f.write(b"baz") + + def tearDown(self): + shutil.rmtree(self.dir_path) + + def test_open(self): + with OSFS(self.dir_path) as test_fs: + self.assertTrue(test_fs.exists(self.TEST_FILENAME_UNICODE)) + self.assertTrue(test_fs.isfile(self.TEST_FILENAME_UNICODE)) + self.assertFalse(test_fs.isdir(self.TEST_FILENAME_UNICODE)) + with test_fs.open(self.TEST_FILENAME_UNICODE, "rb") as f: + self.assertEqual(f.read(), b"baz") + self.assertEqual(test_fs.readtext(self.TEST_FILENAME_UNICODE), "baz") + test_fs.remove(self.TEST_FILENAME_UNICODE) + self.assertFalse(test_fs.exists(self.TEST_FILENAME_UNICODE)) + + def test_listdir(self): + with OSFS(self.dir_path) as test_fs: + dirlist = test_fs.listdir("/") + self.assertEqual(dirlist, [self.TEST_FILENAME_UNICODE]) + self.assertEqual(test_fs.readtext(dirlist[0]), "baz") + + def test_scandir(self): + with OSFS(self.dir_path) as test_fs: + for info in test_fs.scandir("/"): + self.assertIsInstance(info.name, six.text_type) + self.assertEqual(info.name, self.TEST_FILENAME_UNICODE) diff --git a/tests/test_ftpfs.py b/tests/test_ftpfs.py index 8f64e279..77b4a4b6 100644 --- a/tests/test_ftpfs.py +++ b/tests/test_ftpfs.py @@ -25,6 +25,7 @@ from fs import errors from fs.opener import open_fs from fs.ftpfs import FTPFS, ftp_errors +from fs.path import join from fs.subfs import SubFS from fs.test import FSTestCases @@ -200,7 +201,7 @@ def test_opener_path(self): def test_create(self): - directory = os.path.join("home", self.user, "test", "directory") + directory = join("home", self.user, "test", "directory") base = "ftp://user:1234@{}:{}/foo".format(self.server.host, self.server.port) url = "{}/{}".format(base, directory) @@ -215,7 +216,7 @@ def test_create(self): # Open the base filesystem and check the subdirectory exists with open_fs(base) as ftp_fs: self.assertTrue(ftp_fs.isdir(directory)) - self.assertTrue(ftp_fs.isfile(os.path.join(directory, "foo"))) + self.assertTrue(ftp_fs.isfile(join(directory, "foo"))) # Open without `create` and check the file exists with open_fs(url) as ftp_fs: diff --git a/tests/test_osfs.py b/tests/test_osfs.py index 59d2ab6a..09c74df9 100644 --- a/tests/test_osfs.py +++ b/tests/test_osfs.py @@ -115,6 +115,7 @@ def test_unicode_paths(self): finally: shutil.rmtree(dir_path) + @unittest.skipIf(not hasattr(os, "symlink"), "No symlink support") def test_symlinks(self): with open(self._get_real_path("foo"), "wb") as f: f.write(b"foobar") diff --git a/tests/test_tarfs.py b/tests/test_tarfs.py index 2603582b..0ce09606 100644 --- a/tests/test_tarfs.py +++ b/tests/test_tarfs.py @@ -26,6 +26,7 @@ class TestWriteReadTarFS(unittest.TestCase): def setUp(self): fh, self._temp_path = tempfile.mkstemp() + os.close(fh) def tearDown(self): os.remove(self._temp_path) diff --git a/tests/test_zipfs.py b/tests/test_zipfs.py index c8c7ad76..421d80d8 100644 --- a/tests/test_zipfs.py +++ b/tests/test_zipfs.py @@ -22,6 +22,7 @@ class TestWriteReadZipFS(unittest.TestCase): def setUp(self): fh, self._temp_path = tempfile.mkstemp() + os.close(fh) def tearDown(self): os.remove(self._temp_path)