Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.9] - (Unreleased)

### Changed

- `MemFS` now immediately releases all memory it holds when `close()` is called,
rather than when it gets garbage collected. Closes [issue #308](https://github.com/PyFilesystem/pyfilesystem2/issues/308).

## [2.4.8] - 2019-06-12

### Changed
Expand Down
1 change: 1 addition & 0 deletions CONTRIBUTORS.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

Many thanks to the following developers for contributing to this project:

- [Diego Argueta](https://github.com/dargueta)
- [Geoff Jukes](https://github.com/geoffjukes)
- [Giampaolo](https://github.com/gpcimino)
- [Martin Larralde](https://github.com/althonos)
Expand Down
5 changes: 5 additions & 0 deletions fs/memoryfs.py
Original file line number Diff line number Diff line change
Expand Up @@ -340,6 +340,11 @@ def _get_dir_entry(self, dir_path):
current_entry = current_entry.get_entry(path_component)
return current_entry

def close(self):
# type: () -> None
self.root = None
return super(MemoryFS, self).close()

def getinfo(self, path, namespaces=None):
# type: (Text, Optional[Collection[Text]]) -> Info
namespaces = namespaces or ()
Expand Down
55 changes: 55 additions & 0 deletions tests/test_memoryfs.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,68 @@
from __future__ import unicode_literals

import posixpath
import unittest

from fs import memoryfs
from fs.test import FSTestCases
from fs.test import UNICODE_TEXT

try:
# Only supported on Python 3.4+
import tracemalloc
except ImportError:
tracemalloc = None


class TestMemoryFS(FSTestCases, unittest.TestCase):
"""Test OSFS implementation."""

def make_fs(self):
return memoryfs.MemoryFS()

def _create_many_files(self):
for parent_dir in {"/", "/one", "/one/two", "/one/other-two/three"}:
self.fs.makedirs(parent_dir, recreate=True)
for file_id in range(50):
self.fs.writetext(
posixpath.join(parent_dir, str(file_id)), UNICODE_TEXT
)

@unittest.skipIf(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thorough test 👍

not tracemalloc, "`tracemalloc` isn't supported on this Python version."
)
def test_close_mem_free(self):
"""Ensure all file memory is freed when calling close().

Prevents regression against issue #308.
"""
trace_filters = [tracemalloc.Filter(True, "*/memoryfs.py")]
tracemalloc.start()

before = tracemalloc.take_snapshot().filter_traces(trace_filters)
self._create_many_files()
after_create = tracemalloc.take_snapshot().filter_traces(trace_filters)

self.fs.close()
after_close = tracemalloc.take_snapshot().filter_traces(trace_filters)
tracemalloc.stop()

[diff_create] = after_create.compare_to(
before, key_type="filename", cumulative=True
)
self.assertGreater(
diff_create.size_diff,
0,
"Memory usage didn't increase after creating files; diff is %0.2f KiB."
% (diff_create.size_diff / 1024.0),
)

[diff_close] = after_close.compare_to(
after_create, key_type="filename", cumulative=True
)
self.assertLess(
diff_close.size_diff,
0,
"Memory usage increased after closing the file system; diff is %0.2f KiB."
% (diff_close.size_diff / 1024.0),
)