diff options
author | Aldo Cortesi <aldo@nullcube.com> | 2016-10-29 10:55:57 +1300 |
---|---|---|
committer | Aldo Cortesi <aldo@nullcube.com> | 2016-10-29 10:55:57 +1300 |
commit | 90e7142b5c8dd3ec9896e5308ea2e81a2d77d31d (patch) | |
tree | 3019934871c3ec64d131a2747e309b8c67aff07b | |
parent | 12a70d03ad721f6a137d118b65c11851ef7b96d7 (diff) | |
download | mitmproxy-90e7142b5c8dd3ec9896e5308ea2e81a2d77d31d.tar.gz mitmproxy-90e7142b5c8dd3ec9896e5308ea2e81a2d77d31d.tar.bz2 mitmproxy-90e7142b5c8dd3ec9896e5308ea2e81a2d77d31d.zip |
addons.View: better order reversal
Deal with some subtleties in order reversal, add a toggle method that emits
refresh.
-rw-r--r-- | mitmproxy/addons/view.py | 50 | ||||
-rw-r--r-- | test/mitmproxy/addons/test_view.py | 21 |
2 files changed, 55 insertions, 16 deletions
diff --git a/mitmproxy/addons/view.py b/mitmproxy/addons/view.py index 99481376..b5682b7a 100644 --- a/mitmproxy/addons/view.py +++ b/mitmproxy/addons/view.py @@ -34,7 +34,7 @@ class View(collections.Sequence): self._store = {} self.filter = matchall self.order_key = key_request_start - self.order_reverse = False + self.order_reversed = False self._view = sortedcontainers.SortedListWithKey(key = self.order_key) # These signals broadcast events that affect the view. That is, an @@ -46,13 +46,42 @@ class View(collections.Sequence): # Signals that the view should be refreshed completely self.sig_refresh = blinker.Signal() + def _rev(self, idx: int) -> int: + """ + Reverses an index, if needed + """ + if self.order_reversed: + if idx < 0: + idx = -idx - 1 + else: + idx = len(self._view) - idx - 1 + if idx < 0: + raise IndexError + return idx + def __len__(self): return len(self._view) def __getitem__(self, offset) -> flow.Flow: - if self.order_reverse: - offset = -offset - 1 - return self._view[offset] + return self._view[self._rev(offset)] + + # Reflect some methods to the efficient underlying implementation + + def bisect(self, f: flow.Flow) -> int: + v = self._view.bisect(f) + # Bisect returns an item to the RIGHT of the existing entries. + if v == 0: + return v + return self._rev(v - 1) + 1 + + def index(self, f: flow.Flow) -> int: + return self._rev(self._view.index(f)) + + # API + + def toggle_reversed(self): + self.order_reversed = not self.order_reversed + self.sig_refresh.send(self) def set_order(self, order_key: typing.Callable): """ @@ -122,14 +151,8 @@ class View(collections.Sequence): # The value was not in the view pass - # Reflect some methods to the efficient underlying implementation - def bisect(self, f: flow.Flow) -> int: - return self._view.bisect(f) - - def index(self, f: flow.Flow) -> int: - return self._view.index(f) - # Event handlers + def request(self, f): self.add(f) @@ -186,9 +209,8 @@ class Focus: def _sig_refresh(self, view): if len(view) == 0: self.focusflow = None - else: - if self.focusflow not in view: - self.focusflow = view[0] + elif self.focusflow not in view: + self.focusflow = view[0] def _sig_add(self, view, flow): # We only have to act if we don't have a focus element diff --git a/test/mitmproxy/addons/test_view.py b/test/mitmproxy/addons/test_view.py index 527464ad..1ab7e8f4 100644 --- a/test/mitmproxy/addons/test_view.py +++ b/test/mitmproxy/addons/test_view.py @@ -62,16 +62,33 @@ def test_order(): v.set_order(view.key_request_method) assert [i.request.method for i in v] == ["GET", "GET", "PUT", "PUT"] - v.order_reverse = True + v.toggle_reversed() assert [i.request.method for i in v] == ["PUT", "PUT", "GET", "GET"] v.set_order(view.key_request_start) assert [i.request.timestamp_start for i in v] == [4, 3, 2, 1] - v.order_reverse = False + v.toggle_reversed() assert [i.request.timestamp_start for i in v] == [1, 2, 3, 4] +def test_reversed(): + v = view.View() + v.request(tft(start=1)) + v.request(tft(start=2)) + v.request(tft(start=3)) + v.toggle_reversed() + + assert v[0].request.timestamp_start == 3 + assert v[-1].request.timestamp_start == 1 + assert v[2].request.timestamp_start == 1 + tutils.raises(IndexError, v.__getitem__, 5) + tutils.raises(IndexError, v.__getitem__, -5) + + assert v.bisect(v[0]) == 1 + assert v.bisect(v[2]) == 3 + + def test_update(): v = view.View() flt = flowfilter.parse("~m get") |