From e59ba1341775eb6eb169a0884b09f18997dd5792 Mon Sep 17 00:00:00 2001 From: Aldo Cortesi Date: Sun, 27 May 2018 10:12:24 +1200 Subject: [PATCH 1/2] Use deferral mechanism for cfg file options Fixes #3162 --- mitmproxy/optmanager.py | 22 ++++++++++------------ mitmproxy/tools/main.py | 3 +-- test/mitmproxy/test_optmanager.py | 9 ++++++--- 3 files changed, 17 insertions(+), 17 deletions(-) diff --git a/mitmproxy/optmanager.py b/mitmproxy/optmanager.py index 2a4beba90..7d8ca9143 100644 --- a/mitmproxy/optmanager.py +++ b/mitmproxy/optmanager.py @@ -217,6 +217,10 @@ class OptManager: self.changed.send(self, updated=updated) return unknown + def update_defer(self, **kwargs): + unknown = self.update_known(**kwargs) + self._deferred.update(unknown) + def update(self, **kwargs): u = self.update_known(**kwargs) if u: @@ -494,26 +498,21 @@ def parse(text): return data -def load(opts, text): +def load(opts: OptManager, text: str) -> None: """ Load configuration from text, over-writing options already set in this object. May raise OptionsError if the config file is invalid. - - Returns a dictionary of all unknown options. """ data = parse(text) - return opts.update_known(**data) + opts.update_defer(**data) -def load_paths(opts, *paths): +def load_paths(opts: OptManager, *paths: str) -> None: """ Load paths in order. Each path takes precedence over the previous path. Paths that don't exist are ignored, errors raise an OptionsError. - - Returns a dictionary of unknown options. """ - ret = {} for p in paths: p = os.path.expanduser(p) if os.path.exists(p) and os.path.isfile(p): @@ -525,15 +524,14 @@ def load_paths(opts, *paths): "Error reading %s: %s" % (p, e) ) try: - ret.update(load(opts, txt)) + load(opts, txt) except exceptions.OptionsError as e: raise exceptions.OptionsError( "Error reading %s: %s" % (p, e) ) - return ret -def serialize(opts, text, defaults=False): +def serialize(opts: OptManager, text: str, defaults: bool = False) -> str: """ Performs a round-trip serialization. If text is not None, it is treated as a previous serialization that should be modified @@ -554,7 +552,7 @@ def serialize(opts, text, defaults=False): return ruamel.yaml.round_trip_dump(data) -def save(opts, path, defaults=False): +def save(opts: OptManager, path: str, defaults: bool =False) -> None: """ Save to path. If the destination file exists, modify it in-place. diff --git a/mitmproxy/tools/main.py b/mitmproxy/tools/main.py index 4166f78fd..789bef636 100644 --- a/mitmproxy/tools/main.py +++ b/mitmproxy/tools/main.py @@ -93,7 +93,7 @@ def run( sys.exit(1) try: opts.confdir = args.confdir - unknown = optmanager.load_paths( + optmanager.load_paths( opts, os.path.join(opts.confdir, OPTIONS_FILE_NAME), ) @@ -109,7 +109,6 @@ def run( server = proxy.server.DummyServer(pconf) master.server = server - opts.update_known(**unknown) if args.options: print(optmanager.dump_defaults(opts)) sys.exit(0) diff --git a/test/mitmproxy/test_optmanager.py b/test/mitmproxy/test_optmanager.py index 4356434b9..2d408b6e5 100644 --- a/test/mitmproxy/test_optmanager.py +++ b/test/mitmproxy/test_optmanager.py @@ -269,11 +269,13 @@ def test_serialize(): t = "# a comment" optmanager.load(o2, t) - assert optmanager.load(o2, "foobar: '123'") == {"foobar": "123"} + optmanager.load(o2, "foobar: '123'") + assert o2._deferred == {"foobar": "123"} t = "" optmanager.load(o2, t) - assert optmanager.load(o2, "foobar: '123'") == {"foobar": "123"} + optmanager.load(o2, "foobar: '123'") + assert o2._deferred == {"foobar": "123"} def test_serialize_defaults(): @@ -297,7 +299,8 @@ def test_saving(tmpdir): with open(dst, 'a') as f: f.write("foobar: '123'") - assert optmanager.load_paths(o, dst) == {"foobar": "123"} + optmanager.load_paths(o, dst) + assert o._deferred == {"foobar": "123"} with open(dst, 'a') as f: f.write("'''") From ec2ae19e22613eadffdb1ff17c1e7b0a8e6a4422 Mon Sep 17 00:00:00 2001 From: Aldo Cortesi Date: Sun, 27 May 2018 10:43:14 +1200 Subject: [PATCH 2/2] optmanager: tweaks and cleanups --- mitmproxy/optmanager.py | 10 +++++----- test/mitmproxy/test_optmanager.py | 20 ++++++++++---------- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/mitmproxy/optmanager.py b/mitmproxy/optmanager.py index 7d8ca9143..06e696c01 100644 --- a/mitmproxy/optmanager.py +++ b/mitmproxy/optmanager.py @@ -91,7 +91,7 @@ class OptManager: mutation doesn't change the option state inadvertently. """ def __init__(self): - self._deferred: typing.Dict[str, str] = {} + self.deferred: typing.Dict[str, str] = {} self.changed = blinker.Signal() self.errored = blinker.Signal() # Options must be the last attribute here - after that, we raise an @@ -219,7 +219,7 @@ class OptManager: def update_defer(self, **kwargs): unknown = self.update_known(**kwargs) - self._deferred.update(unknown) + self.deferred.update(unknown) def update(self, **kwargs): u = self.update_known(**kwargs) @@ -307,7 +307,7 @@ class OptManager: else: unknown[optname] = optval if defer: - self._deferred.update(unknown) + self.deferred.update(unknown) elif unknown: raise exceptions.OptionsError("Unknown options: %s" % ", ".join(unknown.keys())) self.update(**vals) @@ -318,12 +318,12 @@ class OptManager: have since been added. """ update = {} - for optname, optval in self._deferred.items(): + for optname, optval in self.deferred.items(): if optname in self._options: update[optname] = self.parse_setval(self._options[optname], optval) self.update(**update) for k in update.keys(): - del self._deferred[k] + del self.deferred[k] def parse_setval(self, o: _Option, optstr: typing.Optional[str]) -> typing.Any: """ diff --git a/test/mitmproxy/test_optmanager.py b/test/mitmproxy/test_optmanager.py index 2d408b6e5..1e4f09d47 100644 --- a/test/mitmproxy/test_optmanager.py +++ b/test/mitmproxy/test_optmanager.py @@ -270,12 +270,12 @@ def test_serialize(): t = "# a comment" optmanager.load(o2, t) optmanager.load(o2, "foobar: '123'") - assert o2._deferred == {"foobar": "123"} + assert o2.deferred == {"foobar": "123"} t = "" optmanager.load(o2, t) optmanager.load(o2, "foobar: '123'") - assert o2._deferred == {"foobar": "123"} + assert o2.deferred == {"foobar": "123"} def test_serialize_defaults(): @@ -300,7 +300,7 @@ def test_saving(tmpdir): with open(dst, 'a') as f: f.write("foobar: '123'") optmanager.load_paths(o, dst) - assert o._deferred == {"foobar": "123"} + assert o.deferred == {"foobar": "123"} with open(dst, 'a') as f: f.write("'''") @@ -429,13 +429,13 @@ def test_set(): assert opts.seqstr == [] with pytest.raises(exceptions.OptionsError): - opts.set("deferred=wobble") + opts.set("deferredoption=wobble") - opts.set("deferred=wobble", defer=True) - assert "deferred" in opts._deferred + opts.set("deferredoption=wobble", defer=True) + assert "deferredoption" in opts.deferred opts.process_deferred() - assert "deferred" in opts._deferred - opts.add_option("deferred", str, "default", "help") + assert "deferredoption" in opts.deferred + opts.add_option("deferredoption", str, "default", "help") opts.process_deferred() - assert "deferred" not in opts._deferred - assert opts.deferred == "wobble" + assert "deferredoption" not in opts.deferred + assert opts.deferredoption == "wobble"