mirror of
https://github.com/Grasscutters/mitmproxy.git
synced 2025-01-30 14:58:38 +00:00
Enable custom options in config files
We also now ignore unknown options in config files by default, and print a warning if verbosity is incremented.
This commit is contained in:
parent
2832e790fd
commit
b745428b5c
@ -7,4 +7,5 @@ def start(options):
|
|||||||
|
|
||||||
|
|
||||||
def configure(options, updated):
|
def configure(options, updated):
|
||||||
ctx.log.info("custom option value: %s" % options.custom)
|
if "custom" in updated:
|
||||||
|
ctx.log.info("custom option value: %s" % options.custom)
|
||||||
|
@ -81,8 +81,6 @@ class _Option:
|
|||||||
class OptManager:
|
class OptManager:
|
||||||
"""
|
"""
|
||||||
OptManager is the base class from which Options objects are derived.
|
OptManager is the base class from which Options objects are derived.
|
||||||
Note that the __init__ method of all child classes must force all
|
|
||||||
arguments to be positional only, by including a "*" argument.
|
|
||||||
|
|
||||||
.changed is a blinker Signal that triggers whenever options are
|
.changed is a blinker Signal that triggers whenever options are
|
||||||
updated. If any handler in the chain raises an exceptions.OptionsError
|
updated. If any handler in the chain raises an exceptions.OptionsError
|
||||||
@ -176,15 +174,29 @@ class OptManager:
|
|||||||
o.reset()
|
o.reset()
|
||||||
self.changed.send(self._options.keys())
|
self.changed.send(self._options.keys())
|
||||||
|
|
||||||
|
def update_known(self, **kwargs):
|
||||||
|
"""
|
||||||
|
Update and set all known options from kwargs. Returns a dictionary
|
||||||
|
of unknown options.
|
||||||
|
"""
|
||||||
|
known, unknown = {}, {}
|
||||||
|
for k, v in kwargs.items():
|
||||||
|
if k in self._options:
|
||||||
|
known[k] = v
|
||||||
|
else:
|
||||||
|
unknown[k] = v
|
||||||
|
updated = set(known.keys())
|
||||||
|
if updated:
|
||||||
|
with self.rollback(updated):
|
||||||
|
for k, v in known.items():
|
||||||
|
self._options[k].set(v)
|
||||||
|
self.changed.send(self, updated=updated)
|
||||||
|
return unknown
|
||||||
|
|
||||||
def update(self, **kwargs):
|
def update(self, **kwargs):
|
||||||
updated = set(kwargs.keys())
|
u = self.update_known(**kwargs)
|
||||||
with self.rollback(updated):
|
if u:
|
||||||
for k, v in kwargs.items():
|
raise KeyError("Unknown options: %s" % ", ".join(u.keys()))
|
||||||
if k not in self._options:
|
|
||||||
raise KeyError("No such option: %s" % k)
|
|
||||||
self._options[k].set(v)
|
|
||||||
self.changed.send(self, updated=updated)
|
|
||||||
return self
|
|
||||||
|
|
||||||
def setter(self, attr):
|
def setter(self, attr):
|
||||||
"""
|
"""
|
||||||
@ -413,12 +425,11 @@ def load(opts, text):
|
|||||||
"""
|
"""
|
||||||
Load configuration from text, over-writing options already set in
|
Load configuration from text, over-writing options already set in
|
||||||
this object. May raise OptionsError if the config file is invalid.
|
this object. May raise OptionsError if the config file is invalid.
|
||||||
|
|
||||||
|
Returns a dictionary of all unknown options.
|
||||||
"""
|
"""
|
||||||
data = parse(text)
|
data = parse(text)
|
||||||
try:
|
return opts.update_known(**data)
|
||||||
opts.update(**data)
|
|
||||||
except KeyError as v:
|
|
||||||
raise exceptions.OptionsError(v)
|
|
||||||
|
|
||||||
|
|
||||||
def load_paths(opts, *paths):
|
def load_paths(opts, *paths):
|
||||||
@ -426,18 +437,22 @@ def load_paths(opts, *paths):
|
|||||||
Load paths in order. Each path takes precedence over the previous
|
Load paths in order. Each path takes precedence over the previous
|
||||||
path. Paths that don't exist are ignored, errors raise an
|
path. Paths that don't exist are ignored, errors raise an
|
||||||
OptionsError.
|
OptionsError.
|
||||||
|
|
||||||
|
Returns a dictionary of unknown options.
|
||||||
"""
|
"""
|
||||||
|
ret = {}
|
||||||
for p in paths:
|
for p in paths:
|
||||||
p = os.path.expanduser(p)
|
p = os.path.expanduser(p)
|
||||||
if os.path.exists(p) and os.path.isfile(p):
|
if os.path.exists(p) and os.path.isfile(p):
|
||||||
with open(p, "r") as f:
|
with open(p, "r") as f:
|
||||||
txt = f.read()
|
txt = f.read()
|
||||||
try:
|
try:
|
||||||
load(opts, txt)
|
ret.update(load(opts, txt))
|
||||||
except exceptions.OptionsError as e:
|
except exceptions.OptionsError as e:
|
||||||
raise exceptions.OptionsError(
|
raise exceptions.OptionsError(
|
||||||
"Error reading %s: %s" % (p, e)
|
"Error reading %s: %s" % (p, e)
|
||||||
)
|
)
|
||||||
|
return ret
|
||||||
|
|
||||||
|
|
||||||
def serialize(opts, text, defaults=False):
|
def serialize(opts, text, defaults=False):
|
||||||
|
@ -69,10 +69,13 @@ def run(MasterKlass, args): # pragma: no cover
|
|||||||
args = parser.parse_args(args)
|
args = parser.parse_args(args)
|
||||||
master = None
|
master = None
|
||||||
try:
|
try:
|
||||||
optmanager.load_paths(opts, args.conf)
|
unknown = optmanager.load_paths(opts, args.conf)
|
||||||
server = process_options(parser, opts, args)
|
server = process_options(parser, opts, args)
|
||||||
master = MasterKlass(opts, server)
|
master = MasterKlass(opts, server)
|
||||||
master.addons.configure_all(opts, opts.keys())
|
master.addons.configure_all(opts, opts.keys())
|
||||||
|
remaining = opts.update_known(**unknown)
|
||||||
|
if remaining and opts.verbosity > 1:
|
||||||
|
print("Ignored options: %s" % remaining)
|
||||||
if args.options:
|
if args.options:
|
||||||
print(optmanager.dump_defaults(opts))
|
print(optmanager.dump_defaults(opts))
|
||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
|
@ -83,10 +83,11 @@ def test_options():
|
|||||||
|
|
||||||
with pytest.raises(TypeError):
|
with pytest.raises(TypeError):
|
||||||
TO(nonexistent = "value")
|
TO(nonexistent = "value")
|
||||||
with pytest.raises(Exception, match="No such option"):
|
with pytest.raises(Exception, match="Unknown options"):
|
||||||
o.nonexistent = "value"
|
o.nonexistent = "value"
|
||||||
with pytest.raises(Exception, match="No such option"):
|
with pytest.raises(Exception, match="Unknown options"):
|
||||||
o.update(nonexistent = "value")
|
o.update(nonexistent = "value")
|
||||||
|
assert o.update_known(nonexistent = "value") == {"nonexistent": "value"}
|
||||||
|
|
||||||
rec = []
|
rec = []
|
||||||
|
|
||||||
@ -226,9 +227,7 @@ def test_serialize():
|
|||||||
|
|
||||||
t = ""
|
t = ""
|
||||||
optmanager.load(o2, t)
|
optmanager.load(o2, t)
|
||||||
|
assert optmanager.load(o2, "foobar: '123'") == {"foobar": "123"}
|
||||||
with pytest.raises(exceptions.OptionsError, matches='No such option: foobar'):
|
|
||||||
optmanager.load(o2, "foobar: '123'")
|
|
||||||
|
|
||||||
|
|
||||||
def test_serialize_defaults():
|
def test_serialize_defaults():
|
||||||
@ -252,7 +251,11 @@ def test_saving(tmpdir):
|
|||||||
|
|
||||||
with open(dst, 'a') as f:
|
with open(dst, 'a') as f:
|
||||||
f.write("foobar: '123'")
|
f.write("foobar: '123'")
|
||||||
with pytest.raises(exceptions.OptionsError, matches=''):
|
assert optmanager.load_paths(o, dst) == {"foobar": "123"}
|
||||||
|
|
||||||
|
with open(dst, 'a') as f:
|
||||||
|
f.write("'''")
|
||||||
|
with pytest.raises(exceptions.OptionsError):
|
||||||
optmanager.load_paths(o, dst)
|
optmanager.load_paths(o, dst)
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user