Rev 6383: (jelmer) Include quote() and unquote() directly in bzrlib.urlutils. (Jelmer in file:///srv/pqm.bazaar-vcs.org/archives/thelove/bzr/%2Btrunk/
Patch Queue Manager
pqm at pqm.ubuntu.com
Mon Dec 19 01:56:41 UTC 2011
At file:///srv/pqm.bazaar-vcs.org/archives/thelove/bzr/%2Btrunk/
------------------------------------------------------------
revno: 6383 [merge]
revision-id: pqm at pqm.ubuntu.com-20111219015641-k7fyhyf6rfgk93m2
parent: pqm at pqm.ubuntu.com-20111219011443-9ai5egjyc2rgnup0
parent: jelmer at canonical.com-20111219013027-pokwpa1buegc1pv2
committer: Patch Queue Manager <pqm at pqm.ubuntu.com>
branch nick: +trunk
timestamp: Mon 2011-12-19 01:56:41 +0000
message:
(jelmer) Include quote() and unquote() directly in bzrlib.urlutils. (Jelmer
Vernooij)
modified:
bzrlib/mail_client.py mail_client.py-20070809192806-vuxt3t19srtpjpdn-1
bzrlib/plugins/launchpad/lp_registration.py lp_registration.py-20060315190948-daa617eafe3a8d48
bzrlib/plugins/weave_fmt/repository.py presplitout.py-20070125045333-wfav3tsh73oxu3zk-1
bzrlib/smart/medium.py medium.py-20061103051856-rgu2huy59fkz902q-1
bzrlib/tests/http_server.py httpserver.py-20061012142527-m1yxdj1xazsf8d7s-1
bzrlib/tests/test_ftp_transport.py test_aftp_transport.-20060823221619-98mwjzxtwtkt527k-1
bzrlib/tests/test_import_tariff.py test_import_tariff.p-20100207155145-ff9infp7goncs7zh-1
bzrlib/tests/test_mail_client.py test_mail_client.py-20070809192806-vuxt3t19srtpjpdn-2
bzrlib/tests/test_permissions.py test_permissions.py-20051215004520-ccf475789c80e80c
bzrlib/tests/test_urlutils.py test_urlutils.py-20060502192900-46b1f9579987cf9c
bzrlib/transport/__init__.py transport.py-20050711165921-4978aa7ce1285ad5
bzrlib/transport/http/__init__.py http_transport.py-20050711212304-506c5fd1059ace96
bzrlib/urlutils.py urlutils.py-20060502195429-e8a161ecf8fac004
bzrlib/versionedfile.py versionedfile.py-20060222045106-5039c71ee3b65490
doc/en/release-notes/bzr-2.5.txt bzr2.5.txt-20110708125756-587p0hpw7oke4h05-1
=== modified file 'bzrlib/mail_client.py'
--- a/bzrlib/mail_client.py 2010-04-23 08:51:52 +0000
+++ b/bzrlib/mail_client.py 2011-12-18 15:43:47 +0000
@@ -19,7 +19,6 @@
import subprocess
import sys
import tempfile
-import urllib
import bzrlib
from bzrlib import (
@@ -310,7 +309,7 @@
message_options['attachment'] = urlutils.local_path_to_url(
attach_path)
if body is not None:
- options_list = ['body=%s' % urllib.quote(self._encode_safe(body))]
+ options_list = ['body=%s' % urlutils.quote(self._encode_safe(body))]
else:
options_list = []
options_list.extend(["%s='%s'" % (k, v) for k, v in
@@ -352,15 +351,15 @@
"""See ExternalMailClient._get_compose_commandline"""
compose_url = []
if from_ is not None:
- compose_url.append('from=' + urllib.quote(from_))
+ compose_url.append('from=' + urlutils.quote(from_))
if subject is not None:
- # Don't use urllib.quote_plus because Claws doesn't seem
+ # Don't use urlutils.quote_plus because Claws doesn't seem
# to recognise spaces encoded as "+".
compose_url.append(
- 'subject=' + urllib.quote(self._encode_safe(subject)))
+ 'subject=' + urlutils.quote(self._encode_safe(subject)))
if body is not None:
compose_url.append(
- 'body=' + urllib.quote(self._encode_safe(body)))
+ 'body=' + urlutils.quote(self._encode_safe(body)))
# to must be supplied for the claws-mail --compose syntax to work.
if to is None:
raise errors.NoMailAddressSpecified()
=== modified file 'bzrlib/plugins/launchpad/lp_registration.py'
--- a/bzrlib/plugins/launchpad/lp_registration.py 2011-03-24 11:41:42 +0000
+++ b/bzrlib/plugins/launchpad/lp_registration.py 2011-12-18 15:43:47 +0000
@@ -166,8 +166,8 @@
# the url? perhaps a bit more secure against accidentally
# revealing it. std66 s3.2.1 discourages putting the
# password in the url.
- hostinfo = '%s:%s@%s' % (urllib.quote(self.registrant_email),
- urllib.quote(self.registrant_password),
+ hostinfo = '%s:%s@%s' % (urlutils.quote(self.registrant_email),
+ urlutils.quote(self.registrant_password),
hostinfo)
url = urlunsplit((scheme, hostinfo, path, '', ''))
else:
=== modified file 'bzrlib/plugins/weave_fmt/repository.py'
--- a/bzrlib/plugins/weave_fmt/repository.py 2011-12-07 14:03:01 +0000
+++ b/bzrlib/plugins/weave_fmt/repository.py 2011-12-18 15:43:47 +0000
@@ -23,7 +23,6 @@
import gzip
import os
from cStringIO import StringIO
-import urllib
from bzrlib.lazy_import import lazy_import
lazy_import(globals(), """
@@ -708,7 +707,7 @@
raise errors.ObjectNotLocked(self)
relpaths = set()
for quoted_relpath in self._transport.iter_files_recursive():
- relpath = urllib.unquote(quoted_relpath)
+ relpath = urlutils.unquote(quoted_relpath)
path, ext = os.path.splitext(relpath)
if ext == '.gz':
relpath = path
@@ -748,7 +747,7 @@
raise errors.ObjectNotLocked(self)
relpaths = set()
for quoted_relpath in self._transport.iter_files_recursive():
- relpath = urllib.unquote(quoted_relpath)
+ relpath = urlutils.unquote(quoted_relpath)
path, ext = os.path.splitext(relpath)
if ext == '.gz':
relpath = path
=== modified file 'bzrlib/smart/medium.py'
--- a/bzrlib/smart/medium.py 2011-11-25 17:54:52 +0000
+++ b/bzrlib/smart/medium.py 2011-12-18 15:43:47 +0000
@@ -28,7 +28,6 @@
import os
import sys
import time
-import urllib
import bzrlib
from bzrlib.lazy_import import lazy_import
@@ -840,7 +839,7 @@
"""
medium_base = urlutils.join(self.base, '/')
rel_url = urlutils.relative_url(medium_base, transport.base)
- return urllib.unquote(rel_url)
+ return urlutils.unquote(rel_url)
class SmartClientStreamMedium(SmartClientMedium):
=== modified file 'bzrlib/tests/http_server.py'
--- a/bzrlib/tests/http_server.py 2011-03-08 16:00:55 +0000
+++ b/bzrlib/tests/http_server.py 2011-12-18 15:43:47 +0000
@@ -22,9 +22,9 @@
import re
import SimpleHTTPServer
import socket
-import urllib
import urlparse
+from bzrlib import urlutils
from bzrlib.tests import test_server
@@ -336,7 +336,7 @@
"""
# abandon query parameters
path = urlparse.urlparse(path)[2]
- path = posixpath.normpath(urllib.unquote(path))
+ path = posixpath.normpath(urlutils.unquote(path))
path = path.decode('utf-8')
words = path.split('/')
words = filter(None, words)
=== modified file 'bzrlib/tests/test_ftp_transport.py'
--- a/bzrlib/tests/test_ftp_transport.py 2011-08-19 22:34:02 +0000
+++ b/bzrlib/tests/test_ftp_transport.py 2011-12-18 15:43:47 +0000
@@ -16,7 +16,6 @@
import ftplib
import getpass
-import urllib
from bzrlib import (
config,
@@ -24,6 +23,7 @@
tests,
transport,
ui,
+ urlutils,
)
from bzrlib.transport import ftp
@@ -85,9 +85,9 @@
parsed_url = transport.ConnectedTransport._split_url(base)
new_url = parsed_url.clone()
new_url.user = self.user
- new_url.quoted_user = urllib.quote(self.user)
+ new_url.quoted_user = urlutils.quote(self.user)
new_url.password = self.password
- new_url.quoted_password = urllib.quote(self.password)
+ new_url.quoted_password = urlutils.quote(self.password)
return str(new_url)
def test_no_prompt_for_username(self):
=== modified file 'bzrlib/tests/test_import_tariff.py'
--- a/bzrlib/tests/test_import_tariff.py 2011-12-18 15:49:48 +0000
+++ b/bzrlib/tests/test_import_tariff.py 2011-12-19 00:55:07 +0000
@@ -190,11 +190,14 @@
'bzrlib.xml8',
'getpass',
'kerberos',
+ 'ssl',
+ 'socket',
'smtplib',
'tarfile',
'tempfile',
'termios',
'tty',
+ 'urllib',
] + old_format_modules)
# TODO: similar test for repository-only operations, checking we avoid
# loading wt-specific stuff
=== modified file 'bzrlib/tests/test_mail_client.py'
--- a/bzrlib/tests/test_mail_client.py 2009-09-02 08:26:27 +0000
+++ b/bzrlib/tests/test_mail_client.py 2011-12-18 15:43:47 +0000
@@ -14,8 +14,6 @@
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
-import urllib
-
from bzrlib import (
errors,
mail_client,
@@ -212,7 +210,7 @@
claws = mail_client.Claws(None)
cmdline = claws._get_compose_commandline(
u'jrandom at example.org', u'\xb5cosm of fun!', u'file%')
- subject_string = urllib.quote(
+ subject_string = urlutils.quote(
u'\xb5cosm of fun!'.encode(osutils.get_user_encoding(), 'replace'))
self.assertEqual(
['--compose',
=== modified file 'bzrlib/tests/test_permissions.py'
--- a/bzrlib/tests/test_permissions.py 2011-02-25 15:24:22 +0000
+++ b/bzrlib/tests/test_permissions.py 2011-12-18 15:43:47 +0000
@@ -32,9 +32,8 @@
import os
import sys
-import urllib
-from bzrlib import transport
+from bzrlib import urlutils
from bzrlib.branch import Branch
from bzrlib.bzrdir import BzrDir
from bzrlib.tests import TestCaseWithTransport, TestSkipped
@@ -68,11 +67,11 @@
test.assertTransportMode(t, base, dir_mode)
for root, dirs, files in os.walk(base):
for d in dirs:
- p = '/'.join([urllib.quote(x) for x in root.split('/\\') + [d]])
+ p = '/'.join([urlutils.quote(x) for x in root.split('/\\') + [d]])
test.assertTransportMode(t, p, dir_mode)
for f in files:
p = os.path.join(root, f)
- p = '/'.join([urllib.quote(x) for x in root.split('/\\') + [f]])
+ p = '/'.join([urlutils.quote(x) for x in root.split('/\\') + [f]])
test.assertTransportMode(t, p, file_mode)
=== modified file 'bzrlib/tests/test_urlutils.py'
--- a/bzrlib/tests/test_urlutils.py 2011-11-24 13:15:51 +0000
+++ b/bzrlib/tests/test_urlutils.py 2011-12-18 20:46:39 +0000
@@ -1026,3 +1026,20 @@
urlutils.file_relpath, "file:///A:/b", "file:///A:/")
self.assertRaises(PathNotChild,
urlutils.file_relpath, "file:///A:/b/c", "file:///A:/b")
+
+
+class QuoteTests(TestCase):
+
+ def test_quote(self):
+ self.assertEqual('abc%20def', urlutils.quote('abc def'))
+ self.assertEqual('abc%2Fdef', urlutils.quote('abc/def', safe=''))
+ self.assertEqual('abc/def', urlutils.quote('abc/def', safe='/'))
+
+ def test_quote_tildes(self):
+ self.assertEqual('%7Efoo', urlutils.quote('~foo'))
+ self.assertEqual('~foo', urlutils.quote('~foo', safe='/~'))
+
+ def test_unquote(self):
+ self.assertEqual('%', urlutils.unquote('%25'))
+ self.assertEqual('\xc3\xa5', urlutils.unquote('%C3%A5'))
+ self.assertEqual(u"\xe5", urlutils.unquote(u'\xe5'))
=== modified file 'bzrlib/transport/__init__.py'
--- a/bzrlib/transport/__init__.py 2011-11-25 17:49:44 +0000
+++ b/bzrlib/transport/__init__.py 2011-12-18 15:43:47 +0000
@@ -33,7 +33,6 @@
lazy_import(globals(), """
import errno
from stat import S_ISDIR
-import urllib
import urlparse
from bzrlib import (
@@ -1415,12 +1414,12 @@
:return: The corresponding URL.
"""
- netloc = urllib.quote(host)
+ netloc = urlutils.quote(host)
if user is not None:
# Note that we don't put the password back even if we
# have one so that it doesn't get accidentally
# exposed.
- netloc = '%s@%s' % (urllib.quote(user), netloc)
+ netloc = '%s@%s' % (urlutils.quote(user), netloc)
if port is not None:
netloc = '%s:%d' % (netloc, port)
path = urlutils.escape(path)
=== modified file 'bzrlib/transport/http/__init__.py'
--- a/bzrlib/transport/http/__init__.py 2011-09-19 13:02:42 +0000
+++ b/bzrlib/transport/http/__init__.py 2011-12-18 15:43:47 +0000
@@ -22,7 +22,6 @@
from cStringIO import StringIO
import re
import urlparse
-import urllib
import sys
import weakref
@@ -63,9 +62,9 @@
host = netloc.split(':', 1)[0]
else:
host = netloc
- username = urllib.unquote(username)
+ username = urlutils.unquote(username)
if password is not None:
- password = urllib.unquote(password)
+ password = urlutils.unquote(password)
else:
password = ui.ui_factory.get_password(
prompt=u'HTTP %(user)s@%(host)s password',
@@ -589,7 +588,7 @@
if transport_base.startswith('bzr+'):
transport_base = transport_base[4:]
rel_url = urlutils.relative_url(self.base, transport_base)
- return urllib.unquote(rel_url)
+ return urlutils.unquote(rel_url)
def send_http_smart_request(self, bytes):
try:
=== modified file 'bzrlib/urlutils.py'
--- a/bzrlib/urlutils.py 2011-11-24 13:15:51 +0000
+++ b/bzrlib/urlutils.py 2011-12-19 01:30:27 +0000
@@ -23,7 +23,6 @@
from bzrlib.lazy_import import lazy_import
lazy_import(globals(), """
from posixpath import split as _posix_split
-import urllib
import urlparse
from bzrlib import (
@@ -60,13 +59,87 @@
return split(url, exclude_trailing_slash=exclude_trailing_slash)[0]
+# Private copies of quote and unquote, copied from Python's
+# urllib module because urllib unconditionally imports socket, which imports
+# ssl.
+
+always_safe = ('ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+ 'abcdefghijklmnopqrstuvwxyz'
+ '0123456789' '_.-')
+_safe_map = {}
+for i, c in zip(xrange(256), str(bytearray(xrange(256)))):
+ _safe_map[c] = c if (i < 128 and c in always_safe) else '%{0:02X}'.format(i)
+_safe_quoters = {}
+
+
+def quote(s, safe='/'):
+ """quote('abc def') -> 'abc%20def'
+
+ Each part of a URL, e.g. the path info, the query, etc., has a
+ different set of reserved characters that must be quoted.
+
+ RFC 2396 Uniform Resource Identifiers (URI): Generic Syntax lists
+ the following reserved characters.
+
+ reserved = ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" |
+ "$" | ","
+
+ Each of these characters is reserved in some component of a URL,
+ but not necessarily in all of them.
+
+ By default, the quote function is intended for quoting the path
+ section of a URL. Thus, it will not encode '/'. This character
+ is reserved, but in typical usage the quote function is being
+ called on a path where the existing slash characters are used as
+ reserved characters.
+ """
+ # fastpath
+ if not s:
+ if s is None:
+ raise TypeError('None object cannot be quoted')
+ return s
+ cachekey = (safe, always_safe)
+ try:
+ (quoter, safe) = _safe_quoters[cachekey]
+ except KeyError:
+ safe_map = _safe_map.copy()
+ safe_map.update([(c, c) for c in safe])
+ quoter = safe_map.__getitem__
+ safe = always_safe + safe
+ _safe_quoters[cachekey] = (quoter, safe)
+ if not s.rstrip(safe):
+ return s
+ return ''.join(map(quoter, s))
+
+
+_hexdig = '0123456789ABCDEFabcdef'
+_hextochr = dict((a + b, chr(int(a + b, 16)))
+ for a in _hexdig for b in _hexdig)
+
+def unquote(s):
+ """unquote('abc%20def') -> 'abc def'."""
+ res = s.split('%')
+ # fastpath
+ if len(res) == 1:
+ return s
+ s = res[0]
+ for item in res[1:]:
+ try:
+ s += _hextochr[item[:2]] + item[2:]
+ except KeyError:
+ s += '%' + item
+ except UnicodeDecodeError:
+ s += unichr(int(item[:2], 16)) + item[2:]
+ return s
+
+
def escape(relpath):
"""Escape relpath to be a valid url."""
if isinstance(relpath, unicode):
relpath = relpath.encode('utf-8')
# After quoting and encoding, the path should be perfectly
# safe as a plain ASCII string, str() just enforces this
- return str(urllib.quote(relpath, safe='/~'))
+ return str(quote(relpath, safe='/~'))
def file_relpath(base, path):
@@ -566,7 +639,7 @@
This returns a Unicode path from a URL
"""
# jam 20060427 URLs are supposed to be ASCII only strings
- # If they are passed in as unicode, urllib.unquote
+ # If they are passed in as unicode, unquote
# will return a UNICODE string, which actually contains
# utf-8 bytes. So we have to ensure that they are
# plain ASCII strings, or the final .decode will
@@ -577,7 +650,7 @@
except UnicodeError, e:
raise errors.InvalidURL(url, 'URL was not a plain ASCII url: %s' % (e,))
- unquoted = urllib.unquote(url)
+ unquoted = unquote(url)
try:
unicode_path = unquoted.decode('utf-8')
except UnicodeError, e:
@@ -742,20 +815,20 @@
port, quoted_path):
self.scheme = scheme
self.quoted_host = quoted_host
- self.host = urllib.unquote(self.quoted_host)
+ self.host = unquote(self.quoted_host)
self.quoted_user = quoted_user
if self.quoted_user is not None:
- self.user = urllib.unquote(self.quoted_user)
+ self.user = unquote(self.quoted_user)
else:
self.user = None
self.quoted_password = quoted_password
if self.quoted_password is not None:
- self.password = urllib.unquote(self.quoted_password)
+ self.password = unquote(self.quoted_password)
else:
self.password = None
self.port = port
self.quoted_path = _url_hex_escapes_re.sub(_unescape_safe_chars, quoted_path)
- self.path = urllib.unquote(self.quoted_path)
+ self.path = unquote(self.quoted_path)
def __eq__(self, other):
return (isinstance(other, self.__class__) and
@@ -871,7 +944,7 @@
if offset is not None:
relative = unescape(offset).encode('utf-8')
path = self._combine_paths(self.path, relative)
- path = urllib.quote(path, safe="/~")
+ path = quote(path, safe="/~")
else:
path = self.quoted_path
return self.__class__(self.scheme, self.quoted_user,
=== modified file 'bzrlib/versionedfile.py'
--- a/bzrlib/versionedfile.py 2011-05-16 10:08:01 +0000
+++ b/bzrlib/versionedfile.py 2011-12-18 15:43:47 +0000
@@ -24,8 +24,6 @@
from bzrlib.lazy_import import lazy_import
lazy_import(globals(), """
-import urllib
-
from bzrlib import (
annotate,
bencode,
@@ -38,6 +36,7 @@
multiparent,
tsort,
revision,
+ urlutils,
)
""")
from bzrlib.registry import Registry
@@ -821,11 +820,11 @@
def map(self, key):
"""See KeyMapper.map()."""
- return urllib.quote(self._map(key))
+ return urlutils.quote(self._map(key))
def unmap(self, partition_id):
"""See KeyMapper.unmap()."""
- return self._unmap(urllib.unquote(partition_id))
+ return self._unmap(urlutils.unquote(partition_id))
class PrefixMapper(URLEscapeMapper):
@@ -878,7 +877,7 @@
def _escape(self, prefix):
"""Turn a key element into a filesystem safe string.
- This is similar to a plain urllib.quote, except
+ This is similar to a plain urlutils.quote, except
it uses specific safe characters, so that it doesn't
have to translate a lot of valid file ids.
"""
@@ -891,7 +890,7 @@
def _unescape(self, basename):
"""Escaped names are easily unescaped by urlutils."""
- return urllib.unquote(basename)
+ return urlutils.unquote(basename)
def make_versioned_files_factory(versioned_file_factory, mapper):
=== modified file 'doc/en/release-notes/bzr-2.5.txt'
--- a/doc/en/release-notes/bzr-2.5.txt 2011-12-15 14:47:22 +0000
+++ b/doc/en/release-notes/bzr-2.5.txt 2011-12-18 20:47:47 +0000
@@ -116,6 +116,11 @@
speeding up various commands including ``bzr export``,
``bzr checkout`` and ``bzr cat``. (Jelmer Vernooij, #608640)
+* ``bzrlib.urlutils`` now includes ``quote`` and ``unquote`` functions,
+ rather than importing them from ``urllib``. This prevents loading
+ of the ``socket``, ``ssl`` and ``urllib`` modules for
+ local bzr operations. (Jelmer Vernooij)
+
Testing
*******
More information about the bazaar-commits
mailing list