comparison tests/test-batching.py @ 41335:b81ca9a3f4e4

py3: port test-batching.py to python3 I used byteify-strings.py on this file, then manually added the various pycompat and bprint bits as needed. Differential Revision: https://phab.mercurial-scm.org/D5678
author Augie Fackler <augie@google.com>
date Thu, 24 Jan 2019 11:35:40 -0500
parents 33a6eee08db2
children 2372284d9457
comparison
equal deleted inserted replaced
41334:5361f9ed8a30 41335:b81ca9a3f4e4
9 9
10 import contextlib 10 import contextlib
11 11
12 from mercurial import ( 12 from mercurial import (
13 localrepo, 13 localrepo,
14 pycompat,
14 wireprotov1peer, 15 wireprotov1peer,
16 )
15 17
16 ) 18 def bprint(*bs):
19 print(*[pycompat.sysstr(b) for b in bs])
17 20
18 # equivalent of repo.repository 21 # equivalent of repo.repository
19 class thing(object): 22 class thing(object):
20 def hello(self): 23 def hello(self):
21 return "Ready." 24 return b"Ready."
22 25
23 # equivalent of localrepo.localrepository 26 # equivalent of localrepo.localrepository
24 class localthing(thing): 27 class localthing(thing):
25 def foo(self, one, two=None): 28 def foo(self, one, two=None):
26 if one: 29 if one:
27 return "%s and %s" % (one, two,) 30 return b"%s and %s" % (one, two,)
28 return "Nope" 31 return b"Nope"
29 def bar(self, b, a): 32 def bar(self, b, a):
30 return "%s und %s" % (b, a,) 33 return b"%s und %s" % (b, a,)
31 def greet(self, name=None): 34 def greet(self, name=None):
32 return "Hello, %s" % name 35 return b"Hello, %s" % name
33 36
34 @contextlib.contextmanager 37 @contextlib.contextmanager
35 def commandexecutor(self): 38 def commandexecutor(self):
36 e = localrepo.localcommandexecutor(self) 39 e = localrepo.localcommandexecutor(self)
37 try: 40 try:
41 44
42 # usage of "thing" interface 45 # usage of "thing" interface
43 def use(it): 46 def use(it):
44 47
45 # Direct call to base method shared between client and server. 48 # Direct call to base method shared between client and server.
46 print(it.hello()) 49 bprint(it.hello())
47 50
48 # Direct calls to proxied methods. They cause individual roundtrips. 51 # Direct calls to proxied methods. They cause individual roundtrips.
49 print(it.foo("Un", two="Deux")) 52 bprint(it.foo(b"Un", two=b"Deux"))
50 print(it.bar("Eins", "Zwei")) 53 bprint(it.bar(b"Eins", b"Zwei"))
51 54
52 # Batched call to a couple of proxied methods. 55 # Batched call to a couple of proxied methods.
53 56
54 with it.commandexecutor() as e: 57 with it.commandexecutor() as e:
55 ffoo = e.callcommand('foo', {'one': 'One', 'two': 'Two'}) 58 ffoo = e.callcommand(b'foo', {b'one': b'One', b'two': b'Two'})
56 fbar = e.callcommand('bar', {'b': 'Eins', 'a': 'Zwei'}) 59 fbar = e.callcommand(b'bar', {b'b': b'Eins', b'a': b'Zwei'})
57 fbar2 = e.callcommand('bar', {'b': 'Uno', 'a': 'Due'}) 60 fbar2 = e.callcommand(b'bar', {b'b': b'Uno', b'a': b'Due'})
58 61
59 print(ffoo.result()) 62 bprint(ffoo.result())
60 print(fbar.result()) 63 bprint(fbar.result())
61 print(fbar2.result()) 64 bprint(fbar2.result())
62 65
63 # local usage 66 # local usage
64 mylocal = localthing() 67 mylocal = localthing()
65 print() 68 print()
66 print("== Local") 69 bprint(b"== Local")
67 use(mylocal) 70 use(mylocal)
68 71
69 # demo remoting; mimicks what wireproto and HTTP/SSH do 72 # demo remoting; mimicks what wireproto and HTTP/SSH do
70 73
71 # shared 74 # shared
72 75
73 def escapearg(plain): 76 def escapearg(plain):
74 return (plain 77 return (plain
75 .replace(':', '::') 78 .replace(b':', b'::')
76 .replace(',', ':,') 79 .replace(b',', b':,')
77 .replace(';', ':;') 80 .replace(b';', b':;')
78 .replace('=', ':=')) 81 .replace(b'=', b':='))
79 def unescapearg(escaped): 82 def unescapearg(escaped):
80 return (escaped 83 return (escaped
81 .replace(':=', '=') 84 .replace(b':=', b'=')
82 .replace(':;', ';') 85 .replace(b':;', b';')
83 .replace(':,', ',') 86 .replace(b':,', b',')
84 .replace('::', ':')) 87 .replace(b'::', b':'))
85 88
86 # server side 89 # server side
87 90
88 # equivalent of wireproto's global functions 91 # equivalent of wireproto's global functions
89 class server(object): 92 class server(object):
90 def __init__(self, local): 93 def __init__(self, local):
91 self.local = local 94 self.local = local
92 def _call(self, name, args): 95 def _call(self, name, args):
93 args = dict(arg.split('=', 1) for arg in args) 96 args = dict(arg.split(b'=', 1) for arg in args)
94 return getattr(self, name)(**args) 97 return getattr(self, name)(**args)
95 def perform(self, req): 98 def perform(self, req):
96 print("REQ:", req) 99 bprint(b"REQ:", req)
97 name, args = req.split('?', 1) 100 name, args = req.split(b'?', 1)
98 args = args.split('&') 101 args = args.split(b'&')
99 vals = dict(arg.split('=', 1) for arg in args) 102 vals = dict(arg.split(b'=', 1) for arg in args)
100 res = getattr(self, name)(**vals) 103 res = getattr(self, pycompat.sysstr(name))(**pycompat.strkwargs(vals))
101 print(" ->", res) 104 bprint(b" ->", res)
102 return res 105 return res
103 def batch(self, cmds): 106 def batch(self, cmds):
104 res = [] 107 res = []
105 for pair in cmds.split(';'): 108 for pair in cmds.split(b';'):
106 name, args = pair.split(':', 1) 109 name, args = pair.split(b':', 1)
107 vals = {} 110 vals = {}
108 for a in args.split(','): 111 for a in args.split(b','):
109 if a: 112 if a:
110 n, v = a.split('=') 113 n, v = a.split(b'=')
111 vals[n] = unescapearg(v) 114 vals[n] = unescapearg(v)
112 res.append(escapearg(getattr(self, name)(**vals))) 115 res.append(escapearg(getattr(self, pycompat.sysstr(name))(
113 return ';'.join(res) 116 **pycompat.strkwargs(vals))))
117 return b';'.join(res)
114 def foo(self, one, two): 118 def foo(self, one, two):
115 return mangle(self.local.foo(unmangle(one), unmangle(two))) 119 return mangle(self.local.foo(unmangle(one), unmangle(two)))
116 def bar(self, b, a): 120 def bar(self, b, a):
117 return mangle(self.local.bar(unmangle(b), unmangle(a))) 121 return mangle(self.local.bar(unmangle(b), unmangle(a)))
118 def greet(self, name): 122 def greet(self, name):
122 # local side 126 # local side
123 127
124 # equivalent of wireproto.encode/decodelist, that is, type-specific marshalling 128 # equivalent of wireproto.encode/decodelist, that is, type-specific marshalling
125 # here we just transform the strings a bit to check we're properly en-/decoding 129 # here we just transform the strings a bit to check we're properly en-/decoding
126 def mangle(s): 130 def mangle(s):
127 return ''.join(chr(ord(c) + 1) for c in s) 131 return b''.join(pycompat.bytechr(ord(c) + 1) for c in pycompat.bytestr(s))
128 def unmangle(s): 132 def unmangle(s):
129 return ''.join(chr(ord(c) - 1) for c in s) 133 return b''.join(pycompat.bytechr(ord(c) - 1) for c in pycompat.bytestr(s))
130 134
131 # equivalent of wireproto.wirerepository and something like http's wire format 135 # equivalent of wireproto.wirerepository and something like http's wire format
132 class remotething(thing): 136 class remotething(thing):
133 def __init__(self, server): 137 def __init__(self, server):
134 self.server = server 138 self.server = server
135 def _submitone(self, name, args): 139 def _submitone(self, name, args):
136 req = name + '?' + '&'.join(['%s=%s' % (n, v) for n, v in args]) 140 req = name + b'?' + b'&'.join([b'%s=%s' % (n, v) for n, v in args])
137 return self.server.perform(req) 141 return self.server.perform(req)
138 def _submitbatch(self, cmds): 142 def _submitbatch(self, cmds):
139 req = [] 143 req = []
140 for name, args in cmds: 144 for name, args in cmds:
141 args = ','.join(n + '=' + escapearg(v) for n, v in args) 145 args = b','.join(n + b'=' + escapearg(v) for n, v in args)
142 req.append(name + ':' + args) 146 req.append(name + b':' + args)
143 req = ';'.join(req) 147 req = b';'.join(req)
144 res = self._submitone('batch', [('cmds', req,)]) 148 res = self._submitone(b'batch', [(b'cmds', req,)])
145 for r in res.split(';'): 149 for r in res.split(b';'):
146 yield r 150 yield r
147 151
148 @contextlib.contextmanager 152 @contextlib.contextmanager
149 def commandexecutor(self): 153 def commandexecutor(self):
150 e = wireprotov1peer.peerexecutor(self) 154 e = wireprotov1peer.peerexecutor(self)
153 finally: 157 finally:
154 e.close() 158 e.close()
155 159
156 @wireprotov1peer.batchable 160 @wireprotov1peer.batchable
157 def foo(self, one, two=None): 161 def foo(self, one, two=None):
158 encargs = [('one', mangle(one),), ('two', mangle(two),)] 162 encargs = [(b'one', mangle(one),), (b'two', mangle(two),)]
159 encresref = wireprotov1peer.future() 163 encresref = wireprotov1peer.future()
160 yield encargs, encresref 164 yield encargs, encresref
161 yield unmangle(encresref.value) 165 yield unmangle(encresref.value)
162 166
163 @wireprotov1peer.batchable 167 @wireprotov1peer.batchable
164 def bar(self, b, a): 168 def bar(self, b, a):
165 encresref = wireprotov1peer.future() 169 encresref = wireprotov1peer.future()
166 yield [('b', mangle(b),), ('a', mangle(a),)], encresref 170 yield [(b'b', mangle(b),), (b'a', mangle(a),)], encresref
167 yield unmangle(encresref.value) 171 yield unmangle(encresref.value)
168 172
169 # greet is coded directly. It therefore does not support batching. If it 173 # greet is coded directly. It therefore does not support batching. If it
170 # does appear in a batch, the batch is split around greet, and the call to 174 # does appear in a batch, the batch is split around greet, and the call to
171 # greet is done in its own roundtrip. 175 # greet is done in its own roundtrip.
172 def greet(self, name=None): 176 def greet(self, name=None):
173 return unmangle(self._submitone('greet', [('name', mangle(name),)])) 177 return unmangle(self._submitone(b'greet', [(b'name', mangle(name),)]))
174 178
175 # demo remote usage 179 # demo remote usage
176 180
177 myproxy = remotething(myserver) 181 myproxy = remotething(myserver)
178 print() 182 print()
179 print("== Remote") 183 bprint(b"== Remote")
180 use(myproxy) 184 use(myproxy)