diff --git a/CHANGELOG.md b/CHANGELOG.md index ef16734e..6d45213d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/). Closes [#459](https://github.com/PyFilesystem/pyfilesystem2/issues/459). ### Fixed +- Preserved concrete filesystem types when entering context managers. + Related to [#580](https://github.com/PyFilesystem/pyfilesystem2/issues/580). - Elaborated documentation of `filter_dirs` and `exclude_dirs` in `fs.walk.Walker`. Closes [#371](https://github.com/PyFilesystem/pyfilesystem2/issues/371). - Fixes a backward incompatibility where `fs.move.move_file` raises `DestinationExists` diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index 78102487..be9bc250 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -20,6 +20,7 @@ Many thanks to the following developers for contributing to this project: - [George Macon](https://github.com/gmacon) - [Giampaolo Cimino](https://github.com/gpcimino) - [@Hoboneer](https://github.com/Hoboneer) +- [Hugohong258](https://github.com/Hugohong258) - [Jen Hagg](https://github.com/jenhagg) - [Joseph Atkins-Turkish](https://github.com/Spacerat) - [Joshua Tauberer](https://github.com/JoshData) diff --git a/fs/base.py b/fs/base.py index d42997d4..792de74c 100644 --- a/fs/base.py +++ b/fs/base.py @@ -118,7 +118,7 @@ def __del__(self): self.close() def __enter__(self): - # type: (...) -> FS + # type: (_F) -> _F """Allow use of filesystem as a context manager.""" return self diff --git a/tests/test_context_typing.py b/tests/test_context_typing.py new file mode 100644 index 00000000..0960158f --- /dev/null +++ b/tests/test_context_typing.py @@ -0,0 +1,41 @@ +"""Check preservation of concrete filesystem types in context managers.""" +from __future__ import unicode_literals + +import unittest + +try: + from mypy import api as mypy_api +except ImportError: + mypy_api = None + + +class TestContextTyping(unittest.TestCase): + @unittest.skipIf(mypy_api is None, "mypy is not installed") + def test_context_manager_preserves_subclass_type(self): + source = """ +from fs.memoryfs import MemoryFS +from fs.osfs import OSFS +from fs.tempfs import TempFS + +def accepts_temp(fs): + # type: (TempFS) -> None + pass + +with TempFS() as temp: + accepts_temp(temp) + +with OSFS(".") as osfs: + concrete = osfs # type: OSFS + +class CustomFS(MemoryFS): + def custom_method(self): + # type: () -> int + return 1 + +with CustomFS() as custom: + custom.custom_method() +""" + output, error, status = mypy_api.run( + ["--follow-imports=silent", "--no-incremental", "-c", source] + ) + self.assertEqual(status, 0, output + error)