##// END OF EJS Templates
pycompat: custom implementation of urllib.parse.quote()...
pycompat: custom implementation of urllib.parse.quote() urllib.parse.quote() accepts either str or bytes and returns str. There exists a urllib.parse.quote_from_bytes() which only accepts bytes. We should probably use that to retain strong typing and avoid surprises. In addition, since nearly all strings in Mercurial are bytes, we probably don't want quote() returning unicode. So, this patch implements a custom quote() that only accepts bytes and returns bytes. The quoted URL should only contain URL safe characters which is a strict subset of ASCII. So `.encode('ascii', 'strict')` should be safe.

File last commit:

r28800:544908ae default
r31400:fb1f7033 default
Show More
test-batching.py
180 lines | 5.5 KiB | text/x-python | PythonLexer
Peter Arrenbrecht
wireproto: add basic command batching infrastructure...
r14621 # test-batching.py - tests for transparent command batching
#
# Copyright 2011 Peter Arrenbrecht <peter@arrenbrecht.ch>
#
# This software may be used and distributed according to the terms of the
# GNU General Public License version 2 or any later version.
Robert Stanca
py3: use print_function in test-batching.py
r28732 from __future__ import absolute_import, print_function
Yuya Nishihara
test-batching: stop direct symbol import of mercurial modules...
r28800
from mercurial import (
peer,
wireproto,
Robert Stanca
py3: use absolute_import in test-batching.py
r28731 )
Peter Arrenbrecht
wireproto: add basic command batching infrastructure...
r14621
# equivalent of repo.repository
class thing(object):
def hello(self):
return "Ready."
# equivalent of localrepo.localrepository
class localthing(thing):
def foo(self, one, two=None):
if one:
return "%s and %s" % (one, two,)
return "Nope"
def bar(self, b, a):
return "%s und %s" % (b, a,)
def greet(self, name=None):
return "Hello, %s" % name
def batch(self):
'''Support for local batching.'''
Yuya Nishihara
test-batching: stop direct symbol import of mercurial modules...
r28800 return peer.localbatch(self)
Peter Arrenbrecht
wireproto: add basic command batching infrastructure...
r14621
# usage of "thing" interface
def use(it):
# Direct call to base method shared between client and server.
Robert Stanca
py3: use print_function in test-batching.py
r28732 print(it.hello())
Peter Arrenbrecht
wireproto: add basic command batching infrastructure...
r14621
# Direct calls to proxied methods. They cause individual roundtrips.
Robert Stanca
py3: use print_function in test-batching.py
r28732 print(it.foo("Un", two="Deux"))
print(it.bar("Eins", "Zwei"))
Peter Arrenbrecht
wireproto: add basic command batching infrastructure...
r14621
# Batched call to a couple of (possibly proxied) methods.
batch = it.batch()
# The calls return futures to eventually hold results.
foo = batch.foo(one="One", two="Two")
foo2 = batch.foo(None)
bar = batch.bar("Eins", "Zwei")
# We can call non-batchable proxy methods, but the break the current batch
# request and cause additional roundtrips.
greet = batch.greet(name="John Smith")
# We can also add local methods into the mix, but they break the batch too.
hello = batch.hello()
bar2 = batch.bar(b="Uno", a="Due")
# Only now are all the calls executed in sequence, with as few roundtrips
# as possible.
batch.submit()
# After the call to submit, the futures actually contain values.
Robert Stanca
py3: use print_function in test-batching.py
r28732 print(foo.value)
print(foo2.value)
print(bar.value)
print(greet.value)
print(hello.value)
print(bar2.value)
Peter Arrenbrecht
wireproto: add basic command batching infrastructure...
r14621
# local usage
mylocal = localthing()
Robert Stanca
py3: use print_function in test-batching.py
r28732 print()
print("== Local")
Peter Arrenbrecht
wireproto: add basic command batching infrastructure...
r14621 use(mylocal)
# demo remoting; mimicks what wireproto and HTTP/SSH do
# shared
def escapearg(plain):
return (plain
.replace(':', '::')
.replace(',', ':,')
.replace(';', ':;')
.replace('=', ':='))
def unescapearg(escaped):
return (escaped
.replace(':=', '=')
.replace(':;', ';')
.replace(':,', ',')
.replace('::', ':'))
# server side
# equivalent of wireproto's global functions
Thomas Arendsen Hein
classes: fix class style problems found by b071cd58af50...
r14764 class server(object):
Peter Arrenbrecht
wireproto: add basic command batching infrastructure...
r14621 def __init__(self, local):
self.local = local
def _call(self, name, args):
args = dict(arg.split('=', 1) for arg in args)
return getattr(self, name)(**args)
def perform(self, req):
Robert Stanca
py3: use print_function in test-batching.py
r28732 print("REQ:", req)
Peter Arrenbrecht
wireproto: add basic command batching infrastructure...
r14621 name, args = req.split('?', 1)
args = args.split('&')
vals = dict(arg.split('=', 1) for arg in args)
res = getattr(self, name)(**vals)
Robert Stanca
py3: use print_function in test-batching.py
r28732 print(" ->", res)
Peter Arrenbrecht
wireproto: add basic command batching infrastructure...
r14621 return res
def batch(self, cmds):
res = []
for pair in cmds.split(';'):
name, args = pair.split(':', 1)
vals = {}
for a in args.split(','):
if a:
n, v = a.split('=')
vals[n] = unescapearg(v)
res.append(escapearg(getattr(self, name)(**vals)))
return ';'.join(res)
def foo(self, one, two):
return mangle(self.local.foo(unmangle(one), unmangle(two)))
def bar(self, b, a):
return mangle(self.local.bar(unmangle(b), unmangle(a)))
def greet(self, name):
return mangle(self.local.greet(unmangle(name)))
myserver = server(mylocal)
# local side
# equivalent of wireproto.encode/decodelist, that is, type-specific marshalling
# here we just transform the strings a bit to check we're properly en-/decoding
def mangle(s):
return ''.join(chr(ord(c) + 1) for c in s)
def unmangle(s):
return ''.join(chr(ord(c) - 1) for c in s)
# equivalent of wireproto.wirerepository and something like http's wire format
class remotething(thing):
def __init__(self, server):
self.server = server
def _submitone(self, name, args):
req = name + '?' + '&'.join(['%s=%s' % (n, v) for n, v in args])
return self.server.perform(req)
def _submitbatch(self, cmds):
req = []
for name, args in cmds:
args = ','.join(n + '=' + escapearg(v) for n, v in args)
req.append(name + ':' + args)
req = ';'.join(req)
res = self._submitone('batch', [('cmds', req,)])
return res.split(';')
def batch(self):
Yuya Nishihara
test-batching: stop direct symbol import of mercurial modules...
r28800 return wireproto.remotebatch(self)
Peter Arrenbrecht
wireproto: add basic command batching infrastructure...
r14621
Yuya Nishihara
test-batching: stop direct symbol import of mercurial modules...
r28800 @peer.batchable
Peter Arrenbrecht
wireproto: add basic command batching infrastructure...
r14621 def foo(self, one, two=None):
if not one:
yield "Nope", None
encargs = [('one', mangle(one),), ('two', mangle(two),)]
Yuya Nishihara
test-batching: stop direct symbol import of mercurial modules...
r28800 encresref = peer.future()
Peter Arrenbrecht
wireproto: add basic command batching infrastructure...
r14621 yield encargs, encresref
yield unmangle(encresref.value)
Yuya Nishihara
test-batching: stop direct symbol import of mercurial modules...
r28800 @peer.batchable
Peter Arrenbrecht
wireproto: add basic command batching infrastructure...
r14621 def bar(self, b, a):
Yuya Nishihara
test-batching: stop direct symbol import of mercurial modules...
r28800 encresref = peer.future()
Peter Arrenbrecht
wireproto: add basic command batching infrastructure...
r14621 yield [('b', mangle(b),), ('a', mangle(a),)], encresref
yield unmangle(encresref.value)
# greet is coded directly. It therefore does not support batching. If it
# does appear in a batch, the batch is split around greet, and the call to
# greet is done in its own roundtrip.
def greet(self, name=None):
return unmangle(self._submitone('greet', [('name', mangle(name),)]))
# demo remote usage
myproxy = remotething(myserver)
Robert Stanca
py3: use print_function in test-batching.py
r28732 print()
print("== Remote")
Peter Arrenbrecht
wireproto: add basic command batching infrastructure...
r14621 use(myproxy)