Skip to content

Commit cd139cb

Browse files
committed
use FS URLs in multi and mount fs
1 parent 6f0e3a5 commit cd139cb

File tree

10 files changed

+135
-10
lines changed

10 files changed

+135
-10
lines changed

fs/base.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1204,7 +1204,7 @@ def check(self):
12041204
Check a filesystem may be used.
12051205
12061206
Will throw a :class:`~fs.errors.FilesystemClosed` if the
1207-
filesystem is closed.
1207+
filesystem is closed.
12081208
12091209
:returns: None
12101210
:raises fs.errors.FilesystemClosed: if the filesystem

fs/iotools.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,6 @@ def __iter__(self):
115115
return iter(self._f)
116116

117117

118-
119118
def make_stream(name,
120119
bin_file,
121120
mode='r',

fs/mountfs.py

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
from __future__ import print_function
33
from __future__ import unicode_literals
44

5+
from six import text_type
6+
57
from . import errors
68
from .base import FS
79
from .memoryfs import MemoryFS
@@ -67,10 +69,19 @@ def mount(self, path, fs):
6769
6870
:param path: A path within the MountFS.
6971
:type path: str
70-
:param fs: A filesystem object to mount.
72+
:param fs: A filesystem object or FS URL to mount.
7173
:type fs: :class:`~fs.base.FS`
7274
7375
"""
76+
if isinstance(fs, text_type):
77+
from .opener import open_fs
78+
fs = open_fs(fs)
79+
80+
if not isinstance(fs, FS):
81+
raise TypeError(
82+
'fs argument must be an FS object or a FS URL'
83+
)
84+
7485
if fs is self:
7586
raise ValueError('Unable to mount self')
7687
_path = forcedir(abspath(normpath(path)))

fs/multifs.py

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,21 @@
55
from collections import namedtuple
66
from operator import itemgetter
77

8+
from six import text_type
9+
810
from .base import FS
911
from .mode import check_writable
1012
from . import errors
13+
from .opener import open_fs
1114
from .path import abspath, normpath
1215

1316

1417
_PrioritizedFS = namedtuple(
1518
'_PrioritizedFS',
16-
['priority', 'fs']
19+
[
20+
'priority',
21+
'fs'
22+
]
1723
)
1824

1925

@@ -61,8 +67,8 @@ def add_fs(self, name, fs, write=False, priority=0):
6167
:param name: A unique name to refer to the filesystem being
6268
added.
6369
:type name: str
64-
:param fs: The filesystem to add
65-
:type fs: Filesystem
70+
:param fs: The filesystem to add.
71+
:type fs: Filesystem or FS URL.
6672
:param write: If this value is True, then the ``fs`` will be
6773
used as the writeable FS.
6874
:type write: bool
@@ -75,6 +81,14 @@ def add_fs(self, name, fs, write=False, priority=0):
7581
7682
"""
7783

84+
if isinstance(fs, text_type):
85+
fs = open_fs(fs)
86+
87+
if not isinstance(fs, FS):
88+
raise TypeError(
89+
'fs argument should be an FS object or FS URL'
90+
)
91+
7892
self._filesystems[name] = _PrioritizedFS(
7993
priority=(priority, self._sort_index),
8094
fs=fs

fs/opener/appfs.py

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
# coding: utf-8
2+
"""Defines the MemOpener."""
3+
4+
from __future__ import absolute_import
5+
from __future__ import print_function
6+
from __future__ import unicode_literals
7+
8+
from .base import Opener
9+
from .errors import OpenerError
10+
from .. import appfs
11+
12+
13+
class Opener(Opener):
14+
15+
protocols = [
16+
'userdata',
17+
'userconf',
18+
'sitedata',
19+
'siteconf',
20+
'usercache',
21+
'userlog'
22+
]
23+
24+
_protocol_mapping = {
25+
'userdata': appfs.UserDataFS,
26+
'userconf': appfs.UserConfigFS,
27+
'sitedata': appfs.SiteDataFS,
28+
'siteconf': appfs.SiteConfigFS,
29+
'usercache': appfs.UserCacheFS,
30+
'userlog': appfs.UserLogFS
31+
}
32+
33+
def open_fs(self, fs_url, parse_result, writeable, create, cwd):
34+
fs_class = self._protocol_mapping[parse_result.protocol]
35+
36+
tokens = parse_result.resource.split(':', 3)
37+
if len(tokens) == 2:
38+
appname, author = tokens
39+
version = None
40+
elif len(tokens) == 3:
41+
appname, author, version = tokens
42+
else:
43+
raise OpenerError(
44+
'resource should be <appname>:<author> '
45+
'or <appname>:<author>:<version'
46+
)
47+
48+
fs_instance = fs_class(
49+
appname,
50+
author=author,
51+
version=version,
52+
create=create
53+
)
54+
return fs_instance
55+

fs/wrapfs.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,6 @@ def delegate_fs(self):
7070
"""
7171
return self._wrap_fs
7272

73-
7473
def appendbytes(self, path, data):
7574
self.check()
7675
_fs, _path = self.delegate_path(path)
@@ -88,7 +87,6 @@ def appendtext(self, path, text,
8887
errors=errors,
8988
newline=newline)
9089

91-
9290
def getinfo(self, path, namespaces=None):
9391
self.check()
9492
_fs, _path = self.delegate_path(path)

setup.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,13 @@
4747
'tar = fs.opener.tarfs:TarOpener',
4848
'temp = fs.opener.tempfs:TempOpener',
4949
'zip = fs.opener.zipfs:ZipOpener',
50+
51+
'userdata = fs.opener.appfs:Opener',
52+
'userconf = fs.opener.appfs:Opener',
53+
'sitedata = fs.opener.appfs:Opener',
54+
'siteconf = fs.opener.appfs:Opener',
55+
'usercache = fs.opener.appfs:Opener',
56+
'userlog = fs.opener.appfs:Opener',
5057
]},
5158
license="MIT",
5259
long_description=DESCRIPTION,

tests/test_mountfs.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,15 +30,21 @@ def make_fs(self):
3030

3131
class TestMountFSBehaviours(unittest.TestCase):
3232

33+
def test_bad_mount(self):
34+
mount_fs = MountFS()
35+
with self.assertRaises(TypeError):
36+
mount_fs.mount('foo', 5)
37+
with self.assertRaises(TypeError):
38+
mount_fs.mount('foo', b'bar')
39+
3340
def test_listdir(self):
3441
mount_fs = MountFS()
3542
self.assertEqual(mount_fs.listdir('/'), [])
3643
m1 = MemoryFS()
37-
m2 = TempFS()
3844
m3 = MemoryFS()
3945
m4 = TempFS()
4046
mount_fs.mount('/m1', m1)
41-
mount_fs.mount('/m2', m2)
47+
mount_fs.mount('/m2', 'temp://')
4248
mount_fs.mount('/m3', m3)
4349
with self.assertRaises(MountError):
4450
mount_fs.mount('/m3/foo', m4)

tests/test_multifs.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
import unittest
44

5+
from six import text_type
6+
57
from fs.multifs import MultiFS
68
from fs.memoryfs import MemoryFS
79
from fs import errors
@@ -64,6 +66,18 @@ def test_no_auto_close(self):
6466
self.assertFalse(m1.isclosed())
6567
self.assertFalse(m2.isclosed())
6668

69+
def test_opener(self):
70+
"""Test use of FS URLs."""
71+
multi_fs = MultiFS()
72+
with self.assertRaises(TypeError):
73+
multi_fs.add_fs(u'foo', 5)
74+
multi_fs.add_fs(u'f1', u'mem://')
75+
multi_fs.add_fs(u'f2', u'temp://')
76+
self.assertIsInstance(
77+
multi_fs.get_fs(u'f1'),
78+
MemoryFS
79+
)
80+
6781
def test_priority(self):
6882
"""Test priority order is working"""
6983
m1 = MemoryFS()

tests/test_opener.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -202,3 +202,24 @@ def test_open_fs(self):
202202
mem_fs = opener.open_fs("mem://")
203203
mem_fs_2 = opener.open_fs(mem_fs)
204204
self.assertEqual(mem_fs, mem_fs_2)
205+
206+
def test_open_userdata(self):
207+
with self.assertRaises(errors.OpenerError):
208+
opener.open_fs('userdata://foo:bar:baz:egg')
209+
210+
app_fs = opener.open_fs(
211+
'userdata://fstest:willmcgugan:1.0',
212+
create=True
213+
)
214+
self.assertEqual(app_fs.app_dirs.appname, 'fstest')
215+
self.assertEqual(app_fs.app_dirs.appauthor, 'willmcgugan')
216+
self.assertEqual(app_fs.app_dirs.version, '1.0')
217+
218+
def test_open_userdata_no_version(self):
219+
app_fs = opener.open_fs(
220+
'userdata://fstest:willmcgugan',
221+
create=True
222+
)
223+
self.assertEqual(app_fs.app_dirs.appname, 'fstest')
224+
self.assertEqual(app_fs.app_dirs.appauthor, 'willmcgugan')
225+
self.assertEqual(app_fs.app_dirs.version, None)

0 commit comments

Comments
 (0)