Skip to content

Commit d1632b6

Browse files
committed
Patch 1/3 - Replace Optparse with ArgumentParser
This is the first of a 3-patch series of commits to address #24 This commit introduces tests for the current `Optparse` based implementation to ensure that the next commit doesn't break current usage compatibility. The next commit would introduce the `ArgumentParser` based implementation. The final commit will attempt to do some minor clean up to make the code a bit more idomatic / pythonic.
1 parent c4169e5 commit d1632b6

3 files changed

Lines changed: 164 additions & 6 deletions

File tree

fuse.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727
from fuseparts._fuse import FuseError, FuseAPIVersion
2828
from fuseparts.subbedopts import SubOptsHive, SubbedOptFormatter
2929
from fuseparts.subbedopts import SubbedOptIndentedFormatter, SubbedOptParse
30-
from fuseparts.subbedopts import SUPPRESS_HELP, OptParseError
30+
from fuseparts.subbedopts import SUPPRESS_HELP, FuseError
3131
from fuseparts.setcompatwrap import set
3232

3333

@@ -282,7 +282,7 @@ def __init__(self, *args, **kw):
282282

283283
if dsd == 'whine':
284284
def dsdcb(option, opt_str, value, parser):
285-
raise RuntimeError("""
285+
raise FuseError("""
286286
287287
! If you want the "-s" option to work, pass
288288
!
@@ -305,14 +305,15 @@ def dsdcb(option, opt_str, value, parser):
305305
self.add_option('-s', action='callback', callback=dsdcb,
306306
help=SUPPRESS_HELP)
307307

308+
add_argument = SubbedOptParse.add_option
308309

309310
def exit(self, status=0, msg=None):
310311
if msg:
311312
sys.stderr.write(msg)
312313

313314
def error(self, msg):
314315
SubbedOptParse.error(self, msg)
315-
raise OptParseError(msg)
316+
raise FuseError(msg)
316317

317318
def print_help(self, file=sys.stderr):
318319
SubbedOptParse.print_help(self, file)
@@ -331,7 +332,7 @@ def parse_args(self, args=None, values=None):
331332
def add_option(self, *opts, **attrs):
332333
if 'mountopt' in attrs:
333334
if opts or 'subopt' in attrs:
334-
raise OptParseError(
335+
raise FuseError(
335336
"having options or specifying the `subopt' attribute conflicts with `mountopt' attribute")
336337
opts = ('-o',)
337338
attrs['subopt'] = attrs.pop('mountopt')

fuseparts/subbedopts.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,10 @@
1616
##########
1717

1818

19+
class FuseError(OptParseError):
20+
"""Exception raised for FUSE-specific Optparing errors"""
21+
pass
22+
1923

2024
class SubOptsHive(object):
2125
"""
@@ -47,7 +51,7 @@ def canonify(self):
4751
with True value to optlist, stringify other values.
4852
"""
4953

50-
for k, v in self.optdict.items():
54+
for k, v in list(self.optdict.items()):
5155
if v == False:
5256
self.optdict.pop(k)
5357
elif v == True:
@@ -242,7 +246,7 @@ def __init__(self, *args, **kw):
242246
def add_option(self, *args, **kwargs):
243247
if 'action' in kwargs and kwargs['action'] == 'store_hive':
244248
if 'subopt' in kwargs:
245-
raise OptParseError(
249+
raise FuseError(
246250
"""option can't have a `subopt' attr and `action="store_hive"' at the same time""")
247251
if not 'type' in kwargs:
248252
kwargs['type'] = 'string'

tests/test_fuse_args.py

Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
import pytest
2+
import optparse
3+
import os
4+
import sys
5+
from pathlib import Path
6+
import argparse
7+
8+
from fuse import FuseArgs, FuseOptParse, Fuse, FuseError, FUSE_PYTHON_API_VERSION
9+
10+
# Set up fuse_python_api for testing
11+
import fuse
12+
fuse.fuse_python_api = FUSE_PYTHON_API_VERSION
13+
14+
15+
def test_init():
16+
"""FuseArgs initialization"""
17+
args = FuseArgs()
18+
assert args.mountpoint is None
19+
assert args.optlist == set()
20+
assert args.optdict == {}
21+
assert args.getmod('showhelp') is False
22+
assert args.getmod('showversion') is False
23+
assert args.getmod('foreground') is False
24+
25+
@pytest.mark.parametrize("mod", ['showhelp', 'showversion', 'foreground'])
26+
def test_get_set_mod(mod):
27+
"""FuseArgs modifier handling"""
28+
args = FuseArgs()
29+
args.setmod(mod)
30+
assert args.getmod(mod) is True
31+
32+
args.unsetmod(mod)
33+
assert args.getmod(mod) is False
34+
35+
def test_fuse_args_mount_expected():
36+
"""FuseArgs mount_expected method"""
37+
args = FuseArgs()
38+
assert args.mount_expected() is True
39+
40+
args.setmod('showhelp')
41+
assert args.mount_expected() is False
42+
args.unsetmod('showhelp')
43+
44+
args.setmod('showversion')
45+
assert args.mount_expected() is False
46+
args.unsetmod('showversion')
47+
48+
def test_fuse_args_add():
49+
"""FuseArgs add method"""
50+
args = FuseArgs()
51+
52+
# Test adding simple option
53+
args.add('debug')
54+
assert 'debug' in args.optlist
55+
56+
# Test adding option with value
57+
args.add('uid=1000')
58+
assert args.optdict['uid'] == '1000'
59+
60+
# Test adding option with explicit value
61+
args.add('gid', '1000')
62+
assert args.optdict['gid'] == '1000'
63+
64+
# Test adding False value
65+
args.add('allow_other', False)
66+
assert 'allow_other' not in args.optlist
67+
assert 'allow_other' not in args.optdict
68+
69+
def test_fuse_args_canonify():
70+
"""FuseArgs canonify method"""
71+
args = FuseArgs()
72+
73+
# Test converting False values
74+
args.optdict['allow_other'] = False
75+
args.canonify()
76+
assert 'allow_other' not in args.optdict
77+
78+
# Test converting True values
79+
args.optdict['debug'] = True
80+
args.canonify()
81+
assert True in args.optlist
82+
assert True not in args.optdict
83+
84+
def test_fuse_args_assemble():
85+
"""FuseArgs assemble method"""
86+
args = FuseArgs()
87+
args.mountpoint = '/mnt'
88+
args.setmod('foreground')
89+
args.add('debug')
90+
args.add('uid=1000')
91+
92+
cmdline = args.assemble()
93+
# The first argument should be a program name
94+
assert isinstance(cmdline[0], str)
95+
assert cmdline[1] == '/mnt'
96+
assert '-f' in cmdline
97+
assert cmdline[-1] in ('-odebug,uid=1000', '-ouid=1000,debug')
98+
99+
def test_fuse_cliparse_basic():
100+
"""Basic FuseOptParse functionality"""
101+
parser = FuseOptParse()
102+
parser.add_argument('--mountpoint', nargs='?', help='Mount point')
103+
args = parser.parse_args(['/mnt', '-f', '-o', 'debug,uid=1000'])
104+
105+
assert parser.fuse_args.mountpoint == '/mnt'
106+
assert parser.fuse_args.getmod('foreground')
107+
assert 'debug' in parser.fuse_args.optlist
108+
assert parser.fuse_args.optdict['uid'] == '1000'
109+
110+
def test_fuse_cliparse_standard_mods():
111+
"""FuseOptParse standard modifiers"""
112+
parser = FuseOptParse(standard_mods=True)
113+
parser.add_argument('--mountpoint', nargs='?', help='Mount point')
114+
args = parser.parse_args(['/mnt', '-f', '-d'])
115+
116+
assert parser.fuse_args.getmod('foreground')
117+
assert 'debug' in parser.fuse_args.optlist
118+
119+
def test_fuse_cliparse_dash_s():
120+
"""FuseOptParse -s option handling"""
121+
# Test whine mode (default)
122+
parser = FuseOptParse()
123+
parser.add_argument('--mountpoint', nargs='?', help='Mount point')
124+
with pytest.raises(FuseError):
125+
parser.parse_args(['/mnt', '-s'])
126+
127+
# Test setsingle mode
128+
mock_fuse = Fuse()
129+
mock_fuse.multithreaded = True
130+
131+
parser = FuseOptParse(dash_s_do='setsingle', fuse=mock_fuse)
132+
parser.add_argument('--mountpoint', nargs='?', help='Mount point')
133+
args = parser.parse_args(['/mnt', '-s'])
134+
assert not mock_fuse.multithreaded
135+
136+
def test_fuse_cliparse_error_handling():
137+
"""FuseOptParse error handling"""
138+
parser = FuseOptParse()
139+
parser.add_argument('--mountpoint', nargs='?', help='Mount point')
140+
141+
# Test invalid option
142+
with pytest.raises(FuseError):
143+
parser.parse_args(['/mnt', '--invalid-option'])
144+
145+
def test_fuse_cliparse_mount_options():
146+
"""FuseOptParse mount options handling"""
147+
parser = FuseOptParse()
148+
parser.add_argument('--mountpoint', nargs='?', help='Mount point')
149+
args = parser.parse_args(['/mnt', '-o', 'debug,uid=1000,gid=1000'])
150+
151+
assert 'debug' in parser.fuse_args.optlist
152+
assert parser.fuse_args.optdict['uid'] == '1000'
153+
assert parser.fuse_args.optdict['gid'] == '1000'

0 commit comments

Comments
 (0)