--- a/contrib/check-code.py Tue Jul 26 21:30:12 2011 +0200
+++ b/contrib/check-code.py Thu Jul 28 14:20:06 2011 -0500
@@ -148,7 +148,7 @@
(r'(?<!def)\s+(any|all|format)\(',
"any/all/format not available in Python 2.4"),
(r'(?<!def)\s+(callable)\(',
- "callable not available in Python 3, use hasattr(f, '__call__')"),
+ "callable not available in Python 3, use getattr(f, '__call__', None)"),
(r'if\s.*\selse', "if ... else form not available in Python 2.4"),
(r'^\s*(%s)\s\s' % '|'.join(keyword.kwlist),
"gratuitous whitespace after Python keyword"),
@@ -168,6 +168,8 @@
"comparison with singleton, use 'is' or 'is not' instead"),
(r'^\s*(while|if) [01]:',
"use True/False for constant Boolean expression"),
+ (r'(?<!def)\s+hasattr',
+ 'hasattr(foo, bar) is broken, use util.safehasattr(foo, bar) instead'),
(r'opener\([^)]*\).read\(',
"use opener.read() instead"),
(r'opener\([^)]*\).write\(',
--- a/contrib/setup3k.py Tue Jul 26 21:30:12 2011 +0200
+++ b/contrib/setup3k.py Thu Jul 28 14:20:06 2011 -0500
@@ -8,7 +8,7 @@
from lib2to3.refactor import get_fixers_from_package as getfixers
import sys
-if not hasattr(sys, 'version_info') or sys.version_info < (2, 4, 0, 'final'):
+if getattr(sys, 'version_info', (0, 0, 0)) < (2, 4, 0, 'final'):
raise SystemExit("Mercurial requires Python 2.4 or later.")
if sys.version_info[0] >= 3:
@@ -236,7 +236,7 @@
try:
build_ext.build_extension(self, ext)
except CCompilerError:
- if not hasattr(ext, 'optional') or not ext.optional:
+ if getattr(ext, 'optional', False):
raise
log.warn("Failed to build optional extension '%s' (skipping)",
ext.name)
--- a/contrib/win32/hgwebdir_wsgi.py Tue Jul 26 21:30:12 2011 +0200
+++ b/contrib/win32/hgwebdir_wsgi.py Thu Jul 28 14:20:06 2011 -0500
@@ -50,7 +50,7 @@
#sys.path.insert(0, r'c:\path\to\python\lib')
# Enable tracing. Run 'python -m win32traceutil' to debug
-if hasattr(sys, 'isapidllhandle'):
+if getattr(sys, 'isapidllhandle', None) is not None:
import win32traceutil
# To serve pages in local charset instead of UTF-8, remove the two lines below
--- a/doc/gendoc.py Tue Jul 26 21:30:12 2011 +0200
+++ b/doc/gendoc.py Thu Jul 28 14:20:06 2011 -0500
@@ -9,6 +9,7 @@
from mercurial.i18n import _
from mercurial.help import helptable
from mercurial import extensions
+from mercurial import util
def get_desc(docstr):
if not docstr:
@@ -95,7 +96,7 @@
ui.write(".. _%s:\n" % name)
ui.write("\n")
section(ui, sec)
- if hasattr(doc, '__call__'):
+ if util.safehasattr(doc, '__call__'):
doc = doc()
ui.write(doc)
ui.write("\n")
--- a/hgext/convert/cvsps.py Tue Jul 26 21:30:12 2011 +0200
+++ b/hgext/convert/cvsps.py Thu Jul 28 14:20:06 2011 -0500
@@ -11,6 +11,7 @@
from mercurial import util
from mercurial.i18n import _
from mercurial import hook
+from mercurial import util
class logentry(object):
'''Class logentry has the following attributes:
@@ -513,8 +514,8 @@
e.comment == c.comment and
e.author == c.author and
e.branch == c.branch and
- (not hasattr(e, 'branchpoints') or
- not hasattr (c, 'branchpoints') or
+ (not util.safehasattr(e, 'branchpoints') or
+ not util.safehasattr (c, 'branchpoints') or
e.branchpoints == c.branchpoints) and
((c.date[0] + c.date[1]) <=
(e.date[0] + e.date[1]) <=
--- a/hgext/convert/git.py Tue Jul 26 21:30:12 2011 +0200
+++ b/hgext/convert/git.py Thu Jul 28 14:20:06 2011 -0500
@@ -16,7 +16,7 @@
# Windows does not support GIT_DIR= construct while other systems
# cannot remove environment variable. Just assume none have
# both issues.
- if hasattr(os, 'unsetenv'):
+ if util.safehasattr(os, 'unsetenv'):
def gitopen(self, s, noerr=False):
prevgitdir = os.environ.get('GIT_DIR')
os.environ['GIT_DIR'] = self.path
--- a/hgext/convert/transport.py Tue Jul 26 21:30:12 2011 +0200
+++ b/hgext/convert/transport.py Thu Jul 28 14:20:06 2011 -0500
@@ -54,7 +54,7 @@
if p:
providers.append(p)
else:
- if hasattr(svn.client, 'get_windows_simple_provider'):
+ if util.safehasattr(svn.client, 'get_windows_simple_provider'):
providers.append(svn.client.get_windows_simple_provider(pool))
return svn.core.svn_auth_open(providers, pool)
@@ -73,7 +73,7 @@
self.password = ''
# Only Subversion 1.4 has reparent()
- if ra is None or not hasattr(svn.ra, 'reparent'):
+ if ra is None or not util.safehasattr(svn.ra, 'reparent'):
self.client = svn.client.create_context(self.pool)
ab = _create_auth_baton(self.pool)
if False:
--- a/hgext/inotify/__init__.py Tue Jul 26 21:30:12 2011 +0200
+++ b/hgext/inotify/__init__.py Thu Jul 28 14:20:06 2011 -0500
@@ -11,6 +11,7 @@
# todo: socket permissions
from mercurial.i18n import _
+from mercurial import util
import server
from client import client, QueryFailed
@@ -31,7 +32,7 @@
ui.write((' %s/\n') % path)
def reposetup(ui, repo):
- if not hasattr(repo, 'dirstate'):
+ if not util.safehasattr(repo, 'dirstate'):
return
class inotifydirstate(repo.dirstate.__class__):
--- a/hgext/mq.py Tue Jul 26 21:30:12 2011 +0200
+++ b/hgext/mq.py Thu Jul 28 14:20:06 2011 -0500
@@ -938,7 +938,7 @@
p.write("# User " + user + "\n")
if date:
p.write("# Date %s %s\n\n" % date)
- if hasattr(msg, '__call__'):
+ if util.safehasattr(msg, '__call__'):
msg = msg()
commitmsg = msg and msg or ("[mq]: %s" % patchfn)
n = repo.commit(commitmsg, user, date, match=match, force=True)
--- a/hgext/pager.py Tue Jul 26 21:30:12 2011 +0200
+++ b/hgext/pager.py Thu Jul 28 14:20:06 2011 -0500
@@ -58,7 +58,7 @@
from mercurial.i18n import _
def _runpager(p):
- if not hasattr(os, 'fork'):
+ if not util.safehasattr(os, 'fork'):
sys.stdout = util.popen(p, 'wb')
if util.isatty(sys.stderr):
sys.stderr = sys.stdout
--- a/hgext/relink.py Tue Jul 26 21:30:12 2011 +0200
+++ b/hgext/relink.py Thu Jul 28 14:20:06 2011 -0500
@@ -36,7 +36,8 @@
command is running. (Both repositories will be locked against
writes.)
"""
- if not hasattr(util, 'samefile') or not hasattr(util, 'samedevice'):
+ if (not util.safehasattr(util, 'samefile') or
+ not util.safehasattr(util, 'samedevice')):
raise util.Abort(_('hardlinks are not supported on this system'))
src = hg.repository(ui, ui.expandpath(origin or 'default-relink',
origin or 'default'))
--- a/mercurial/bookmarks.py Tue Jul 26 21:30:12 2011 +0200
+++ b/mercurial/bookmarks.py Thu Jul 28 14:20:06 2011 -0500
@@ -151,11 +151,10 @@
def listbookmarks(repo):
# We may try to list bookmarks on a repo type that does not
# support it (e.g., statichttprepository).
- if not hasattr(repo, '_bookmarks'):
- return {}
+ marks = getattr(repo, '_bookmarks', {})
d = {}
- for k, v in repo._bookmarks.iteritems():
+ for k, v in marks.iteritems():
d[k] = hex(v)
return d
--- a/mercurial/byterange.py Tue Jul 26 21:30:12 2011 +0200
+++ b/mercurial/byterange.py Thu Jul 28 14:20:06 2011 -0500
@@ -103,9 +103,7 @@
"""This effectively allows us to wrap at the instance level.
Any attribute not found in _this_ object will be searched for
in self.fo. This includes methods."""
- if hasattr(self.fo, name):
- return getattr(self.fo, name)
- raise AttributeError(name)
+ return getattr(self.fo, name)
def tell(self):
"""Return the position within the range.
@@ -170,10 +168,8 @@
offset is relative to the current position (self.realpos).
"""
assert offset >= 0
- if not hasattr(self.fo, 'seek'):
- self._poor_mans_seek(offset)
- else:
- self.fo.seek(self.realpos + offset)
+ seek = getattr(self.fo, 'seek', self._poor_mans_seek)
+ seek(self.realpos + offset)
self.realpos += offset
def _poor_mans_seek(self, offset):
--- a/mercurial/cmdutil.py Tue Jul 26 21:30:12 2011 +0200
+++ b/mercurial/cmdutil.py Thu Jul 28 14:20:06 2011 -0500
@@ -161,7 +161,7 @@
if not pat or pat == '-':
fp = writable and repo.ui.fout or repo.ui.fin
- if hasattr(fp, 'fileno'):
+ if util.safehasattr(fp, 'fileno'):
return os.fdopen(os.dup(fp.fileno()), mode)
else:
# if this fp can't be duped properly, return
@@ -177,9 +177,9 @@
return getattr(self.f, attr)
return wrappedfileobj(fp)
- if hasattr(pat, 'write') and writable:
+ if util.safehasattr(pat, 'write') and writable:
return pat
- if hasattr(pat, 'read') and 'r' in mode:
+ if util.safehasattr(pat, 'read') and 'r' in mode:
return pat
return open(makefilename(repo, pat, node, total, seqno, revwidth,
pathname),
@@ -520,7 +520,7 @@
revwidth=revwidth, mode='ab')
if fp != template:
shouldclose = True
- if fp != sys.stdout and hasattr(fp, 'name'):
+ if fp != sys.stdout and util.safehasattr(fp, 'name'):
repo.ui.note("%s\n" % fp.name)
fp.write("# HG changeset patch\n")
--- a/mercurial/commands.py Tue Jul 26 21:30:12 2011 +0200
+++ b/mercurial/commands.py Thu Jul 28 14:20:06 2011 -0500
@@ -1659,8 +1659,9 @@
def debugignore(ui, repo, *values, **opts):
"""display the combined ignore pattern"""
ignore = repo.dirstate._ignore
- if hasattr(ignore, 'includepat'):
- ui.write("%s\n" % ignore.includepat)
+ includepat = getattr(ignore, 'includepat', None)
+ if includepat is not None:
+ ui.write("%s\n" % includepat)
else:
raise util.Abort(_("no ignore patterns found"))
@@ -2647,7 +2648,7 @@
doc = gettext(entry[0].__doc__)
if not doc:
doc = _("(no help text available)")
- if hasattr(entry[0], 'definition'): # aliased command
+ if util.safehasattr(entry[0], 'definition'): # aliased command
if entry[0].definition.startswith('!'): # shell alias
doc = _('shell alias for::\n\n %s') % entry[0].definition[1:]
else:
@@ -2732,7 +2733,7 @@
# description
if not doc:
doc = _("(no help text available)")
- if hasattr(doc, '__call__'):
+ if util.safehasattr(doc, '__call__'):
doc = doc()
ui.write("%s\n\n" % header)
--- a/mercurial/demandimport.py Tue Jul 26 21:30:12 2011 +0200
+++ b/mercurial/demandimport.py Thu Jul 28 14:20:06 2011 -0500
@@ -27,6 +27,8 @@
import __builtin__
_origimport = __import__
+nothing = object()
+
class _demandmod(object):
"""module demand-loader and proxy"""
def __init__(self, name, globals, locals):
@@ -50,7 +52,7 @@
h, t = p, None
if '.' in p:
h, t = p.split('.', 1)
- if not hasattr(mod, h):
+ if getattr(mod, h, nothing) is nothing:
setattr(mod, h, _demandmod(p, mod.__dict__, mod.__dict__))
elif t:
subload(getattr(mod, h), t)
@@ -109,12 +111,12 @@
mod = _origimport(name, globals, locals)
# recurse down the module chain
for comp in name.split('.')[1:]:
- if not hasattr(mod, comp):
+ if getattr(mod, comp, nothing) is nothing:
setattr(mod, comp, _demandmod(comp, mod.__dict__, mod.__dict__))
mod = getattr(mod, comp)
for x in fromlist:
# set requested submodules for demand load
- if not hasattr(mod, x):
+ if getattr(mod, x, nothing) is nothing:
setattr(mod, x, _demandmod(x, mod.__dict__, locals))
return mod
@@ -137,6 +139,8 @@
# raise ImportError if x not defined
'__main__',
'_ssl', # conditional imports in the stdlib, issue1964
+ 'rfc822',
+ 'mimetools',
]
def enable():
@@ -146,4 +150,3 @@
def disable():
"disable global demand-loading of modules"
__builtin__.__import__ = _origimport
-
--- a/mercurial/dispatch.py Tue Jul 26 21:30:12 2011 +0200
+++ b/mercurial/dispatch.py Thu Jul 28 14:20:06 2011 -0500
@@ -159,16 +159,16 @@
elif m in "zlib".split():
ui.warn(_("(is your Python install correct?)\n"))
except IOError, inst:
- if hasattr(inst, "code"):
+ if util.safehasattr(inst, "code"):
ui.warn(_("abort: %s\n") % inst)
- elif hasattr(inst, "reason"):
+ elif util.safehasattr(inst, "reason"):
try: # usually it is in the form (errno, strerror)
reason = inst.reason.args[1]
except (AttributeError, IndexError):
# it might be anything, for example a string
reason = inst.reason
ui.warn(_("abort: error: %s\n") % reason)
- elif hasattr(inst, "args") and inst.args[0] == errno.EPIPE:
+ elif util.safehasattr(inst, "args") and inst.args[0] == errno.EPIPE:
if ui.debugflag:
ui.warn(_("broken pipe\n"))
elif getattr(inst, "strerror", None):
@@ -338,7 +338,7 @@
ui.debug("alias '%s' shadows command '%s'\n" %
(self.name, self.cmdname))
- if hasattr(self, 'shell'):
+ if util.safehasattr(self, 'shell'):
return self.fn(ui, *args, **opts)
else:
try:
@@ -506,7 +506,7 @@
cmd = aliases[0]
fn = entry[0]
- if cmd and hasattr(fn, 'shell'):
+ if cmd and util.safehasattr(fn, 'shell'):
d = lambda: fn(ui, *args[1:])
return lambda: runcommand(lui, None, cmd, args[:1], ui, options, d, [], {})
--- a/mercurial/encoding.py Tue Jul 26 21:30:12 2011 +0200
+++ b/mercurial/encoding.py Thu Jul 28 14:20:06 2011 -0500
@@ -140,12 +140,12 @@
def colwidth(s):
"Find the column width of a UTF-8 string for display"
d = s.decode(encoding, 'replace')
- if hasattr(unicodedata, 'east_asian_width'):
+ eaw = getattr(unicodedata, 'east_asian_width', None)
+ if eaw is not None:
wide = "WF"
if ambiguous == "wide":
wide = "WFA"
- w = unicodedata.east_asian_width
- return sum([w(c) in wide and 2 or 1 for c in d])
+ return sum([eaw(c) in wide and 2 or 1 for c in d])
return len(d)
def lower(s):
--- a/mercurial/extensions.py Tue Jul 26 21:30:12 2011 +0200
+++ b/mercurial/extensions.py Thu Jul 28 14:20:06 2011 -0500
@@ -124,7 +124,7 @@
where orig is the original (wrapped) function, and *args, **kwargs
are the arguments passed to it.
'''
- assert hasattr(wrapper, '__call__')
+ assert util.safehasattr(wrapper, '__call__')
aliases, entry = cmdutil.findcmd(command, table)
for alias, e in table.iteritems():
if e is entry:
@@ -177,12 +177,12 @@
your end users, you should play nicely with others by using the
subclass trick.
'''
- assert hasattr(wrapper, '__call__')
+ assert util.safehasattr(wrapper, '__call__')
def wrap(*args, **kwargs):
return wrapper(origfn, *args, **kwargs)
origfn = getattr(container, funcname)
- assert hasattr(origfn, '__call__')
+ assert util.safehasattr(origfn, '__call__')
setattr(container, funcname, wrap)
return origfn
--- a/mercurial/fancyopts.py Tue Jul 26 21:30:12 2011 +0200
+++ b/mercurial/fancyopts.py Thu Jul 28 14:20:06 2011 -0500
@@ -75,7 +75,7 @@
# copy defaults to state
if isinstance(default, list):
state[name] = default[:]
- elif hasattr(default, '__call__'):
+ elif getattr(default, '__call__', False):
state[name] = None
else:
state[name] = default
--- a/mercurial/help.py Tue Jul 26 21:30:12 2011 +0200
+++ b/mercurial/help.py Thu Jul 28 14:20:06 2011 -0500
@@ -31,7 +31,7 @@
"""Return a delayed loader for help/topic.txt."""
def loader():
- if hasattr(sys, 'frozen'):
+ if util.mainfrozen():
module = sys.executable
else:
module = __file__
--- a/mercurial/hg.py Tue Jul 26 21:30:12 2011 +0200
+++ b/mercurial/hg.py Thu Jul 28 14:20:06 2011 -0500
@@ -537,7 +537,7 @@
def remoteui(src, opts):
'build a remote ui from ui or repo and opts'
- if hasattr(src, 'baseui'): # looks like a repository
+ if util.safehasattr(src, 'baseui'): # looks like a repository
dst = src.baseui.copy() # drop repo-specific config
src = src.ui # copy target options from repo
else: # assume it's a global ui object
--- a/mercurial/hgweb/hgweb_mod.py Tue Jul 26 21:30:12 2011 +0200
+++ b/mercurial/hgweb/hgweb_mod.py Thu Jul 28 14:20:06 2011 -0500
@@ -7,7 +7,7 @@
# GNU General Public License version 2 or any later version.
import os
-from mercurial import ui, hg, hook, error, encoding, templater
+from mercurial import ui, hg, hook, error, encoding, templater, util
from common import get_stat, ErrorResponse, permhooks, caching
from common import HTTP_OK, HTTP_NOT_MODIFIED, HTTP_BAD_REQUEST
from common import HTTP_NOT_FOUND, HTTP_SERVER_ERROR
@@ -147,7 +147,7 @@
cmd = cmd[style + 1:]
# avoid accepting e.g. style parameter as command
- if hasattr(webcommands, cmd):
+ if util.safehasattr(webcommands, cmd):
req.form['cmd'] = [cmd]
else:
cmd = ''
--- a/mercurial/hgweb/request.py Tue Jul 26 21:30:12 2011 +0200
+++ b/mercurial/hgweb/request.py Thu Jul 28 14:20:06 2011 -0500
@@ -101,7 +101,7 @@
self.headers = []
def write(self, thing):
- if hasattr(thing, "__iter__"):
+ if util.safehasattr(thing, "__iter__"):
for part in thing:
self.write(part)
else:
--- a/mercurial/hgweb/server.py Tue Jul 26 21:30:12 2011 +0200
+++ b/mercurial/hgweb/server.py Thu Jul 28 14:20:06 2011 -0500
@@ -248,7 +248,7 @@
from threading import activeCount
_mixin = SocketServer.ThreadingMixIn
except ImportError:
- if hasattr(os, "fork"):
+ if util.safehasattr(os, "fork"):
_mixin = SocketServer.ForkingMixIn
else:
class _mixin(object):
--- a/mercurial/hgweb/webutil.py Tue Jul 26 21:30:12 2011 +0200
+++ b/mercurial/hgweb/webutil.py Thu Jul 28 14:20:06 2011 -0500
@@ -72,7 +72,7 @@
d['date'] = s.date()
d['description'] = s.description()
d['branch'] = s.branch()
- if hasattr(s, 'path'):
+ if util.safehasattr(s, 'path'):
d['file'] = s.path()
yield d
--- a/mercurial/hgweb/wsgicgi.py Tue Jul 26 21:30:12 2011 +0200
+++ b/mercurial/hgweb/wsgicgi.py Thu Jul 28 14:20:06 2011 -0500
@@ -78,5 +78,4 @@
for chunk in content:
write(chunk)
finally:
- if hasattr(content, 'close'):
- content.close()
+ getattr(content, 'close', lambda : None)()
--- a/mercurial/hook.py Tue Jul 26 21:30:12 2011 +0200
+++ b/mercurial/hook.py Thu Jul 28 14:20:06 2011 -0500
@@ -21,14 +21,14 @@
ui.note(_("calling hook %s: %s\n") % (hname, funcname))
obj = funcname
- if not hasattr(obj, '__call__'):
+ if not util.safehasattr(obj, '__call__'):
d = funcname.rfind('.')
if d == -1:
raise util.Abort(_('%s hook is invalid ("%s" not in '
'a module)') % (hname, funcname))
modname = funcname[:d]
oldpaths = sys.path
- if hasattr(sys, "frozen"):
+ if util.mainfrozen():
# binary installs require sys.path manipulation
modpath, modfile = os.path.split(modname)
if modpath and modfile:
@@ -60,7 +60,7 @@
raise util.Abort(_('%s hook is invalid '
'("%s" is not defined)') %
(hname, funcname))
- if not hasattr(obj, '__call__'):
+ if not util.safehasattr(obj, '__call__'):
raise util.Abort(_('%s hook is invalid '
'("%s" is not callable)') %
(hname, funcname))
@@ -99,7 +99,7 @@
env = {}
for k, v in args.iteritems():
- if hasattr(v, '__call__'):
+ if util.safehasattr(v, '__call__'):
v = v()
if isinstance(v, dict):
# make the dictionary element order stable across Python
@@ -145,7 +145,7 @@
for hname, cmd in ui.configitems('hooks'):
if hname.split('.')[0] != name or not cmd:
continue
- if hasattr(cmd, '__call__'):
+ if util.safehasattr(cmd, '__call__'):
r = _pythonhook(ui, repo, name, hname, cmd, args, throw) or r
elif cmd.startswith('python:'):
if cmd.count(':') >= 2:
--- a/mercurial/httprepo.py Tue Jul 26 21:30:12 2011 +0200
+++ b/mercurial/httprepo.py Thu Jul 28 14:20:06 2011 -0500
@@ -44,8 +44,7 @@
def __del__(self):
for h in self.urlopener.handlers:
h.close()
- if hasattr(h, "close_all"):
- h.close_all()
+ getattr(h, "close_all", lambda : None)()
def url(self):
return self.path
--- a/mercurial/i18n.py Tue Jul 26 21:30:12 2011 +0200
+++ b/mercurial/i18n.py Thu Jul 28 14:20:06 2011 -0500
@@ -9,7 +9,7 @@
import gettext, sys, os
# modelled after templater.templatepath:
-if hasattr(sys, 'frozen'):
+if getattr(sys, 'frozen', None) is not None:
module = sys.executable
else:
module = __file__
@@ -61,4 +61,3 @@
_ = lambda message: message
else:
_ = gettext
-
--- a/mercurial/keepalive.py Tue Jul 26 21:30:12 2011 +0200
+++ b/mercurial/keepalive.py Thu Jul 28 14:20:06 2011 -0500
@@ -547,13 +547,14 @@
print "send:", repr(str)
try:
blocksize = 8192
- if hasattr(str,'read') :
+ read = getattr(str, 'read', None)
+ if read is not None:
if self.debuglevel > 0:
print "sendIng a read()able"
- data = str.read(blocksize)
+ data = read(blocksize)
while data:
self.sock.sendall(data)
- data = str.read(blocksize)
+ data = read(blocksize)
else:
self.sock.sendall(str)
except socket.error, v:
--- a/mercurial/lsprof.py Tue Jul 26 21:30:12 2011 +0200
+++ b/mercurial/lsprof.py Thu Jul 28 14:20:06 2011 -0500
@@ -86,9 +86,7 @@
for k, v in list(sys.modules.iteritems()):
if v is None:
continue
- if not hasattr(v, '__file__'):
- continue
- if not isinstance(v.__file__, str):
+ if not isinstance(getattr(v, '__file__', None), str):
continue
if v.__file__.startswith(code.co_filename):
mname = _fn2mod[code.co_filename] = k
--- a/mercurial/mail.py Tue Jul 26 21:30:12 2011 +0200
+++ b/mercurial/mail.py Thu Jul 28 14:20:06 2011 -0500
@@ -37,7 +37,7 @@
# backward compatible: when tls = true, we use starttls.
starttls = tls == 'starttls' or util.parsebool(tls)
smtps = tls == 'smtps'
- if (starttls or smtps) and not hasattr(socket, 'ssl'):
+ if (starttls or smtps) and not util.safehasattr(socket, 'ssl'):
raise util.Abort(_("can't use TLS: Python SSL support not installed"))
if smtps:
ui.note(_('(using smtps)\n'))
--- a/mercurial/patch.py Tue Jul 26 21:30:12 2011 +0200
+++ b/mercurial/patch.py Thu Jul 28 14:20:06 2011 -0500
@@ -126,7 +126,7 @@
mimeheaders = ['content-type']
- if not hasattr(stream, 'next'):
+ if not util.safehasattr(stream, 'next'):
# http responses, for example, have readline but not next
stream = fiter(stream)
--- a/mercurial/revlog.py Tue Jul 26 21:30:12 2011 +0200
+++ b/mercurial/revlog.py Thu Jul 28 14:20:06 2011 -0500
@@ -226,9 +226,10 @@
self._nodepos = None
v = REVLOG_DEFAULT_VERSION
- if hasattr(opener, 'options'):
- if 'revlogv1' in opener.options:
- if 'generaldelta' in opener.options:
+ opts = getattr(opener, 'options', None)
+ if opts is not None:
+ if 'revlogv1' in opts:
+ if 'generaldelta' in opts:
v |= REVLOGGENERALDELTA
else:
v = 0
--- a/mercurial/scmutil.py Tue Jul 26 21:30:12 2011 +0200
+++ b/mercurial/scmutil.py Thu Jul 28 14:20:06 2011 -0500
@@ -324,10 +324,10 @@
def errhandler(err):
if err.filename == path:
raise err
- if followsym and hasattr(os.path, 'samestat'):
+ samestat = getattr(os.path, 'samestat', None)
+ if followsym and samestat is not None:
def adddir(dirlst, dirname):
match = False
- samestat = os.path.samestat
dirstat = os.stat(dirname)
for lstdirstat in dirlst:
if samestat(dirstat, lstdirstat):
--- a/mercurial/statichttprepo.py Tue Jul 26 21:30:12 2011 +0200
+++ b/mercurial/statichttprepo.py Thu Jul 28 14:20:06 2011 -0500
@@ -31,15 +31,11 @@
try:
f = self.opener.open(req)
data = f.read()
- if hasattr(f, 'getcode'):
- # python 2.6+
- code = f.getcode()
- elif hasattr(f, 'code'):
- # undocumented attribute, seems to be set in 2.4 and 2.5
- code = f.code
- else:
- # Don't know how to check, hope for the best.
- code = 206
+ # Python 2.6+ defines a getcode() function, and 2.4 and
+ # 2.5 appear to always have an undocumented code attribute
+ # set. If we can't read either of those, fall back to 206
+ # and hope for the best.
+ code = getattr(f, 'getcode', lambda : getattr(f, 'code', 206))()
except urllib2.HTTPError, inst:
num = inst.code == 404 and errno.ENOENT or None
raise IOError(num, inst)
--- a/mercurial/subrepo.py Tue Jul 26 21:30:12 2011 +0200
+++ b/mercurial/subrepo.py Thu Jul 28 14:20:06 2011 -0500
@@ -181,22 +181,22 @@
def reporelpath(repo):
"""return path to this (sub)repo as seen from outermost repo"""
parent = repo
- while hasattr(parent, '_subparent'):
+ while util.safehasattr(parent, '_subparent'):
parent = parent._subparent
return repo.root[len(parent.root)+1:]
def subrelpath(sub):
"""return path to this subrepo as seen from outermost repo"""
- if hasattr(sub, '_relpath'):
+ if util.safehasattr(sub, '_relpath'):
return sub._relpath
- if not hasattr(sub, '_repo'):
+ if not util.safehasattr(sub, '_repo'):
return sub._path
return reporelpath(sub._repo)
def _abssource(repo, push=False, abort=True):
"""return pull/push path of repo - either based on parent repo .hgsub info
or on the top repo config. Abort or return None if no source found."""
- if hasattr(repo, '_subparent'):
+ if util.safehasattr(repo, '_subparent'):
source = util.url(repo._subsource)
if source.isabs():
return str(source)
@@ -208,7 +208,7 @@
parent.path = posixpath.normpath(parent.path)
return str(parent)
else: # recursion reached top repo
- if hasattr(repo, '_subtoppath'):
+ if util.safehasattr(repo, '_subtoppath'):
return repo._subtoppath
if push and repo.ui.config('paths', 'default-push'):
return repo.ui.config('paths', 'default-push')
--- a/mercurial/templatefilters.py Tue Jul 26 21:30:12 2011 +0200
+++ b/mercurial/templatefilters.py Thu Jul 28 14:20:06 2011 -0500
@@ -188,13 +188,13 @@
return '"%s"' % jsonescape(u)
elif isinstance(obj, unicode):
return '"%s"' % jsonescape(obj)
- elif hasattr(obj, 'keys'):
+ elif util.safehasattr(obj, 'keys'):
out = []
for k, v in obj.iteritems():
s = '%s: %s' % (json(k), json(v))
out.append(s)
return '{' + ', '.join(out) + '}'
- elif hasattr(obj, '__iter__'):
+ elif util.safehasattr(obj, '__iter__'):
out = []
for i in obj:
out.append(json(i))
@@ -279,7 +279,7 @@
""":stringify: Any type. Turns the value into text by converting values into
text and concatenating them.
"""
- if hasattr(thing, '__iter__') and not isinstance(thing, str):
+ if util.safehasattr(thing, '__iter__') and not isinstance(thing, str):
return "".join([stringify(t) for t in thing if t is not None])
return str(thing)
--- a/mercurial/templater.py Tue Jul 26 21:30:12 2011 +0200
+++ b/mercurial/templater.py Thu Jul 28 14:20:06 2011 -0500
@@ -135,7 +135,7 @@
v = mapping.get(key)
if v is None:
v = context._defaults.get(key, '')
- if hasattr(v, '__call__'):
+ if util.safehasattr(v, '__call__'):
return v(**mapping)
return v
@@ -203,14 +203,14 @@
'''yield a single stream from a possibly nested set of iterators'''
if isinstance(thing, str):
yield thing
- elif not hasattr(thing, '__iter__'):
+ elif not util.safehasattr(thing, '__iter__'):
if thing is not None:
yield str(thing)
else:
for i in thing:
if isinstance(i, str):
yield i
- elif not hasattr(i, '__iter__'):
+ elif not util.safehasattr(i, '__iter__'):
if i is not None:
yield str(i)
elif i is not None:
@@ -341,7 +341,7 @@
normpaths = []
# executable version (py2exe) doesn't support __file__
- if hasattr(sys, 'frozen'):
+ if util.mainfrozen():
module = sys.executable
else:
module = __file__
--- a/mercurial/url.py Tue Jul 26 21:30:12 2011 +0200
+++ b/mercurial/url.py Thu Jul 28 14:20:06 2011 -0500
@@ -129,7 +129,7 @@
orgsend(self, data)
return _sendfile
-has_https = hasattr(urllib2, 'HTTPSHandler')
+has_https = util.safehasattr(urllib2, 'HTTPSHandler')
if has_https:
try:
_create_connection = socket.create_connection
@@ -186,8 +186,8 @@
# general transaction handler to support different ways to handle
# HTTPS proxying before and after Python 2.6.3.
def _generic_start_transaction(handler, h, req):
- if hasattr(req, '_tunnel_host') and req._tunnel_host:
- tunnel_host = req._tunnel_host
+ tunnel_host = getattr(req, '_tunnel_host', None)
+ if tunnel_host:
if tunnel_host[:7] not in ['http://', 'https:/']:
tunnel_host = 'https://' + tunnel_host
new_tunnel = True
--- a/mercurial/util.py Tue Jul 26 21:30:12 2011 +0200
+++ b/mercurial/util.py Thu Jul 28 14:20:06 2011 -0500
@@ -75,6 +75,10 @@
def sha1(s):
return _fastsha1(s)
+_notset = object()
+def safehasattr(thing, attr):
+ return getattr(thing, attr, _notset) is not _notset
+
def _fastsha1(s):
# This function will import sha1 from hashlib or sha (whichever is
# available) and overwrite itself with it on the first call.
@@ -354,8 +358,8 @@
The code supports py2exe (most common, Windows only) and tools/freeze
(portable, not much used).
"""
- return (hasattr(sys, "frozen") or # new py2exe
- hasattr(sys, "importers") or # old py2exe
+ return (safehasattr(sys, "frozen") or # new py2exe
+ safehasattr(sys, "importers") or # old py2exe
imp.is_frozen("__main__")) # tools/freeze
def hgexecutable():
@@ -779,7 +783,7 @@
self._fp.close()
def __del__(self):
- if hasattr(self, '_fp'): # constructor actually did something
+ if safehasattr(self, '_fp'): # constructor actually did something
self.close()
def makedirs(name, mode=None):
@@ -1250,8 +1254,9 @@
def handler(signum, frame):
terminated.add(os.wait())
prevhandler = None
- if hasattr(signal, 'SIGCHLD'):
- prevhandler = signal.signal(signal.SIGCHLD, handler)
+ SIGCHLD = getattr(signal, 'SIGCHLD', None)
+ if SIGCHLD is not None:
+ prevhandler = signal.signal(SIGCHLD, handler)
try:
pid = spawndetached(args)
while not condfn():
--- a/mercurial/windows.py Tue Jul 26 21:30:12 2011 +0200
+++ b/mercurial/windows.py Thu Jul 28 14:20:06 2011 -0500
@@ -99,8 +99,9 @@
def setbinary(fd):
# When run without console, pipes may expose invalid
# fileno(), usually set to -1.
- if hasattr(fd, 'fileno') and fd.fileno() >= 0:
- msvcrt.setmode(fd.fileno(), os.O_BINARY)
+ fno = getattr(fd, 'fileno', None)
+ if fno is not None and fno() >= 0:
+ msvcrt.setmode(fno(), os.O_BINARY)
def pconvert(path):
return '/'.join(path.split(os.sep))
--- a/mercurial/wireproto.py Tue Jul 26 21:30:12 2011 +0200
+++ b/mercurial/wireproto.py Thu Jul 28 14:20:06 2011 -0500
@@ -17,7 +17,7 @@
class future(object):
'''placeholder for a value to be set later'''
def set(self, value):
- if hasattr(self, 'value'):
+ if util.safehasattr(self, 'value'):
raise error.RepoError("future is already set")
self.value = value
@@ -58,8 +58,9 @@
req, rsp = [], []
for name, args, opts, resref in self.calls:
mtd = getattr(self.remote, name)
- if hasattr(mtd, 'batchable'):
- batchable = getattr(mtd, 'batchable')(mtd.im_self, *args, **opts)
+ batchablefn = getattr(mtd, 'batchable', None)
+ if batchablefn is not None:
+ batchable = batchablefn(mtd.im_self, *args, **opts)
encargsorres, encresref = batchable.next()
if encresref:
req.append((name, encargsorres,))
--- a/setup.py Tue Jul 26 21:30:12 2011 +0200
+++ b/setup.py Thu Jul 28 14:20:06 2011 -0500
@@ -5,7 +5,7 @@
# 'python setup.py --help' for more options
import sys, platform
-if not hasattr(sys, 'version_info') or sys.version_info < (2, 4, 0, 'final'):
+if getattr(sys, 'version_info', (0, 0, 0)) < (2, 4, 0, 'final'):
raise SystemExit("Mercurial requires Python 2.4 or later.")
if sys.version_info[0] >= 3:
--- a/tests/run-tests.py Tue Jul 26 21:30:12 2011 +0200
+++ b/tests/run-tests.py Thu Jul 28 14:20:06 2011 -0500
@@ -340,10 +340,7 @@
"""Terminate subprocess (with fallback for Python versions < 2.6)"""
vlog('# Terminating process %d' % proc.pid)
try:
- if hasattr(proc, 'terminate'):
- proc.terminate()
- else:
- os.kill(proc.pid, signal.SIGTERM)
+ getattr(proc, 'terminate', lambda : os.kill(proc.pid, signal.SIGTERM))()
except OSError:
pass
--- a/tests/sitecustomize.py Tue Jul 26 21:30:12 2011 +0200
+++ b/tests/sitecustomize.py Thu Jul 28 14:20:06 2011 -0500
@@ -1,6 +1,5 @@
try:
import coverage
- if hasattr(coverage, 'process_startup'):
- coverage.process_startup()
+ getattr(coverage, 'process_startup', lambda: None)()
except ImportError:
pass
--- a/tests/test-symlink-os-yes-fs-no.py Tue Jul 26 21:30:12 2011 +0200
+++ b/tests/test-symlink-os-yes-fs-no.py Thu Jul 28 14:20:06 2011 -0500
@@ -5,7 +5,7 @@
BUNDLEPATH = os.path.join(TESTDIR, 'bundles', 'test-no-symlinks.hg')
# only makes sense to test on os which supports symlinks
-if not hasattr(os, "symlink"):
+if not getattr(os, "symlink", False):
sys.exit(80) # SKIPPED_STATUS defined in run-tests.py
# clone with symlink support
--- a/tests/test-walkrepo.py Tue Jul 26 21:30:12 2011 +0200
+++ b/tests/test-walkrepo.py Thu Jul 28 14:20:06 2011 -0500
@@ -5,7 +5,7 @@
from os.path import join as pjoin
u = ui.ui()
-sym = hasattr(os, 'symlink') and hasattr(os.path, 'samestat')
+sym = getattr(os, 'symlink', False) and getattr(os.path, 'samestat', False)
hg.repository(u, 'top1', create=1)
mkdir('subdir')
--- a/tests/tinyproxy.py Tue Jul 26 21:30:12 2011 +0200
+++ b/tests/tinyproxy.py Thu Jul 28 14:20:06 2011 -0500
@@ -23,7 +23,8 @@
def handle(self):
(ip, port) = self.client_address
- if hasattr(self, 'allowed_clients') and ip not in self.allowed_clients:
+ allowed = getattr(self, 'allowed_clients', None)
+ if allowed is not None and ip not in allowed:
self.raw_requestline = self.rfile.readline()
if self.parse_request():
self.send_error(403)