Patchwork [2,of,2] graphlog: change state dict to attr struct

login
register
mail settings
Submitter Yuya Nishihara
Date Nov. 21, 2019, 2:13 p.m.
Message ID <07da30f0f8b7dac283a2.1574345630@mimosa>
Download mbox | patch
Permalink /patch/43390/
State Accepted
Headers show

Comments

Yuya Nishihara - Nov. 21, 2019, 2:13 p.m.
# HG changeset patch
# User Yuya Nishihara <yuya@tcha.org>
# Date 1574343781 -32400
#      Thu Nov 21 22:43:01 2019 +0900
# Node ID 07da30f0f8b7dac283a273ef380b05b32f2658f0
# Parent  c19643244c5c9952ff624663e5232c5071d568da
graphlog: change state dict to attr struct

This should help static analysis.

Patch

diff --git a/mercurial/graphmod.py b/mercurial/graphmod.py
--- a/mercurial/graphmod.py
+++ b/mercurial/graphmod.py
@@ -20,6 +20,7 @@  Data depends on type.
 from __future__ import absolute_import
 
 from .node import nullrev
+from .thirdparty import attr
 from . import (
     dagop,
     pycompat,
@@ -192,7 +193,7 @@  def colored(dag, repo):
 
 def asciiedges(type, char, state, rev, parents):
     """adds edge info to changelog DAG walk suitable for ascii()"""
-    seen = state[b'seen']
+    seen = state.seen
     if rev not in seen:
         seen.append(rev)
     nodeidx = seen.index(rev)
@@ -207,7 +208,7 @@  def asciiedges(type, char, state, rev, p
             knownparents.append(parent)
         else:
             newparents.append(parent)
-            state[b'edges'][parent] = state[b'styles'].get(ptype, b'|')
+            state.edges[parent] = state.styles.get(ptype, b'|')
 
     ncols = len(seen)
     width = 1 + ncols * 2
@@ -240,7 +241,7 @@  def asciiedges(type, char, state, rev, p
     if nmorecols > 0:
         width += 2
     # remove current node from edge characters, no longer needed
-    state[b'edges'].pop(rev, None)
+    state.edges.pop(rev, None)
     yield (type, char, width, (nodeidx, edges, ncols, nmorecols))
 
 
@@ -322,7 +323,7 @@  def _drawendinglines(lines, extra, edgem
     while edgechars and edgechars[-1] is None:
         edgechars.pop()
     shift_size = max((edgechars.count(None) * 2) - 1, 0)
-    minlines = 3 if not state[b'graphshorten'] else 2
+    minlines = 3 if not state.graphshorten else 2
     while len(lines) < minlines + shift_size:
         lines.append(extra[:])
 
@@ -344,7 +345,7 @@  def _drawendinglines(lines, extra, edgem
                 positions[i] = max(pos, targets[i])
                 line[pos] = b'/' if pos > targets[i] else extra[toshift[i]]
 
-    map = {1: b'|', 2: b'~'} if not state[b'graphshorten'] else {1: b'~'}
+    map = {1: b'|', 2: b'~'} if not state.graphshorten else {1: b'~'}
     for i, line in enumerate(lines):
         if None not in line:
             continue
@@ -357,16 +358,16 @@  def _drawendinglines(lines, extra, edgem
         seen.remove(parent)
 
 
-def asciistate():
-    """returns the initial value for the "state" argument to ascii()"""
-    return {
-        b'seen': [],
-        b'edges': {},
-        b'lastcoldiff': 0,
-        b'lastindex': 0,
-        b'styles': EDGES.copy(),
-        b'graphshorten': False,
-    }
+@attr.s
+class asciistate(object):
+    """State of ascii() graph rendering"""
+
+    seen = attr.ib(init=False, default=attr.Factory(list))
+    edges = attr.ib(init=False, default=attr.Factory(dict))
+    lastcoldiff = attr.ib(init=False, default=0)
+    lastindex = attr.ib(init=False, default=0)
+    styles = attr.ib(init=False, default=attr.Factory(EDGES.copy))
+    graphshorten = attr.ib(init=False, default=False)
 
 
 def outputgraph(ui, graph):
@@ -409,7 +410,7 @@  def ascii(ui, state, type, char, text, c
     idx, edges, ncols, coldiff = coldata
     assert -2 < coldiff < 2
 
-    edgemap, seen = state[b'edges'], state[b'seen']
+    edgemap, seen = state.edges, state.seen
     # Be tolerant of history issues; make sure we have at least ncols + coldiff
     # elements to work with. See test-glog.t for broken history test cases.
     echars = [c for p in seen for c in (edgemap.get(p, b'|'), b' ')]
@@ -452,10 +453,10 @@  def ascii(ui, state, type, char, text, c
         _getnodelineedgestail(
             echars,
             idx,
-            state[b'lastindex'],
+            state.lastindex,
             ncols,
             coldiff,
-            state[b'lastcoldiff'],
+            state.lastcoldiff,
             fix_nodeline_tail,
         )
     )
@@ -485,7 +486,7 @@  def ascii(ui, state, type, char, text, c
 
     # If 'graphshorten' config, only draw shift_interline
     # when there is any non vertical flow in graph.
-    if state[b'graphshorten']:
+    if state.graphshorten:
         if any(c in br'\/' for c in shift_interline if c):
             lines.append(shift_interline)
     # Else, no 'graphshorten' config so draw shift_interline.
@@ -512,5 +513,5 @@  def ascii(ui, state, type, char, text, c
     outputgraph(ui, zip(lines, text))
 
     # ... and start over
-    state[b'lastcoldiff'] = coldiff
-    state[b'lastindex'] = idx
+    state.lastcoldiff = coldiff
+    state.lastindex = idx
diff --git a/mercurial/logcmdutil.py b/mercurial/logcmdutil.py
--- a/mercurial/logcmdutil.py
+++ b/mercurial/logcmdutil.py
@@ -1012,7 +1012,7 @@  def displaygraph(ui, repo, dag, displaye
     props = props or {}
     formatnode = _graphnodeformatter(ui, displayer)
     state = graphmod.asciistate()
-    styles = state[b'styles']
+    styles = state.styles
 
     # only set graph styling if HGPLAIN is not set.
     if ui.plain(b'graph'):
@@ -1033,7 +1033,7 @@  def displaygraph(ui, repo, dag, displaye
                 styles[key] = None
 
         # experimental config: experimental.graphshorten
-        state[b'graphshorten'] = ui.configbool(b'experimental', b'graphshorten')
+        state.graphshorten = ui.configbool(b'experimental', b'graphshorten')
 
     for rev, type, ctx, parents in dag:
         char = formatnode(repo, ctx)