aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAldo Cortesi <aldo@corte.si>2017-03-13 11:06:18 +1300
committerAldo Cortesi <aldo@corte.si>2017-03-14 08:34:25 +1300
commit2832e790fd27d45f8bfbed1b4ce7f1e15910018d (patch)
tree554d05c7169f84b3e64c3d2b3257f0bb2b5674d8
parentc24f7d8e12ee2002678adb695be513a7e593e198 (diff)
downloadmitmproxy-2832e790fd27d45f8bfbed1b4ce7f1e15910018d.tar.gz
mitmproxy-2832e790fd27d45f8bfbed1b4ce7f1e15910018d.tar.bz2
mitmproxy-2832e790fd27d45f8bfbed1b4ce7f1e15910018d.zip
Move serialization methods out of Options
Attributes on options share a namespace with options themselves. It's getting too crowded on our Options object, so let's shift some obvious stuff into the module.
-rw-r--r--mitmproxy/optmanager.py159
-rw-r--r--mitmproxy/tools/console/options.py3
-rw-r--r--mitmproxy/tools/main.py2
-rw-r--r--test/mitmproxy/test_optmanager.py30
4 files changed, 100 insertions, 94 deletions
diff --git a/mitmproxy/optmanager.py b/mitmproxy/optmanager.py
index fc540b74..225a2f73 100644
--- a/mitmproxy/optmanager.py
+++ b/mitmproxy/optmanager.py
@@ -222,83 +222,6 @@ class OptManager:
"""
return self._options[option].has_changed()
- def save(self, path, defaults=False):
- """
- Save to path. If the destination file exists, modify it in-place.
- """
- if os.path.exists(path) and os.path.isfile(path):
- with open(path, "r") as f:
- data = f.read()
- else:
- data = ""
- data = self.serialize(data, defaults)
- with open(path, "w") as f:
- f.write(data)
-
- def serialize(self, text, defaults=False):
- """
- Performs a round-trip serialization. If text is not None, it is
- treated as a previous serialization that should be modified
- in-place.
-
- - If "defaults" is False, only options with non-default values are
- serialized. Default values in text are preserved.
- - Unknown options in text are removed.
- - Raises OptionsError if text is invalid.
- """
- data = self._load(text)
- for k in self.keys():
- if defaults or self.has_changed(k):
- data[k] = getattr(self, k)
- for k in list(data.keys()):
- if k not in self._options:
- del data[k]
- return ruamel.yaml.round_trip_dump(data)
-
- def _load(self, text):
- if not text:
- return {}
- try:
- data = ruamel.yaml.load(text, ruamel.yaml.RoundTripLoader)
- except ruamel.yaml.error.YAMLError as v:
- snip = v.problem_mark.get_snippet()
- raise exceptions.OptionsError(
- "Config error at line %s:\n%s\n%s" %
- (v.problem_mark.line + 1, snip, v.problem)
- )
- if isinstance(data, str):
- raise exceptions.OptionsError("Config error - no keys found.")
- return data
-
- def load(self, text):
- """
- Load configuration from text, over-writing options already set in
- this object. May raise OptionsError if the config file is invalid.
- """
- data = self._load(text)
- try:
- self.update(**data)
- except KeyError as v:
- raise exceptions.OptionsError(v)
-
- def load_paths(self, *paths):
- """
- Load paths in order. Each path takes precedence over the previous
- path. Paths that don't exist are ignored, errors raise an
- OptionsError.
- """
- for p in paths:
- p = os.path.expanduser(p)
- if os.path.exists(p) and os.path.isfile(p):
- with open(p, "r") as f:
- txt = f.read()
- try:
- self.load(txt)
- except exceptions.OptionsError as e:
- raise exceptions.OptionsError(
- "Error reading %s: %s" % (p, e)
- )
-
def merge(self, opts):
"""
Merge a dict of options into this object. Options that have None
@@ -468,3 +391,85 @@ def dump_defaults(opts):
)
s.yaml_set_comment_before_after_key(k, before = "\n" + txt)
return ruamel.yaml.round_trip_dump(s)
+
+
+def parse(text):
+ if not text:
+ return {}
+ try:
+ data = ruamel.yaml.load(text, ruamel.yaml.RoundTripLoader)
+ except ruamel.yaml.error.YAMLError as v:
+ snip = v.problem_mark.get_snippet()
+ raise exceptions.OptionsError(
+ "Config error at line %s:\n%s\n%s" %
+ (v.problem_mark.line + 1, snip, v.problem)
+ )
+ if isinstance(data, str):
+ raise exceptions.OptionsError("Config error - no keys found.")
+ return data
+
+
+def load(opts, text):
+ """
+ Load configuration from text, over-writing options already set in
+ this object. May raise OptionsError if the config file is invalid.
+ """
+ data = parse(text)
+ try:
+ opts.update(**data)
+ except KeyError as v:
+ raise exceptions.OptionsError(v)
+
+
+def load_paths(opts, *paths):
+ """
+ Load paths in order. Each path takes precedence over the previous
+ path. Paths that don't exist are ignored, errors raise an
+ OptionsError.
+ """
+ for p in paths:
+ p = os.path.expanduser(p)
+ if os.path.exists(p) and os.path.isfile(p):
+ with open(p, "r") as f:
+ txt = f.read()
+ try:
+ load(opts, txt)
+ except exceptions.OptionsError as e:
+ raise exceptions.OptionsError(
+ "Error reading %s: %s" % (p, e)
+ )
+
+
+def serialize(opts, text, defaults=False):
+ """
+ Performs a round-trip serialization. If text is not None, it is
+ treated as a previous serialization that should be modified
+ in-place.
+
+ - If "defaults" is False, only options with non-default values are
+ serialized. Default values in text are preserved.
+ - Unknown options in text are removed.
+ - Raises OptionsError if text is invalid.
+ """
+ data = parse(text)
+ for k in opts.keys():
+ if defaults or opts.has_changed(k):
+ data[k] = getattr(opts, k)
+ for k in list(data.keys()):
+ if k not in opts._options:
+ del data[k]
+ return ruamel.yaml.round_trip_dump(data)
+
+
+def save(opts, path, defaults=False):
+ """
+ Save to path. If the destination file exists, modify it in-place.
+ """
+ if os.path.exists(path) and os.path.isfile(path):
+ with open(path, "r") as f:
+ data = f.read()
+ else:
+ data = ""
+ data = serialize(opts, data, defaults)
+ with open(path, "w") as f:
+ f.write(data)
diff --git a/mitmproxy/tools/console/options.py b/mitmproxy/tools/console/options.py
index 33e3ec38..79bb53c2 100644
--- a/mitmproxy/tools/console/options.py
+++ b/mitmproxy/tools/console/options.py
@@ -1,6 +1,7 @@
import urwid
from mitmproxy import contentviews
+from mitmproxy import optmanager
from mitmproxy.tools.console import common
from mitmproxy.tools.console import grideditor
from mitmproxy.tools.console import select
@@ -173,7 +174,7 @@ class Options(urwid.WidgetWrap):
return super().keypress(size, key)
def do_save(self, path):
- self.master.options.save(path)
+ optmanager.save(self.master.options, path)
return "Saved"
def save(self):
diff --git a/mitmproxy/tools/main.py b/mitmproxy/tools/main.py
index cc2310c2..8210580c 100644
--- a/mitmproxy/tools/main.py
+++ b/mitmproxy/tools/main.py
@@ -69,7 +69,7 @@ def run(MasterKlass, args): # pragma: no cover
args = parser.parse_args(args)
master = None
try:
- opts.load_paths(args.conf)
+ optmanager.load_paths(opts, args.conf)
server = process_options(parser, opts, args)
master = MasterKlass(opts, server)
master.addons.configure_all(opts, opts.keys())
diff --git a/test/mitmproxy/test_optmanager.py b/test/mitmproxy/test_optmanager.py
index 8ca35984..012c463c 100644
--- a/test/mitmproxy/test_optmanager.py
+++ b/test/mitmproxy/test_optmanager.py
@@ -199,61 +199,61 @@ def test_simple():
def test_serialize():
o = TD2()
o.three = "set"
- assert "dfour" in o.serialize(None, defaults=True)
+ assert "dfour" in optmanager.serialize(o, None, defaults=True)
- data = o.serialize(None)
+ data = optmanager.serialize(o, None)
assert "dfour" not in data
o2 = TD2()
- o2.load(data)
+ optmanager.load(o2, data)
assert o2 == o
t = """
unknown: foo
"""
- data = o.serialize(t)
+ data = optmanager.serialize(o, t)
o2 = TD2()
- o2.load(data)
+ optmanager.load(o2, data)
assert o2 == o
t = "invalid: foo\ninvalid"
with pytest.raises(Exception, match="Config error"):
- o2.load(t)
+ optmanager.load(o2, t)
t = "invalid"
with pytest.raises(Exception, match="Config error"):
- o2.load(t)
+ optmanager.load(o2, t)
t = ""
- o2.load(t)
+ optmanager.load(o2, t)
with pytest.raises(exceptions.OptionsError, matches='No such option: foobar'):
- o2.load("foobar: '123'")
+ optmanager.load(o2, "foobar: '123'")
def test_serialize_defaults():
o = options.Options()
- assert o.serialize(None, defaults=True)
+ assert optmanager.serialize(o, None, defaults=True)
def test_saving(tmpdir):
o = TD2()
o.three = "set"
dst = str(tmpdir.join("conf"))
- o.save(dst, defaults=True)
+ optmanager.save(o, dst, defaults=True)
o2 = TD2()
- o2.load_paths(dst)
+ optmanager.load_paths(o2, dst)
o2.three = "foo"
- o2.save(dst, defaults=True)
+ optmanager.save(o2, dst, defaults=True)
- o.load_paths(dst)
+ optmanager.load_paths(o, dst)
assert o.three == "foo"
with open(dst, 'a') as f:
f.write("foobar: '123'")
with pytest.raises(exceptions.OptionsError, matches=''):
- o.load_paths(dst)
+ optmanager.load_paths(o, dst)
def test_merge():