PY-27650 Create a pip package consistent with PyCharm updates

This commit is contained in:
Elizaveta Shashkova
2018-12-04 15:18:32 +03:00
parent c99d11beca
commit 2ad70f910d
21 changed files with 935 additions and 1016 deletions
@@ -3,10 +3,10 @@
# NOTE: This module must remain compatible with Python 2.3, as it is shared
# by setuptools for distribution with Python 2.3 and up.
import imp
import os
import os.path
import sys
import imp
import os.path
from types import ModuleType
__all__ = [
@@ -540,7 +540,7 @@ def extend_path(path, name):
if os.path.isfile(pkgfile):
try:
f = open(pkgfile)
except IOError, msg:
except IOError as msg:
sys.stderr.write("Can't open %s: %s\n" %
(pkgfile, msg))
else:
+4
View File
@@ -0,0 +1,4 @@
include *.rst *.txt *.md LICENSE VERSION *.pyx
recursive-include pydevd_attach_to_process *.py *.dll *.so *.dylib *.txt *.c *.h *.bat Makefile *.sh *.pyx
recursive-include _pydevd_bundle *.pyx
recursive-include build_tools *.py
+4 -9
View File
@@ -9,27 +9,22 @@ In general, the debugger backend should **NOT** be installed separately if you'r
bundles it (such as PyDev or PyCharm).
It is however available in PyPi so that it can be installed for doing remote debugging with `pip` -- so, when
debugging a process which runs in another machine, it's possible to `pip install pydevd` and in the code use
`pydevd.settrace(host='10.1.1.1')` to connect the debugger backend to the debugger UI running in the IDE
debugging a process which runs in another machine, it's possible to `pip install pydevd-pycharm` and in the code use
`pydevd_pycharm.settrace(host='10.1.1.1')` to connect the debugger backend to the debugger UI running in the IDE
(whereas previously the sources had to be manually copied from the IDE installation).
It should be compatible with Python 2.4 onwards (as well as Jython 2.2.1, IronPython and PyPy -- and
It should be compatible with Python 2.6 onwards (as well as Jython 2.7, IronPython and PyPy -- and
any other variant which properly supports the Python structure for debuggers -- i.e.: sys.settrace/threading.settrace).
Recent versions contain speedup modules using Cython, which are generated with a few changes in the regular files
to `cythonize` the files. To update and compile the cython sources (and generate some other auto-generated files),
`build_tools/build.py` should be run -- note that the resulting .pyx and .c files should be commited.
To see performance changes, see:
https://www.speedtin.com/reports/7_pydevd_cython (performance results with cython).
https://www.speedtin.com/reports/8_pydevd_pure_python (performance results without cython).
To generate a distribution with the precompiled binaries for the IDE, `build_binaries_windows.py` should be run (
note that the environments must be pre-created as specified in that file).
To generate a distribution to upload to PyPi, `python setup.py sdist bdist_wheel` should be run for each python version
which should have a wheel and afterwards `twine upload -s dist/pydevd-*` shoud be run to actually upload the contents
which should have a wheel and afterwards `twine upload -s dist/pydevd-*` should be run to actually upload the contents
to PyPi.
Travis (Linux CI):
@@ -596,7 +596,7 @@ def test(HandlerClass = BaseHTTPRequestHandler,
httpd = ServerClass(server_address, HandlerClass)
sa = httpd.socket.getsockname()
print ("Serving HTTP on", sa[0], "port", sa[1], "...")
print("Serving HTTP on", sa[0], "port", sa[1], "...")
httpd.serve_forever()
@@ -260,7 +260,7 @@ class SimpleXMLRPCDispatcher:
response = (response,)
response = xmlrpclib.dumps(response, methodresponse=1,
allow_none=self.allow_none, encoding=self.encoding)
except Fault, fault:
except Fault as fault:
response = xmlrpclib.dumps(fault, allow_none=self.allow_none,
encoding=self.encoding)
except:
@@ -363,7 +363,7 @@ class SimpleXMLRPCDispatcher:
# XXX A marshalling error in any response will fail the entire
# multicall. If someone cares they should fix this.
results.append([self._dispatch(method_name, params)])
except Fault, fault:
except Fault as fault:
results.append(
{'faultCode' : fault.faultCode,
'faultString' : fault.faultString}
@@ -336,12 +336,12 @@ class BaseServer:
The default is to print a traceback and continue.
"""
print '-'*40
print 'Exception happened during processing of request from',
print client_address
print('-'*40)
print('Exception happened during processing of request from')
print(client_address)
import traceback
traceback.print_exc() # XXX But this goes to stderr!
print '-'*40
print('-'*40)
class TCPServer(BaseServer):
@@ -528,7 +528,7 @@ class ForkingMixIn:
if not pid: continue
try:
self.active_children.remove(pid)
except ValueError, e:
except ValueError as e:
raise ValueError('%s. x=%d and list=%r' % (e.message, pid,
self.active_children))
+454 -183
View File
@@ -1,3 +1,4 @@
# -*- coding: iso-8859-1 -*-
"""Get useful information from live Python objects.
This module encapsulates the interface provided by the internal special
@@ -6,8 +7,9 @@ It also provides some help for examining source code and class layout.
Here are some of the useful functions provided by this module:
ismodule(), isclass(), ismethod(), isfunction(), istraceback(),
isframe(), iscode(), isbuiltin(), isroutine() - check object types
ismodule(), isclass(), ismethod(), isfunction(), isgeneratorfunction(),
isgenerator(), istraceback(), isframe(), iscode(), isbuiltin(),
isroutine() - check object types
getmembers() - get members of an object that satisfy a given condition
getfile(), getsourcefile(), getsource() - find an object's source code
@@ -15,7 +17,7 @@ Here are some of the useful functions provided by this module:
getmodule() - determine the module that an object came from
getclasstree() - arrange classes so as to represent their hierarchy
getargspec(), getargvalues() - get info about function arguments
getargspec(), getargvalues(), getcallargs() - get info about function arguments
formatargspec(), formatargvalues() - format an argument spec
getouterframes(), getinnerframes() - get info about frames
currentframe() - get the current stack frame
@@ -27,7 +29,23 @@ Here are some of the useful functions provided by this module:
__author__ = 'Ka-Ping Yee <ping@lfw.org>'
__date__ = '1 Jan 2001'
import sys, os, types, string, re, imp, tokenize
import sys
import os
import types
import string
import re
import dis
import imp
import tokenize
import linecache
from operator import attrgetter
from collections import namedtuple
# These constants are from Include/code.h.
CO_OPTIMIZED, CO_NEWLOCALS, CO_VARARGS, CO_VARKEYWORDS = 0x1, 0x2, 0x4, 0x8
CO_NESTED, CO_GENERATOR, CO_NOFREE = 0x10, 0x20, 0x40
# See Include/object.h
TPFLAGS_IS_ABSTRACT = 1 << 20
# ----------------------------------------------------------- type-checking
def ismodule(object):
@@ -44,7 +62,7 @@ def isclass(object):
Class objects provide these attributes:
__doc__ documentation string
__module__ name of module in which this class was defined"""
return isinstance(object, types.ClassType) or hasattr(object, '__bases__')
return isinstance(object, (type, types.ClassType))
def ismethod(object):
"""Return true if the object is an instance method.
@@ -77,6 +95,50 @@ def ismethoddescriptor(object):
and not isfunction(object)
and not isclass(object))
def isdatadescriptor(object):
"""Return true if the object is a data descriptor.
Data descriptors have both a __get__ and a __set__ attribute. Examples are
properties (defined in Python) and getsets and members (defined in C).
Typically, data descriptors will also have __name__ and __doc__ attributes
(properties, getsets, and members have both of these attributes), but this
is not guaranteed."""
return (hasattr(object, "__set__") and hasattr(object, "__get__"))
if hasattr(types, 'MemberDescriptorType'):
# CPython and equivalent
def ismemberdescriptor(object):
"""Return true if the object is a member descriptor.
Member descriptors are specialized descriptors defined in extension
modules."""
return isinstance(object, types.MemberDescriptorType)
else:
# Other implementations
def ismemberdescriptor(object):
"""Return true if the object is a member descriptor.
Member descriptors are specialized descriptors defined in extension
modules."""
return False
if hasattr(types, 'GetSetDescriptorType'):
# CPython and equivalent
def isgetsetdescriptor(object):
"""Return true if the object is a getset descriptor.
getset descriptors are specialized descriptors defined in extension
modules."""
return isinstance(object, types.GetSetDescriptorType)
else:
# Other implementations
def isgetsetdescriptor(object):
"""Return true if the object is a getset descriptor.
getset descriptors are specialized descriptors defined in extension
modules."""
return False
def isfunction(object):
"""Return true if the object is a user-defined function.
@@ -90,6 +152,32 @@ def isfunction(object):
func_name (same as __name__)"""
return isinstance(object, types.FunctionType)
def isgeneratorfunction(object):
"""Return true if the object is a user-defined generator function.
Generator function objects provides same attributes as functions.
See help(isfunction) for attributes listing."""
return bool((isfunction(object) or ismethod(object)) and
object.func_code.co_flags & CO_GENERATOR)
def isgenerator(object):
"""Return true if the object is a generator.
Generator objects provide these attributes:
__iter__ defined to support iteration over container
close raises a new GeneratorExit exception inside the
generator to terminate the iteration
gi_code code object
gi_frame frame object or possibly None once the generator has
been exhausted
gi_running set to 1 when generator is executing, 0 otherwise
next return the next item from the container
send resumes the generator and "sends" a value that becomes
the result of the current yield-expression
throw used to raise an exception inside the generator"""
return isinstance(object, types.GeneratorType)
def istraceback(object):
"""Return true if the object is a traceback.
@@ -152,17 +240,26 @@ def isroutine(object):
or ismethod(object)
or ismethoddescriptor(object))
def isabstract(object):
"""Return true if the object is an abstract base class (ABC)."""
return bool(isinstance(object, type) and object.__flags__ & TPFLAGS_IS_ABSTRACT)
def getmembers(object, predicate=None):
"""Return all members of an object as (name, value) pairs sorted by name.
Optionally, only return members that satisfy a given predicate."""
results = []
for key in dir(object):
value = getattr(object, key)
try:
value = getattr(object, key)
except AttributeError:
continue
if not predicate or predicate(value):
results.append((key, value))
results.sort()
return results
Attribute = namedtuple('Attribute', 'name kind defining_class object')
def classify_class_attrs(cls):
"""Return list of attribute-descriptor tuples.
@@ -191,30 +288,21 @@ def classify_class_attrs(cls):
names = dir(cls)
result = []
for name in names:
# Get the object associated with the name.
# Get the object associated with the name, and where it was defined.
# Getting an obj from the __dict__ sometimes reveals more than
# using getattr. Static and class methods are dramatic examples.
if name in cls.__dict__:
obj = cls.__dict__[name]
# Furthermore, some objects may raise an Exception when fetched with
# getattr(). This is the case with some descriptors (bug #1785).
# Thus, we only use getattr() as a last resort.
homecls = None
for base in (cls,) + mro:
if name in base.__dict__:
obj = base.__dict__[name]
homecls = base
break
else:
obj = getattr(cls, name)
# Figure out where it was defined.
homecls = getattr(obj, "__objclass__", None)
if homecls is None:
# search the dicts.
for base in mro:
if name in base.__dict__:
homecls = base
break
# Get the object again, in order to get it from the defining
# __dict__ instead of via getattr (if possible).
if homecls is not None and name in homecls.__dict__:
obj = homecls.__dict__[name]
# Also get the object via getattr.
obj_via_getattr = getattr(cls, name)
homecls = getattr(obj, "__objclass__", homecls)
# Classify the object.
if isinstance(obj, staticmethod):
@@ -223,13 +311,20 @@ def classify_class_attrs(cls):
kind = "class method"
elif isinstance(obj, property):
kind = "property"
elif (ismethod(obj_via_getattr) or
ismethoddescriptor(obj_via_getattr)):
elif ismethoddescriptor(obj):
kind = "method"
else:
elif isdatadescriptor(obj):
kind = "data"
else:
obj_via_getattr = getattr(cls, name)
if (ismethod(obj_via_getattr) or
ismethoddescriptor(obj_via_getattr)):
kind = "method"
else:
kind = "data"
obj = obj_via_getattr
result.append((name, kind, homecls, obj))
result.append(Attribute(name, kind, homecls, obj))
return result
@@ -267,22 +362,37 @@ def getdoc(object):
doc = object.__doc__
except AttributeError:
return None
if not isinstance(doc, (str, unicode)):
if not isinstance(doc, types.StringTypes):
return None
return cleandoc(doc)
def cleandoc(doc):
"""Clean up indentation from docstrings.
Any whitespace that can be uniformly removed from the second line
onwards is removed."""
try:
lines = string.split(string.expandtabs(doc), '\n')
except UnicodeError:
return None
else:
margin = None
# Find minimum indentation of any non-blank lines after first line.
margin = sys.maxint
for line in lines[1:]:
content = len(string.lstrip(line))
if not content: continue
indent = len(line) - content
if margin is None: margin = indent
else: margin = min(margin, indent)
if margin is not None:
if content:
indent = len(line) - content
margin = min(margin, indent)
# Remove indentation.
if lines:
lines[0] = lines[0].lstrip()
if margin < sys.maxint:
for i in range(1, len(lines)): lines[i] = lines[i][margin:]
# Remove any trailing or leading blank lines.
while lines and not lines[-1]:
lines.pop()
while lines and not lines[0]:
lines.pop(0)
return string.join(lines, '\n')
def getfile(object):
@@ -290,12 +400,12 @@ def getfile(object):
if ismodule(object):
if hasattr(object, '__file__'):
return object.__file__
raise TypeError, 'arg is a built-in module'
raise TypeError('{!r} is a built-in module'.format(object))
if isclass(object):
object = sys.modules.get(object.__module__)
if hasattr(object, '__file__'):
return object.__file__
raise TypeError, 'arg is a built-in class'
raise TypeError('{!r} is a built-in class'.format(object))
if ismethod(object):
object = object.im_func
if isfunction(object):
@@ -306,18 +416,21 @@ def getfile(object):
object = object.f_code
if iscode(object):
return object.co_filename
raise TypeError, 'arg is not a module, class, method, ' \
'function, traceback, frame, or code object'
raise TypeError('{!r} is not a module, class, method, '
'function, traceback, frame, or code object'.format(object))
ModuleInfo = namedtuple('ModuleInfo', 'name suffix mode module_type')
def getmoduleinfo(path):
"""Get the module name, suffix, mode, and module type for a given file."""
filename = os.path.basename(path)
suffixes = map(lambda (suffix, mode, mtype):
(-len(suffix), suffix, mode, mtype), imp.get_suffixes())
suffixes = map(lambda info:
(-len(info[0]), info[0], info[1], info[2]),
imp.get_suffixes())
suffixes.sort() # try longest suffixes first, in case they overlap
for neglen, suffix, mode, mtype in suffixes:
if filename[neglen:] == suffix:
return filename[:neglen], suffix, mode, mtype
return ModuleInfo(filename[:neglen], suffix, mode, mtype)
def getmodulename(path):
"""Return the module name for a given file, or None."""
@@ -325,9 +438,11 @@ def getmodulename(path):
if info: return info[0]
def getsourcefile(object):
"""Return the Python source file an object was defined in, if it exists."""
"""Return the filename that can be used to locate an object's source.
Return None if no way can be identified to get the source.
"""
filename = getfile(object)
if string.lower(filename[-4:]) in ['.pyc', '.pyo']:
if string.lower(filename[-4:]) in ('.pyc', '.pyo'):
filename = filename[:-4] + '.py'
for suffix, mode, kind in imp.get_suffixes():
if 'b' in mode and string.lower(filename[-len(suffix):]) == suffix:
@@ -335,39 +450,65 @@ def getsourcefile(object):
return None
if os.path.exists(filename):
return filename
# only return a non-existent filename if the module has a PEP 302 loader
if hasattr(getmodule(object, filename), '__loader__'):
return filename
# or it is in the linecache
if filename in linecache.cache:
return filename
def getabsfile(object):
def getabsfile(object, _filename=None):
"""Return an absolute path to the source or compiled file for an object.
The idea is for each object to have a unique origin, so this routine
normalizes the result as much as possible."""
return os.path.normcase(
os.path.abspath(getsourcefile(object) or getfile(object)))
if _filename is None:
_filename = getsourcefile(object) or getfile(object)
return os.path.normcase(os.path.abspath(_filename))
modulesbyfile = {}
_filesbymodname = {}
def getmodule(object):
def getmodule(object, _filename=None):
"""Return the module an object was defined in, or None if not found."""
if ismodule(object):
return object
if isclass(object):
if hasattr(object, '__module__'):
return sys.modules.get(object.__module__)
# Try the filename to modulename cache
if _filename is not None and _filename in modulesbyfile:
return sys.modules.get(modulesbyfile[_filename])
# Try the cache again with the absolute file name
try:
file = getabsfile(object)
file = getabsfile(object, _filename)
except TypeError:
return None
if modulesbyfile.has_key(file):
return sys.modules[modulesbyfile[file]]
for module in sys.modules.values():
if hasattr(module, '__file__'):
modulesbyfile[getabsfile(module)] = module.__name__
if modulesbyfile.has_key(file):
return sys.modules[modulesbyfile[file]]
if file in modulesbyfile:
return sys.modules.get(modulesbyfile[file])
# Update the filename to module name cache and check yet again
# Copy sys.modules in order to cope with changes while iterating
for modname, module in sys.modules.items():
if ismodule(module) and hasattr(module, '__file__'):
f = module.__file__
if f == _filesbymodname.get(modname, None):
# Have already mapped this module, so skip it
continue
_filesbymodname[modname] = f
f = getabsfile(module)
# Always map to the name the module knows itself by
modulesbyfile[f] = modulesbyfile[
os.path.realpath(f)] = module.__name__
if file in modulesbyfile:
return sys.modules.get(modulesbyfile[file])
# Check the main module
main = sys.modules['__main__']
if not hasattr(object, '__name__'):
return None
if hasattr(main, object.__name__):
mainobject = getattr(main, object.__name__)
if mainobject is object:
return main
# Check builtins
builtin = sys.modules['__builtin__']
if hasattr(builtin, object.__name__):
builtinobject = getattr(builtin, object.__name__)
@@ -381,22 +522,46 @@ def findsource(object):
or code object. The source code is returned as a list of all the lines
in the file and the line number indexes a line in that list. An IOError
is raised if the source code cannot be retrieved."""
try:
file = open(getsourcefile(object))
except (TypeError, IOError):
raise IOError, 'could not get source code'
lines = file.readlines()
file.close()
file = getfile(object)
sourcefile = getsourcefile(object)
if not sourcefile and file[:1] + file[-1:] != '<>':
raise IOError('source code not available')
file = sourcefile if sourcefile else file
module = getmodule(object, file)
if module:
lines = linecache.getlines(file, module.__dict__)
else:
lines = linecache.getlines(file)
if not lines:
raise IOError('could not get source code')
if ismodule(object):
return lines, 0
if isclass(object):
name = object.__name__
pat = re.compile(r'^\s*class\s*' + name + r'\b')
pat = re.compile(r'^(\s*)class\s*' + name + r'\b')
# make some effort to find the best matching class definition:
# use the one with the least indentation, which is the one
# that's most probably not inside a function definition.
candidates = []
for i in range(len(lines)):
if pat.match(lines[i]): return lines, i
else: raise IOError, 'could not find class definition'
match = pat.match(lines[i])
if match:
# if it's at toplevel, it's already the best one
if lines[i][0] == 'c':
return lines, i
# else add whitespace to candidate list
candidates.append((match.group(1), i))
if candidates:
# this will sort by whitespace, and by line number,
# less whitespace first
candidates.sort()
return lines, candidates[0][1]
else:
raise IOError('could not find class definition')
if ismethod(object):
object = object.im_func
@@ -408,25 +573,30 @@ def findsource(object):
object = object.f_code
if iscode(object):
if not hasattr(object, 'co_firstlineno'):
raise IOError, 'could not find function definition'
raise IOError('could not find function definition')
lnum = object.co_firstlineno - 1
pat = re.compile(r'^(\s*def\s)|(.*\slambda(:|\s))')
pat = re.compile(r'^(\s*def\s)|(.*(?<!\w)lambda(:|\s))|^(\s*@)')
while lnum > 0:
if pat.match(lines[lnum]): break
lnum = lnum - 1
return lines, lnum
raise IOError, 'could not find code object'
raise IOError('could not find code object')
def getcomments(object):
"""Get lines of comments immediately preceding an object's source code."""
try: lines, lnum = findsource(object)
except IOError: return None
"""Get lines of comments immediately preceding an object's source code.
Returns None when source can't be found.
"""
try:
lines, lnum = findsource(object)
except (IOError, TypeError):
return None
if ismodule(object):
# Look for a comment block at the top of the file.
start = 0
if lines and lines[0][:2] == '#!': start = 1
while start < len(lines) and string.strip(lines[start]) in ['', '#']:
while start < len(lines) and string.strip(lines[start]) in ('', '#'):
start = start + 1
if start < len(lines) and lines[start][:1] == '#':
comments = []
@@ -441,7 +611,7 @@ def getcomments(object):
indent = indentsize(lines[lnum])
end = lnum - 1
if end >= 0 and string.lstrip(lines[end])[:1] == '#' and \
indentsize(lines[end]) == indent:
indentsize(lines[end]) == indent:
comments = [string.lstrip(string.expandtabs(lines[end]))]
if end > 0:
end = end - 1
@@ -457,49 +627,57 @@ def getcomments(object):
comments[-1:] = []
return string.join(comments, '')
class ListReader:
"""Provide a readline() method to return lines from a list of strings."""
def __init__(self, lines):
self.lines = lines
self.index = 0
def readline(self):
i = self.index
if i < len(self.lines):
self.index = i + 1
return self.lines[i]
else: return ''
class EndOfBlock(Exception): pass
class BlockFinder:
"""Provide a tokeneater() method to detect the end of a code block."""
def __init__(self):
self.indent = 0
self.started = 0
self.last = 0
self.islambda = False
self.started = False
self.passline = False
self.last = 1
def tokeneater(self, type, token, (srow, scol), (erow, ecol), line):
def tokeneater(self, type, token, srow_scol, erow_ecol, line):
srow, scol = srow_scol
erow, ecol = erow_ecol
if not self.started:
if type == tokenize.NAME: self.started = 1
# look for the first "def", "class" or "lambda"
if token in ("def", "class", "lambda"):
if token == "lambda":
self.islambda = True
self.started = True
self.passline = True # skip to the end of the line
elif type == tokenize.NEWLINE:
self.passline = False # stop skipping when a NEWLINE is seen
self.last = srow
if self.islambda: # lambdas always end at the first NEWLINE
raise EndOfBlock
elif self.passline:
pass
elif type == tokenize.INDENT:
self.indent = self.indent + 1
self.passline = True
elif type == tokenize.DEDENT:
self.indent = self.indent - 1
if self.indent == 0: raise EndOfBlock, self.last
elif type == tokenize.NAME and scol == 0:
raise EndOfBlock, self.last
# the end of matching indent/dedent pairs end a block
# (note that this only works for "def"/"class" blocks,
# not e.g. for "if: else:" or "try: finally:" blocks)
if self.indent <= 0:
raise EndOfBlock
elif self.indent == 0 and type not in (tokenize.COMMENT, tokenize.NL):
# any other token on the same indentation level end the previous
# block as well, except the pseudo-tokens COMMENT and NL.
raise EndOfBlock
def getblock(lines):
"""Extract the block of code at the top of the given list of lines."""
blockfinder = BlockFinder()
try:
tokenize.tokenize(ListReader(lines).readline, BlockFinder().tokeneater)
except EndOfBlock, eob:
return lines[:eob.args[0]]
# Fooling the indent/dedent logic implies a one-line definition
return lines[:1]
tokenize.tokenize(iter(lines).next, blockfinder.tokeneater)
except (EndOfBlock, IndentationError):
pass
return lines[:blockfinder.last]
def getsourcelines(object):
"""Return a list of source lines and starting line number for an object.
@@ -527,10 +705,10 @@ def getsource(object):
def walktree(classes, children, parent):
"""Recursive helper function for getclasstree()."""
results = []
classes.sort(lambda a, b: cmp(a.__name__, b.__name__))
classes.sort(key=attrgetter('__module__', '__name__'))
for c in classes:
results.append((c, c.__bases__))
if children.has_key(c):
if c in children:
results.append(walktree(children[c], children, c))
return results
@@ -548,20 +726,20 @@ def getclasstree(classes, unique=0):
for c in classes:
if c.__bases__:
for parent in c.__bases__:
if not children.has_key(parent):
if not parent in children:
children[parent] = []
children[parent].append(c)
if c not in children[parent]:
children[parent].append(c)
if unique and parent in classes: break
elif c not in roots:
roots.append(c)
for parent in children.keys():
for parent in children:
if parent not in classes:
roots.append(parent)
return walktree(roots, children, None)
# ------------------------------------------------ argument list extraction
# These constants are from Python's compile.h.
CO_OPTIMIZED, CO_NEWLOCALS, CO_VARARGS, CO_VARKEYWORDS = 1, 2, 4, 8
Arguments = namedtuple('Arguments', 'args varargs keywords')
def getargs(co):
"""Get information about the arguments accepted by a code object.
@@ -569,7 +747,9 @@ def getargs(co):
Three things are returned: (args, varargs, varkw), where 'args' is
a list of argument names (possibly containing nested lists), and
'varargs' and 'varkw' are the names of the * and ** arguments or None."""
if not iscode(co): raise TypeError, 'arg is not a code object'
if not iscode(co):
raise TypeError('{!r} is not a code object'.format(co))
nargs = co.co_argcount
names = co.co_varnames
@@ -577,24 +757,29 @@ def getargs(co):
step = 0
# The following acrobatics are for anonymous (tuple) arguments.
if not sys.platform.startswith('java'):#Jython doesn't have co_code
code = co.co_code
import dis
for i in range(nargs):
if args[i][:1] in ['', '.']:
stack, remain, count = [], [], []
while step < len(code):
op = ord(code[step])
step = step + 1
if op >= dis.HAVE_ARGUMENT:
opname = dis.opname[op]
value = ord(code[step]) + ord(code[step + 1]) * 256
step = step + 2
if opname in ['UNPACK_TUPLE', 'UNPACK_SEQUENCE']:
remain.append(value)
count.append(value)
elif opname == 'STORE_FAST':
stack.append(names[value])
for i in range(nargs):
if args[i][:1] in ('', '.'):
stack, remain, count = [], [], []
while step < len(co.co_code):
op = ord(co.co_code[step])
step = step + 1
if op >= dis.HAVE_ARGUMENT:
opname = dis.opname[op]
value = ord(co.co_code[step]) + ord(co.co_code[step+1])*256
step = step + 2
if opname in ('UNPACK_TUPLE', 'UNPACK_SEQUENCE'):
remain.append(value)
count.append(value)
elif opname == 'STORE_FAST':
stack.append(names[value])
# Special case for sublists of length 1: def foo((bar))
# doesn't generate the UNPACK_TUPLE bytecode, so if
# `remain` is empty here, we have such a sublist.
if not remain:
stack[0] = [stack[0]]
break
else:
remain[-1] = remain[-1] - 1
while remain[-1] == 0:
remain.pop()
@@ -603,7 +788,7 @@ def getargs(co):
if not remain: break
remain[-1] = remain[-1] - 1
if not remain: break
args[i] = stack[0]
args[i] = stack[0]
varargs = None
if co.co_flags & CO_VARARGS:
@@ -612,7 +797,9 @@ def getargs(co):
varkw = None
if co.co_flags & CO_VARKEYWORDS:
varkw = co.co_varnames[nargs]
return args, varargs, varkw
return Arguments(args, varargs, varkw)
ArgSpec = namedtuple('ArgSpec', 'args varargs keywords defaults')
def getargspec(func):
"""Get the names and default values of a function's arguments.
@@ -620,12 +807,17 @@ def getargspec(func):
A tuple of four things is returned: (args, varargs, varkw, defaults).
'args' is a list of the argument names (it may contain nested lists).
'varargs' and 'varkw' are the names of the * and ** arguments or None.
'defaults' is an n-tuple of the default values of the last n arguments."""
'defaults' is an n-tuple of the default values of the last n arguments.
"""
if ismethod(func):
func = func.im_func
if not isfunction(func): raise TypeError, 'arg is not a Python function'
if not isfunction(func):
raise TypeError('{!r} is not a Python function'.format(func))
args, varargs, varkw = getargs(func.func_code)
return args, varargs, varkw, func.func_defaults
return ArgSpec(args, varargs, varkw, func.func_defaults)
ArgInfo = namedtuple('ArgInfo', 'args varargs keywords locals')
def getargvalues(frame):
"""Get information about arguments passed into a particular frame.
@@ -635,7 +827,7 @@ def getargvalues(frame):
'varargs' and 'varkw' are the names of the * and ** arguments or None.
'locals' is the locals dictionary of the given frame."""
args, varargs, varkw = getargs(frame.f_code)
return args, varargs, varkw, frame.f_locals
return ArgInfo(args, varargs, varkw, frame.f_locals)
def joinseq(seq):
if len(seq) == 1:
@@ -645,7 +837,7 @@ def joinseq(seq):
def strseq(object, convert, join=joinseq):
"""Recursively walk a sequence, stringifying each element."""
if type(object) in [types.ListType, types.TupleType]:
if type(object) in (list, tuple):
return join(map(lambda o, c=convert, j=join: strseq(o, c, j), object))
else:
return convert(object)
@@ -665,14 +857,14 @@ def formatargspec(args, varargs=None, varkw=None, defaults=None,
specs = []
if defaults:
firstdefault = len(args) - len(defaults)
for i in range(len(args)):
spec = strseq(args[i], formatarg, join)
for i, arg in enumerate(args):
spec = strseq(arg, formatarg, join)
if defaults and i >= firstdefault:
spec = spec + formatvalue(defaults[i - firstdefault])
specs.append(spec)
if varargs:
if varargs is not None:
specs.append(formatvarargs(varargs))
if varkw:
if varkw is not None:
specs.append(formatvarkw(varkw))
return '(' + string.join(specs, ', ') + ')'
@@ -700,7 +892,99 @@ def formatargvalues(args, varargs, varkw, locals,
specs.append(formatvarkw(varkw) + formatvalue(locals[varkw]))
return '(' + string.join(specs, ', ') + ')'
def getcallargs(func, *positional, **named):
"""Get the mapping of arguments to values.
A dict is returned, with keys the function argument names (including the
names of the * and ** arguments, if any), and values the respective bound
values from 'positional' and 'named'."""
args, varargs, varkw, defaults = getargspec(func)
f_name = func.__name__
arg2value = {}
# The following closures are basically because of tuple parameter unpacking.
assigned_tuple_params = []
def assign(arg, value):
if isinstance(arg, str):
arg2value[arg] = value
else:
assigned_tuple_params.append(arg)
value = iter(value)
for i, subarg in enumerate(arg):
try:
subvalue = next(value)
except StopIteration:
raise ValueError('need more than %d %s to unpack' %
(i, 'values' if i > 1 else 'value'))
assign(subarg,subvalue)
try:
next(value)
except StopIteration:
pass
else:
raise ValueError('too many values to unpack')
def is_assigned(arg):
if isinstance(arg,str):
return arg in arg2value
return arg in assigned_tuple_params
if ismethod(func) and func.im_self is not None:
# implicit 'self' (or 'cls' for classmethods) argument
positional = (func.im_self,) + positional
num_pos = len(positional)
num_total = num_pos + len(named)
num_args = len(args)
num_defaults = len(defaults) if defaults else 0
for arg, value in zip(args, positional):
assign(arg, value)
if varargs:
if num_pos > num_args:
assign(varargs, positional[-(num_pos-num_args):])
else:
assign(varargs, ())
elif 0 < num_args < num_pos:
raise TypeError('%s() takes %s %d %s (%d given)' % (
f_name, 'at most' if defaults else 'exactly', num_args,
'arguments' if num_args > 1 else 'argument', num_total))
elif num_args == 0 and num_total:
if varkw:
if num_pos:
# XXX: We should use num_pos, but Python also uses num_total:
raise TypeError('%s() takes exactly 0 arguments '
'(%d given)' % (f_name, num_total))
else:
raise TypeError('%s() takes no arguments (%d given)' %
(f_name, num_total))
for arg in args:
if isinstance(arg, str) and arg in named:
if is_assigned(arg):
raise TypeError("%s() got multiple values for keyword "
"argument '%s'" % (f_name, arg))
else:
assign(arg, named.pop(arg))
if defaults: # fill in any missing values with the defaults
for arg, value in zip(args[-num_defaults:], defaults):
if not is_assigned(arg):
assign(arg, value)
if varkw:
assign(varkw, named)
elif named:
unexpected = next(iter(named))
if isinstance(unexpected, unicode):
unexpected = unexpected.encode(sys.getdefaultencoding(), 'replace')
raise TypeError("%s() got an unexpected keyword argument '%s'" %
(f_name, unexpected))
unassigned = num_args - len([arg for arg in args if is_assigned(arg)])
if unassigned:
num_required = num_args - num_defaults
raise TypeError('%s() takes %s %d %s (%d given)' % (
f_name, 'at least' if defaults else 'exactly', num_required,
'arguments' if num_required > 1 else 'argument', num_total))
return arg2value
# -------------------------------------------------- stack frame extraction
Traceback = namedtuple('Traceback', 'filename lineno function code_context index')
def getframeinfo(frame, context=1):
"""Get information about a frame or traceback object.
@@ -709,44 +993,35 @@ def getframeinfo(frame, context=1):
the source code, and the index of the current line within that list.
The optional second argument specifies the number of lines of context
to return, which are centered around the current line."""
raise NotImplementedError
# if istraceback(frame):
# frame = frame.tb_frame
# if not isframe(frame):
# raise TypeError, 'arg is not a frame or traceback object'
#
# filename = getsourcefile(frame)
# lineno = getlineno(frame)
# if context > 0:
# start = lineno - 1 - context//2
# try:
# lines, lnum = findsource(frame)
# except IOError:
# lines = index = None
# else:
# start = max(start, 1)
# start = min(start, len(lines) - context)
# lines = lines[start:start+context]
# index = lineno - 1 - start
# else:
# lines = index = None
#
# return (filename, lineno, frame.f_code.co_name, lines, index)
if istraceback(frame):
lineno = frame.tb_lineno
frame = frame.tb_frame
else:
lineno = frame.f_lineno
if not isframe(frame):
raise TypeError('{!r} is not a frame or traceback object'.format(frame))
filename = getsourcefile(frame) or getfile(frame)
if context > 0:
start = lineno - 1 - context//2
try:
lines, lnum = findsource(frame)
except IOError:
lines = index = None
else:
start = max(start, 1)
start = max(0, min(start, len(lines) - context))
lines = lines[start:start+context]
index = lineno - 1 - start
else:
lines = index = None
return Traceback(filename, lineno, frame.f_code.co_name, lines, index)
def getlineno(frame):
"""Get the line number from a frame object, allowing for optimization."""
# Written by Marc-Andr Lemburg; revised by Jim Hugunin and Fredrik Lundh.
lineno = frame.f_lineno
code = frame.f_code
if hasattr(code, 'co_lnotab'):
table = code.co_lnotab
lineno = code.co_firstlineno
addr = 0
for i in range(0, len(table), 2):
addr = addr + ord(table[i])
if addr > frame.f_lasti: break
lineno = lineno + ord(table[i + 1])
return lineno
# FrameType.f_lineno is now a descriptor that grovels co_lnotab
return frame.f_lineno
def getouterframes(frame, context=1):
"""Get a list of records for a frame and all higher (calling) frames.
@@ -770,19 +1045,15 @@ def getinnerframes(tb, context=1):
tb = tb.tb_next
return framelist
def currentframe():
"""Return the frame object for the caller's stack frame."""
try:
raise 'catch me'
except:
return sys.exc_traceback.tb_frame.f_back #@UndefinedVariable
if hasattr(sys, '_getframe'): currentframe = sys._getframe
if hasattr(sys, '_getframe'):
currentframe = sys._getframe
else:
currentframe = lambda _=None: None
def stack(context=1):
"""Return a list of records for the stack above the caller's frame."""
return getouterframes(currentframe().f_back, context)
return getouterframes(sys._getframe(1), context)
def trace(context=1):
"""Return a list of records for the stack below the current exception."""
return getinnerframes(sys.exc_traceback, context) #@UndefinedVariable
return getinnerframes(sys.exc_info()[2], context)
@@ -540,7 +540,7 @@ def extend_path(path, name):
if os.path.isfile(pkgfile):
try:
f = open(pkgfile)
except IOError, msg:
except IOError as msg:
sys.stderr.write("Can't open %s: %s\n" %
(pkgfile, msg))
else:
@@ -1,541 +0,0 @@
r"""UUID objects (universally unique identifiers) according to RFC 4122.
This module provides immutable UUID objects (class UUID) and the functions
uuid1(), uuid3(), uuid4(), uuid5() for generating version 1, 3, 4, and 5
UUIDs as specified in RFC 4122.
If all you want is a unique ID, you should probably call uuid1() or uuid4().
Note that uuid1() may compromise privacy since it creates a UUID containing
the computer's network address. uuid4() creates a random UUID.
Typical usage:
>>> import uuid
# make a UUID based on the host ID and current time
>>> uuid.uuid1()
UUID('a8098c1a-f86e-11da-bd1a-00112444be1e')
# make a UUID using an MD5 hash of a namespace UUID and a name
>>> uuid.uuid3(uuid.NAMESPACE_DNS, 'python.org')
UUID('6fa459ea-ee8a-3ca4-894e-db77e160355e')
# make a random UUID
>>> uuid.uuid4()
UUID('16fd2706-8baf-433b-82eb-8c7fada847da')
# make a UUID using a SHA-1 hash of a namespace UUID and a name
>>> uuid.uuid5(uuid.NAMESPACE_DNS, 'python.org')
UUID('886313e1-3b8a-5372-9b90-0c9aee199e5d')
# make a UUID from a string of hex digits (braces and hyphens ignored)
>>> x = uuid.UUID('{00010203-0405-0607-0809-0a0b0c0d0e0f}')
# convert a UUID to a string of hex digits in standard form
>>> str(x)
'00010203-0405-0607-0809-0a0b0c0d0e0f'
# get the raw 16 bytes of the UUID
>>> x.bytes
'\x00\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x0b\x0c\r\x0e\x0f'
# make a UUID from a 16-byte string
>>> uuid.UUID(bytes=x.bytes)
UUID('00010203-0405-0607-0809-0a0b0c0d0e0f')
"""
__author__ = 'Ka-Ping Yee <ping@zesty.ca>'
RESERVED_NCS, RFC_4122, RESERVED_MICROSOFT, RESERVED_FUTURE = [
'reserved for NCS compatibility', 'specified in RFC 4122',
'reserved for Microsoft compatibility', 'reserved for future definition']
class UUID(object):
"""Instances of the UUID class represent UUIDs as specified in RFC 4122.
UUID objects are immutable, hashable, and usable as dictionary keys.
Converting a UUID to a string with str() yields something in the form
'12345678-1234-1234-1234-123456789abc'. The UUID constructor accepts
five possible forms: a similar string of hexadecimal digits, or a tuple
of six integer fields (with 32-bit, 16-bit, 16-bit, 8-bit, 8-bit, and
48-bit values respectively) as an argument named 'fields', or a string
of 16 bytes (with all the integer fields in big-endian order) as an
argument named 'bytes', or a string of 16 bytes (with the first three
fields in little-endian order) as an argument named 'bytes_le', or a
single 128-bit integer as an argument named 'int'.
UUIDs have these read-only attributes:
bytes the UUID as a 16-byte string (containing the six
integer fields in big-endian byte order)
bytes_le the UUID as a 16-byte string (with time_low, time_mid,
and time_hi_version in little-endian byte order)
fields a tuple of the six integer fields of the UUID,
which are also available as six individual attributes
and two derived attributes:
time_low the first 32 bits of the UUID
time_mid the next 16 bits of the UUID
time_hi_version the next 16 bits of the UUID
clock_seq_hi_variant the next 8 bits of the UUID
clock_seq_low the next 8 bits of the UUID
node the last 48 bits of the UUID
time the 60-bit timestamp
clock_seq the 14-bit sequence number
hex the UUID as a 32-character hexadecimal string
int the UUID as a 128-bit integer
urn the UUID as a URN as specified in RFC 4122
variant the UUID variant (one of the constants RESERVED_NCS,
RFC_4122, RESERVED_MICROSOFT, or RESERVED_FUTURE)
version the UUID version number (1 through 5, meaningful only
when the variant is RFC_4122)
"""
def __init__(self, hex=None, bytes=None, bytes_le=None, fields=None,
int=None, version=None):
r"""Create a UUID from either a string of 32 hexadecimal digits,
a string of 16 bytes as the 'bytes' argument, a string of 16 bytes
in little-endian order as the 'bytes_le' argument, a tuple of six
integers (32-bit time_low, 16-bit time_mid, 16-bit time_hi_version,
8-bit clock_seq_hi_variant, 8-bit clock_seq_low, 48-bit node) as
the 'fields' argument, or a single 128-bit integer as the 'int'
argument. When a string of hex digits is given, curly braces,
hyphens, and a URN prefix are all optional. For example, these
expressions all yield the same UUID:
UUID('{12345678-1234-5678-1234-567812345678}')
UUID('12345678123456781234567812345678')
UUID('urn:uuid:12345678-1234-5678-1234-567812345678')
UUID(bytes='\x12\x34\x56\x78'*4)
UUID(bytes_le='\x78\x56\x34\x12\x34\x12\x78\x56' +
'\x12\x34\x56\x78\x12\x34\x56\x78')
UUID(fields=(0x12345678, 0x1234, 0x5678, 0x12, 0x34, 0x567812345678))
UUID(int=0x12345678123456781234567812345678)
Exactly one of 'hex', 'bytes', 'bytes_le', 'fields', or 'int' must
be given. The 'version' argument is optional; if given, the resulting
UUID will have its variant and version set according to RFC 4122,
overriding the given 'hex', 'bytes', 'bytes_le', 'fields', or 'int'.
"""
if [hex, bytes, bytes_le, fields, int].count(None) != 4:
raise TypeError('need one of hex, bytes, bytes_le, fields, or int')
if hex is not None:
hex = hex.replace('urn:', '').replace('uuid:', '')
hex = hex.strip('{}').replace('-', '')
if len(hex) != 32:
raise ValueError('badly formed hexadecimal UUID string')
int = long(hex, 16)
if bytes_le is not None:
if len(bytes_le) != 16:
raise ValueError('bytes_le is not a 16-char string')
bytes = (bytes_le[3] + bytes_le[2] + bytes_le[1] + bytes_le[0] +
bytes_le[5] + bytes_le[4] + bytes_le[7] + bytes_le[6] +
bytes_le[8:])
if bytes is not None:
if len(bytes) != 16:
raise ValueError('bytes is not a 16-char string')
int = long(('%02x'*16) % tuple(map(ord, bytes)), 16)
if fields is not None:
if len(fields) != 6:
raise ValueError('fields is not a 6-tuple')
(time_low, time_mid, time_hi_version,
clock_seq_hi_variant, clock_seq_low, node) = fields
if not 0 <= time_low < 1<<32L:
raise ValueError('field 1 out of range (need a 32-bit value)')
if not 0 <= time_mid < 1<<16L:
raise ValueError('field 2 out of range (need a 16-bit value)')
if not 0 <= time_hi_version < 1<<16L:
raise ValueError('field 3 out of range (need a 16-bit value)')
if not 0 <= clock_seq_hi_variant < 1<<8L:
raise ValueError('field 4 out of range (need an 8-bit value)')
if not 0 <= clock_seq_low < 1<<8L:
raise ValueError('field 5 out of range (need an 8-bit value)')
if not 0 <= node < 1<<48L:
raise ValueError('field 6 out of range (need a 48-bit value)')
clock_seq = (clock_seq_hi_variant << 8L) | clock_seq_low
int = ((time_low << 96L) | (time_mid << 80L) |
(time_hi_version << 64L) | (clock_seq << 48L) | node)
if int is not None:
if not 0 <= int < 1<<128L:
raise ValueError('int is out of range (need a 128-bit value)')
if version is not None:
if not 1 <= version <= 5:
raise ValueError('illegal version number')
# Set the variant to RFC 4122.
int &= ~(0xc000 << 48L)
int |= 0x8000 << 48L
# Set the version number.
int &= ~(0xf000 << 64L)
int |= version << 76L
self.__dict__['int'] = int
def __cmp__(self, other):
if isinstance(other, UUID):
return cmp(self.int, other.int)
return NotImplemented
def __hash__(self):
return hash(self.int)
def __int__(self):
return self.int
def __repr__(self):
return 'UUID(%r)' % str(self)
def __setattr__(self, name, value):
raise TypeError('UUID objects are immutable')
def __str__(self):
hex = '%032x' % self.int
return '%s-%s-%s-%s-%s' % (
hex[:8], hex[8:12], hex[12:16], hex[16:20], hex[20:])
def get_bytes(self):
bytes = ''
for shift in range(0, 128, 8):
bytes = chr((self.int >> shift) & 0xff) + bytes
return bytes
bytes = property(get_bytes)
def get_bytes_le(self):
bytes = self.bytes
return (bytes[3] + bytes[2] + bytes[1] + bytes[0] +
bytes[5] + bytes[4] + bytes[7] + bytes[6] + bytes[8:])
bytes_le = property(get_bytes_le)
def get_fields(self):
return (self.time_low, self.time_mid, self.time_hi_version,
self.clock_seq_hi_variant, self.clock_seq_low, self.node)
fields = property(get_fields)
def get_time_low(self):
return self.int >> 96L
time_low = property(get_time_low)
def get_time_mid(self):
return (self.int >> 80L) & 0xffff
time_mid = property(get_time_mid)
def get_time_hi_version(self):
return (self.int >> 64L) & 0xffff
time_hi_version = property(get_time_hi_version)
def get_clock_seq_hi_variant(self):
return (self.int >> 56L) & 0xff
clock_seq_hi_variant = property(get_clock_seq_hi_variant)
def get_clock_seq_low(self):
return (self.int >> 48L) & 0xff
clock_seq_low = property(get_clock_seq_low)
def get_time(self):
return (((self.time_hi_version & 0x0fffL) << 48L) |
(self.time_mid << 32L) | self.time_low)
time = property(get_time)
def get_clock_seq(self):
return (((self.clock_seq_hi_variant & 0x3fL) << 8L) |
self.clock_seq_low)
clock_seq = property(get_clock_seq)
def get_node(self):
return self.int & 0xffffffffffff
node = property(get_node)
def get_hex(self):
return '%032x' % self.int
hex = property(get_hex)
def get_urn(self):
return 'urn:uuid:' + str(self)
urn = property(get_urn)
def get_variant(self):
if not self.int & (0x8000 << 48L):
return RESERVED_NCS
elif not self.int & (0x4000 << 48L):
return RFC_4122
elif not self.int & (0x2000 << 48L):
return RESERVED_MICROSOFT
else:
return RESERVED_FUTURE
variant = property(get_variant)
def get_version(self):
# The version bits are only meaningful for RFC 4122 UUIDs.
if self.variant == RFC_4122:
return int((self.int >> 76L) & 0xf)
version = property(get_version)
def _find_mac(command, args, hw_identifiers, get_index):
import os
for dir in ['', '/sbin/', '/usr/sbin']:
executable = os.path.join(dir, command)
if not os.path.exists(executable):
continue
try:
# LC_ALL to get English output, 2>/dev/null to
# prevent output on stderr
cmd = 'LC_ALL=C %s %s 2>/dev/null' % (executable, args)
pipe = os.popen(cmd)
except IOError:
continue
for line in pipe:
words = line.lower().split()
for i in range(len(words)):
if words[i] in hw_identifiers:
return int(words[get_index(i)].replace(':', ''), 16)
return None
def _ifconfig_getnode():
"""Get the hardware address on Unix by running ifconfig."""
# This works on Linux ('' or '-a'), Tru64 ('-av'), but not all Unixes.
for args in ('', '-a', '-av'):
mac = _find_mac('ifconfig', args, ['hwaddr', 'ether'], lambda i: i+1)
if mac:
return mac
import socket
ip_addr = socket.gethostbyname(socket.gethostname())
# Try getting the MAC addr from arp based on our IP address (Solaris).
mac = _find_mac('arp', '-an', [ip_addr], lambda i: -1)
if mac:
return mac
# This might work on HP-UX.
mac = _find_mac('lanscan', '-ai', ['lan0'], lambda i: 0)
if mac:
return mac
return None
def _ipconfig_getnode():
"""Get the hardware address on Windows by running ipconfig.exe."""
import os, re
dirs = ['', r'c:\windows\system32', r'c:\winnt\system32']
try:
import ctypes
buffer = ctypes.create_string_buffer(300)
ctypes.windll.kernel32.GetSystemDirectoryA(buffer, 300) # @UndefinedVariable
dirs.insert(0, buffer.value.decode('mbcs'))
except:
pass
for dir in dirs:
try:
pipe = os.popen(os.path.join(dir, 'ipconfig') + ' /all')
except IOError:
continue
for line in pipe:
value = line.split(':')[-1].strip().lower()
if re.match('([0-9a-f][0-9a-f]-){5}[0-9a-f][0-9a-f]', value):
return int(value.replace('-', ''), 16)
def _netbios_getnode():
"""Get the hardware address on Windows using NetBIOS calls.
See http://support.microsoft.com/kb/118623 for details."""
import win32wnet, netbios
ncb = netbios.NCB()
ncb.Command = netbios.NCBENUM
ncb.Buffer = adapters = netbios.LANA_ENUM()
adapters._pack()
if win32wnet.Netbios(ncb) != 0:
return
adapters._unpack()
for i in range(adapters.length):
ncb.Reset()
ncb.Command = netbios.NCBRESET
ncb.Lana_num = ord(adapters.lana[i])
if win32wnet.Netbios(ncb) != 0:
continue
ncb.Reset()
ncb.Command = netbios.NCBASTAT
ncb.Lana_num = ord(adapters.lana[i])
ncb.Callname = '*'.ljust(16)
ncb.Buffer = status = netbios.ADAPTER_STATUS()
if win32wnet.Netbios(ncb) != 0:
continue
status._unpack()
bytes = map(ord, status.adapter_address)
return ((bytes[0]<<40L) + (bytes[1]<<32L) + (bytes[2]<<24L) +
(bytes[3]<<16L) + (bytes[4]<<8L) + bytes[5])
# Thanks to Thomas Heller for ctypes and for his help with its use here.
# If ctypes is available, use it to find system routines for UUID generation.
_uuid_generate_random = _uuid_generate_time = _UuidCreate = None
try:
import ctypes, ctypes.util
_buffer = ctypes.create_string_buffer(16)
# The uuid_generate_* routines are provided by libuuid on at least
# Linux and FreeBSD, and provided by libc on Mac OS X.
for libname in ['uuid', 'c']:
try:
lib = ctypes.CDLL(ctypes.util.find_library(libname))
except:
continue
if hasattr(lib, 'uuid_generate_random'):
_uuid_generate_random = lib.uuid_generate_random
if hasattr(lib, 'uuid_generate_time'):
_uuid_generate_time = lib.uuid_generate_time
# On Windows prior to 2000, UuidCreate gives a UUID containing the
# hardware address. On Windows 2000 and later, UuidCreate makes a
# random UUID and UuidCreateSequential gives a UUID containing the
# hardware address. These routines are provided by the RPC runtime.
# NOTE: at least on Tim's WinXP Pro SP2 desktop box, while the last
# 6 bytes returned by UuidCreateSequential are fixed, they don't appear
# to bear any relationship to the MAC address of any network device
# on the box.
try:
lib = ctypes.windll.rpcrt4
except:
lib = None
_UuidCreate = getattr(lib, 'UuidCreateSequential',
getattr(lib, 'UuidCreate', None))
except:
pass
def _unixdll_getnode():
"""Get the hardware address on Unix using ctypes."""
_uuid_generate_time(_buffer)
return UUID(bytes=_buffer.raw).node
def _windll_getnode():
"""Get the hardware address on Windows using ctypes."""
if _UuidCreate(_buffer) == 0:
return UUID(bytes=_buffer.raw).node
def _random_getnode():
"""Get a random node ID, with eighth bit set as suggested by RFC 4122."""
import random
return random.randrange(0, 1<<48L) | 0x010000000000L
_node = None
def getnode():
"""Get the hardware address as a 48-bit positive integer.
The first time this runs, it may launch a separate program, which could
be quite slow. If all attempts to obtain the hardware address fail, we
choose a random 48-bit number with its eighth bit set to 1 as recommended
in RFC 4122.
"""
global _node
if _node is not None:
return _node
import sys
if sys.platform == 'win32':
getters = [_windll_getnode, _netbios_getnode, _ipconfig_getnode]
else:
getters = [_unixdll_getnode, _ifconfig_getnode]
for getter in getters + [_random_getnode]:
try:
_node = getter()
except:
continue
if _node is not None:
return _node
_last_timestamp = None
def uuid1(node=None, clock_seq=None):
"""Generate a UUID from a host ID, sequence number, and the current time.
If 'node' is not given, getnode() is used to obtain the hardware
address. If 'clock_seq' is given, it is used as the sequence number;
otherwise a random 14-bit sequence number is chosen."""
# When the system provides a version-1 UUID generator, use it (but don't
# use UuidCreate here because its UUIDs don't conform to RFC 4122).
if _uuid_generate_time and node is clock_seq is None:
_uuid_generate_time(_buffer)
return UUID(bytes=_buffer.raw)
global _last_timestamp
import time
nanoseconds = int(time.time() * 1e9)
# 0x01b21dd213814000 is the number of 100-ns intervals between the
# UUID epoch 1582-10-15 00:00:00 and the Unix epoch 1970-01-01 00:00:00.
timestamp = int(nanoseconds/100) + 0x01b21dd213814000L
if timestamp <= _last_timestamp:
timestamp = _last_timestamp + 1
_last_timestamp = timestamp
if clock_seq is None:
import random
clock_seq = random.randrange(1<<14L) # instead of stable storage
time_low = timestamp & 0xffffffffL
time_mid = (timestamp >> 32L) & 0xffffL
time_hi_version = (timestamp >> 48L) & 0x0fffL
clock_seq_low = clock_seq & 0xffL
clock_seq_hi_variant = (clock_seq >> 8L) & 0x3fL
if node is None:
node = getnode()
return UUID(fields=(time_low, time_mid, time_hi_version,
clock_seq_hi_variant, clock_seq_low, node), version=1)
def uuid3(namespace, name):
"""Generate a UUID from the MD5 hash of a namespace UUID and a name."""
import md5
hash = md5.md5(namespace.bytes + name).digest()
return UUID(bytes=hash[:16], version=3)
def uuid4():
"""Generate a random UUID."""
# When the system provides a version-4 UUID generator, use it.
if _uuid_generate_random:
_uuid_generate_random(_buffer)
return UUID(bytes=_buffer.raw)
# Otherwise, get randomness from urandom or the 'random' module.
try:
import os
return UUID(bytes=os.urandom(16), version=4)
except:
import random
bytes = [chr(random.randrange(256)) for i in range(16)]
return UUID(bytes=bytes, version=4)
def uuid5(namespace, name):
"""Generate a UUID from the SHA-1 hash of a namespace UUID and a name."""
import sha
hash = sha.sha(namespace.bytes + name).digest()
return UUID(bytes=hash[:16], version=5)
# The following standard UUIDs are for use with uuid3() or uuid5().
NAMESPACE_DNS = UUID('6ba7b810-9dad-11d1-80b4-00c04fd430c8')
NAMESPACE_URL = UUID('6ba7b811-9dad-11d1-80b4-00c04fd430c8')
NAMESPACE_OID = UUID('6ba7b812-9dad-11d1-80b4-00c04fd430c8')
NAMESPACE_X500 = UUID('6ba7b814-9dad-11d1-80b4-00c04fd430c8')
@@ -1,8 +1,6 @@
#Just a copy of the version in python 2.5 to be used if it's not available in jython 2.1
import sys
#
# XML-RPC CLIENT LIBRARY
# $Id$
#
# an XML-RPC client interface for Python.
#
@@ -51,6 +49,7 @@ import sys
# 2003-07-12 gp Correct marshalling of Faults
# 2003-10-31 mvl Add multicall support
# 2004-08-20 mvl Bump minimum supported Python version to 2.1
# 2014-12-02 ch/doko Add workaround for gzip bomb vulnerability
#
# Copyright (c) 1999-2002 by Secret Labs AB.
# Copyright (c) 1999-2002 by Fredrik Lundh.
@@ -141,6 +140,13 @@ Exported functions:
import re, string, time, operator
from types import *
import socket
import errno
import httplib
try:
import gzip
except ImportError:
gzip = None #python can be built without zlib/gzip support
# --------------------------------------------------------------------
# Internal stuff
@@ -157,7 +163,7 @@ except ImportError:
try:
_bool_is_builtin = False.__class__.__name__ == "bool"
except (NameError, AttributeError):
except NameError:
_bool_is_builtin = 0
def _decode(data, encoding, is8bit=re.compile("[\x80-\xff]").search):
@@ -185,32 +191,28 @@ else:
__version__ = "1.0.1"
# xmlrpc integer limits
try:
long
except NameError:
long = int
MAXINT = long(2) ** 31 - 1
MININT = long(-2) ** 31
MAXINT = 2L**31-1
MININT = -2L**31
# --------------------------------------------------------------------
# Error constants (from Dan Libby's specification at
# http://xmlrpc-epi.sourceforge.net/specs/rfc.fault_codes.php)
# Ranges of errors
PARSE_ERROR = -32700
SERVER_ERROR = -32600
PARSE_ERROR = -32700
SERVER_ERROR = -32600
APPLICATION_ERROR = -32500
SYSTEM_ERROR = -32400
TRANSPORT_ERROR = -32300
SYSTEM_ERROR = -32400
TRANSPORT_ERROR = -32300
# Specific errors
NOT_WELLFORMED_ERROR = -32700
UNSUPPORTED_ENCODING = -32701
NOT_WELLFORMED_ERROR = -32700
UNSUPPORTED_ENCODING = -32701
INVALID_ENCODING_CHAR = -32702
INVALID_XMLRPC = -32600
METHOD_NOT_FOUND = -32601
INVALID_XMLRPC = -32600
METHOD_NOT_FOUND = -32601
INVALID_METHOD_PARAMS = -32602
INTERNAL_ERROR = -32603
INTERNAL_ERROR = -32603
# --------------------------------------------------------------------
# Exceptions
@@ -243,9 +245,9 @@ class ProtocolError(Error):
self.headers = headers
def __repr__(self):
return (
"<ProtocolError for %s: %s %s>" %
(self.url, self.errcode, self.errmsg)
)
"<ProtocolError for %s: %s %s>" %
(self.url, self.errcode, self.errmsg)
)
##
# Indicates a broken XML-RPC response package. This exception is
@@ -273,9 +275,9 @@ class Fault(Error):
self.faultString = faultString
def __repr__(self):
return (
"<Fault %s: %s>" %
(self.faultCode, repr(self.faultString))
)
"<Fault %s: %s>" %
(self.faultCode, repr(self.faultString))
)
# --------------------------------------------------------------------
# Special values
@@ -288,10 +290,13 @@ class Fault(Error):
# @param value A boolean value. Any true value is interpreted as True,
# all other values are interpreted as False.
from sys import modules
mod_dict = modules[__name__].__dict__
if _bool_is_builtin:
boolean = Boolean = bool #@UndefinedVariable
boolean = Boolean = bool
# to avoid breaking code which references xmlrpclib.{True,False}
True, False = True, False
mod_dict['True'] = True
mod_dict['False'] = False
else:
class Boolean:
"""Boolean-value wrapper.
@@ -299,7 +304,7 @@ else:
Use True or False to generate a "boolean" XML-RPC value.
"""
def __init__(self, value=0):
def __init__(self, value = 0):
self.value = operator.truth(value)
def encode(self, out):
@@ -322,7 +327,8 @@ else:
def __nonzero__(self):
return self.value
True, False = Boolean(1), Boolean(0)
mod_dict['True'] = Boolean(1)
mod_dict['False'] = Boolean(0)
##
# Map true or false value to XML-RPC boolean values.
@@ -339,6 +345,8 @@ else:
"""Convert any Python value to XML-RPC 'boolean'."""
return _truefalse[operator.truth(value)]
del modules, mod_dict
##
# Wrapper for XML-RPC DateTime values. This converts a time value to
# the format used by XML-RPC.
@@ -352,6 +360,20 @@ else:
# @param value The time, given as an ISO 8601 string, a time
# tuple, or a integer time value.
def _strftime(value):
if datetime:
if isinstance(value, datetime.datetime):
return "%04d%02d%02dT%02d:%02d:%02d" % (
value.year, value.month, value.day,
value.hour, value.minute, value.second)
if not isinstance(value, (TupleType, time.struct_time)):
if value == 0:
value = time.time()
value = time.localtime(value)
return "%04d%02d%02dT%02d:%02d:%02d" % value[:6]
class DateTime:
"""DateTime wrapper for an ISO 8601 string or time tuple or
localtime integer value to generate 'dateTime.iso8601' XML-RPC
@@ -359,28 +381,62 @@ class DateTime:
"""
def __init__(self, value=0):
if not isinstance(value, StringType):
if datetime and isinstance(value, datetime.datetime):
self.value = value.strftime("%Y%m%dT%H:%M:%S")
return
if datetime and isinstance(value, datetime.date):
self.value = value.strftime("%Y%m%dT%H:%M:%S")
return
if datetime and isinstance(value, datetime.time):
today = datetime.datetime.now().strftime("%Y%m%d")
self.value = value.strftime(today + "T%H:%M:%S")
return
if not isinstance(value, (TupleType, time.struct_time)): #@UndefinedVariable
if value == 0:
value = time.time()
value = time.localtime(value)
value = time.strftime("%Y%m%dT%H:%M:%S", value)
self.value = value
if isinstance(value, StringType):
self.value = value
else:
self.value = _strftime(value)
def make_comparable(self, other):
if isinstance(other, DateTime):
s = self.value
o = other.value
elif datetime and isinstance(other, datetime.datetime):
s = self.value
o = other.strftime("%Y%m%dT%H:%M:%S")
elif isinstance(other, (str, unicode)):
s = self.value
o = other
elif hasattr(other, "timetuple"):
s = self.timetuple()
o = other.timetuple()
else:
otype = (hasattr(other, "__class__")
and other.__class__.__name__
or type(other))
raise TypeError("Can't compare %s and %s" %
(self.__class__.__name__, otype))
return s, o
def __lt__(self, other):
s, o = self.make_comparable(other)
return s < o
def __le__(self, other):
s, o = self.make_comparable(other)
return s <= o
def __gt__(self, other):
s, o = self.make_comparable(other)
return s > o
def __ge__(self, other):
s, o = self.make_comparable(other)
return s >= o
def __eq__(self, other):
s, o = self.make_comparable(other)
return s == o
def __ne__(self, other):
s, o = self.make_comparable(other)
return s != o
def timetuple(self):
return time.strptime(self.value, "%Y%m%dT%H:%M:%S")
def __cmp__(self, other):
if isinstance(other, DateTime):
other = other.value
return cmp(self.value, other)
s, o = self.make_comparable(other)
return cmp(s, o)
##
# Get date/time value.
@@ -409,7 +465,7 @@ def _datetime(data):
return value
def _datetime_type(data):
t = time.strptime(data, "%Y%m%dT%H:%M:%S") #@UndefinedVariable
t = time.strptime(data, "%Y%m%dT%H:%M:%S")
return datetime.datetime(*tuple(t)[:6])
##
@@ -466,78 +522,27 @@ if not _bool_is_builtin:
try:
# optional xmlrpclib accelerator
import _xmlrpclib #@UnresolvedImport
import _xmlrpclib
FastParser = _xmlrpclib.Parser
FastUnmarshaller = _xmlrpclib.Unmarshaller
except (AttributeError, ImportError):
FastParser = FastUnmarshaller = None
try:
import _xmlrpclib #@UnresolvedImport
import _xmlrpclib
FastMarshaller = _xmlrpclib.Marshaller
except (AttributeError, ImportError):
FastMarshaller = None
#
# the SGMLOP parser is about 15x faster than Python's builtin
# XML parser. SGMLOP sources can be downloaded from:
#
# http://www.pythonware.com/products/xml/sgmlop.htm
#
try:
import sgmlop
if not hasattr(sgmlop, "XMLParser"):
raise ImportError()
except ImportError:
SgmlopParser = None # sgmlop accelerator not available
else:
class SgmlopParser:
def __init__(self, target):
# setup callbacks
self.finish_starttag = target.start
self.finish_endtag = target.end
self.handle_data = target.data
self.handle_xml = target.xml
# activate parser
self.parser = sgmlop.XMLParser()
self.parser.register(self)
self.feed = self.parser.feed
self.entity = {
"amp": "&", "gt": ">", "lt": "<",
"apos": "'", "quot": '"'
}
def close(self):
try:
self.parser.close()
finally:
self.parser = self.feed = None # nuke circular reference
def handle_proc(self, tag, attr):
m = re.search("encoding\s*=\s*['\"]([^\"']+)[\"']", attr) #@UndefinedVariable
if m:
self.handle_xml(m.group(1), 1)
def handle_entityref(self, entity):
# <string> entity
try:
self.handle_data(self.entity[entity])
except KeyError:
self.handle_data("&%s;" % entity)
try:
from xml.parsers import expat
if not hasattr(expat, "ParserCreate"):
raise ImportError()
raise ImportError
except ImportError:
ExpatParser = None # expat not available
else:
class ExpatParser:
# fast expat parser for Python 2.0 and later. this is about
# 50% slower than sgmlop, on roundtrip testing
# fast expat parser for Python 2.0 and later.
def __init__(self, target):
self._parser = parser = expat.ParserCreate(None, None)
self._target = target
@@ -558,8 +563,7 @@ else:
class SlowParser:
"""Default XML parser (based on xmllib.XMLParser)."""
# this is about 10 times slower than sgmlop, on roundtrip
# testing.
# this is the slowest parser.
def __init__(self, target):
import xmllib # lazy subclassing (!)
if xmllib.XMLParser not in SlowParser.__bases__:
@@ -636,20 +640,30 @@ class Marshaller:
try:
f = self.dispatch[type(value)]
except KeyError:
raise TypeError("cannot marshal %s objects" % type(value))
else:
f(self, value, write)
# check if this object can be marshalled as a structure
try:
value.__dict__
except:
raise TypeError, "cannot marshal %s objects" % type(value)
# check if this class is a sub-class of a basic type,
# because we don't know how to marshal these types
# (e.g. a string sub-class)
for type_ in type(value).__mro__:
if type_ in self.dispatch.keys():
raise TypeError, "cannot marshal %s objects" % type(value)
f = self.dispatch[InstanceType]
f(self, value, write)
def dump_nil (self, value, write):
if not self.allow_none:
raise TypeError("cannot marshal None unless allow_none is enabled")
raise TypeError, "cannot marshal None unless allow_none is enabled"
write("<value><nil/></value>")
dispatch[NoneType] = dump_nil
def dump_int(self, value, write):
# in case ints are > 32 bits
if value > MAXINT or value < MININT:
raise OverflowError("int exceeds XML-RPC limits")
raise OverflowError, "int exceeds XML-RPC limits"
write("<value><int>")
write(str(value))
write("</int></value>\n")
@@ -660,11 +674,11 @@ class Marshaller:
write("<value><boolean>")
write(value and "1" or "0")
write("</boolean></value>\n")
dispatch[bool] = dump_bool #@UndefinedVariable
dispatch[bool] = dump_bool
def dump_long(self, value, write):
if value > MAXINT or value < MININT:
raise OverflowError("long int exceeds XML-RPC limits")
raise OverflowError, "long int exceeds XML-RPC limits"
write("<value><int>")
write(str(int(value)))
write("</int></value>\n")
@@ -692,8 +706,8 @@ class Marshaller:
def dump_array(self, value, write):
i = id(value)
if self.memo.has_key(i):
raise TypeError("cannot marshal recursive sequences")
if i in self.memo:
raise TypeError, "cannot marshal recursive sequences"
self.memo[i] = None
dump = self.__dump
write("<value><array><data>\n")
@@ -706,8 +720,8 @@ class Marshaller:
def dump_struct(self, value, write, escape=escape):
i = id(value)
if self.memo.has_key(i):
raise TypeError("cannot marshal recursive dictionaries")
if i in self.memo:
raise TypeError, "cannot marshal recursive dictionaries"
self.memo[i] = None
dump = self.__dump
write("<value><struct>\n")
@@ -717,7 +731,7 @@ class Marshaller:
if unicode and type(k) is UnicodeType:
k = k.encode(self.encoding)
else:
raise TypeError("dictionary key must be string")
raise TypeError, "dictionary key must be string"
write("<name>%s</name>\n" % escape(k))
dump(v, write)
write("</member>\n")
@@ -728,23 +742,10 @@ class Marshaller:
if datetime:
def dump_datetime(self, value, write):
write("<value><dateTime.iso8601>")
write(value.strftime("%Y%m%dT%H:%M:%S"))
write(_strftime(value))
write("</dateTime.iso8601></value>\n")
dispatch[datetime.datetime] = dump_datetime
def dump_date(self, value, write):
write("<value><dateTime.iso8601>")
write(value.strftime("%Y%m%dT00:00:00"))
write("</dateTime.iso8601></value>\n")
dispatch[datetime.date] = dump_date
def dump_time(self, value, write):
write("<value><dateTime.iso8601>")
write(datetime.datetime.now().date().strftime("%Y%m%dT"))
write(value.strftime("%H:%M:%S"))
write("</dateTime.iso8601></value>\n")
dispatch[datetime.time] = dump_time
def dump_instance(self, value, write):
# check for special wrappers
if value.__class__ in WRAPPERS:
@@ -783,7 +784,7 @@ class Unmarshaller:
self.append = self._stack.append
self._use_datetime = use_datetime
if use_datetime and not datetime:
raise ValueError("the datetime module is not available")
raise ValueError, "the datetime module is not available"
def close(self):
# return response tuple and target method
@@ -850,7 +851,7 @@ class Unmarshaller:
elif data == "1":
self.append(True)
else:
raise TypeError("bad boolean value")
raise TypeError, "bad boolean value"
self._value = 0
dispatch["boolean"] = end_boolean
@@ -858,6 +859,7 @@ class Unmarshaller:
self.append(int(data))
self._value = 0
dispatch["i4"] = end_int
dispatch["i8"] = end_int
dispatch["int"] = end_int
def end_double(self, data):
@@ -886,7 +888,7 @@ class Unmarshaller:
dict = {}
items = self._stack[mark:]
for i in range(0, len(items), 2):
dict[_stringify(items[i])] = items[i + 1]
dict[_stringify(items[i])] = items[i+1]
self._stack[mark:] = [dict]
self._value = 0
dispatch["struct"] = end_struct
@@ -944,7 +946,7 @@ class _MultiCallMethod:
class MultiCallIterator:
"""Iterates over the results of a multicall. Exceptions are
thrown in response to xmlrpc faults."""
raised in response to xmlrpc faults."""
def __init__(self, results):
self.results = results
@@ -956,7 +958,8 @@ class MultiCallIterator:
elif type(item) == type([]):
return item[0]
else:
raise ValueError("unexpected type in multicall result")
raise ValueError, \
"unexpected type in multicall result"
class MultiCall:
"""server -> a object used to boxcar method calls
@@ -1010,7 +1013,7 @@ def getparser(use_datetime=0):
to an unmarshalling object. Return both objects.
"""
if use_datetime and not datetime:
raise ValueError("the datetime module is not available")
raise ValueError, "the datetime module is not available"
if FastParser and FastUnmarshaller:
if use_datetime:
mkdatetime = _datetime_type
@@ -1022,8 +1025,6 @@ def getparser(use_datetime=0):
target = Unmarshaller(use_datetime=use_datetime)
if FastParser:
parser = FastParser(target)
elif SgmlopParser:
parser = SgmlopParser(target)
elif ExpatParser:
parser = ExpatParser(target)
else:
@@ -1067,7 +1068,7 @@ def dumps(params, methodname=None, methodresponse=None, encoding=None,
"""
assert isinstance(params, TupleType) or isinstance(params, Fault), \
"argument must be tuple or Fault instance"
"argument must be tuple or Fault instance"
if isinstance(params, Fault):
methodresponse = 1
@@ -1100,7 +1101,7 @@ def dumps(params, methodname=None, methodresponse=None, encoding=None,
"<methodName>", methodname, "</methodName>\n",
data,
"</methodCall>\n"
)
)
elif methodresponse:
# a method response, or a fault structure
data = (
@@ -1108,7 +1109,7 @@ def dumps(params, methodname=None, methodresponse=None, encoding=None,
"<methodResponse>\n",
data,
"</methodResponse>\n"
)
)
else:
return data # return as is
return string.join(data, "")
@@ -1136,6 +1137,86 @@ def loads(data, use_datetime=0):
p.close()
return u.close(), u.getmethodname()
##
# Encode a string using the gzip content encoding such as specified by the
# Content-Encoding: gzip
# in the HTTP header, as described in RFC 1952
#
# @param data the unencoded data
# @return the encoded data
def gzip_encode(data):
"""data -> gzip encoded data
Encode data using the gzip content encoding as described in RFC 1952
"""
if not gzip:
raise NotImplementedError
f = StringIO.StringIO()
gzf = gzip.GzipFile(mode="wb", fileobj=f, compresslevel=1)
gzf.write(data)
gzf.close()
encoded = f.getvalue()
f.close()
return encoded
##
# Decode a string using the gzip content encoding such as specified by the
# Content-Encoding: gzip
# in the HTTP header, as described in RFC 1952
#
# @param data The encoded data
# @keyparam max_decode Maximum bytes to decode (20MB default), use negative
# values for unlimited decoding
# @return the unencoded data
# @raises ValueError if data is not correctly coded.
# @raises ValueError if max gzipped payload length exceeded
def gzip_decode(data, max_decode=20971520):
"""gzip encoded data -> unencoded data
Decode data using the gzip content encoding as described in RFC 1952
"""
if not gzip:
raise NotImplementedError
f = StringIO.StringIO(data)
gzf = gzip.GzipFile(mode="rb", fileobj=f)
try:
if max_decode < 0: # no limit
decoded = gzf.read()
else:
decoded = gzf.read(max_decode + 1)
except IOError:
raise ValueError("invalid data")
f.close()
gzf.close()
if max_decode >= 0 and len(decoded) > max_decode:
raise ValueError("max gzipped payload length exceeded")
return decoded
##
# Return a decoded file-like object for the gzip encoding
# as described in RFC 1952.
#
# @param response A stream supporting a read() method
# @return a file-like object that the decoded data can be read() from
class GzipDecodedResponse(gzip.GzipFile if gzip else object):
"""a file-like object to decode a response encoded with the gzip
method, as described in RFC 1952.
"""
def __init__(self, response):
#response doesn't support tell() and read(), required by
#GzipFile
if not gzip:
raise NotImplementedError
self.stringio = StringIO.StringIO(response.read())
gzip.GzipFile.__init__(self, mode="rb", fileobj=self.stringio)
def close(self):
gzip.GzipFile.close(self)
self.stringio.close()
# --------------------------------------------------------------------
# request dispatcher
@@ -1163,8 +1244,39 @@ class Transport:
# client identifier (may be overridden)
user_agent = "xmlrpclib.py/%s (by www.pythonware.com)" % __version__
#if true, we'll request gzip encoding
accept_gzip_encoding = True
# if positive, encode request using gzip if it exceeds this threshold
# note that many server will get confused, so only use it if you know
# that they can decode such a request
encode_threshold = None #None = don't encode
def __init__(self, use_datetime=0):
self._use_datetime = use_datetime
self._connection = (None, None)
self._extra_headers = []
##
# Send a complete request, and parse the response.
# Retry request if a cached connection has disconnected.
#
# @param host Target host.
# @param handler Target PRC handler.
# @param request_body XML-RPC request body.
# @param verbose Debugging flag.
# @return Parsed response.
def request(self, host, handler, request_body, verbose=0):
#retry request once if cached connection has gone cold
for i in (0, 1):
try:
return self.single_request(host, handler, request_body, verbose)
except socket.error, e:
if i or e.errno not in (errno.ECONNRESET, errno.ECONNABORTED, errno.EPIPE):
raise
except httplib.BadStatusLine: #close after we sent request
if i:
raise
##
# Send a complete request, and parse the response.
@@ -1175,35 +1287,39 @@ class Transport:
# @param verbose Debugging flag.
# @return Parsed response.
def request(self, host, handler, request_body, verbose=0):
def single_request(self, host, handler, request_body, verbose=0):
# issue XML-RPC request
h = self.make_connection(host)
if verbose:
h.set_debuglevel(1)
self.send_request(h, handler, request_body)
self.send_host(h, host)
self.send_user_agent(h)
self.send_content(h, request_body)
errcode, errmsg, headers = h.getreply()
if errcode != 200:
raise ProtocolError(
host + handler,
errcode, errmsg,
headers
)
self.verbose = verbose
try:
sock = h._conn.sock
except AttributeError:
sock = None
self.send_request(h, handler, request_body)
self.send_host(h, host)
self.send_user_agent(h)
self.send_content(h, request_body)
return self._parse_response(h.getfile(), sock)
response = h.getresponse(buffering=True)
if response.status == 200:
self.verbose = verbose
return self.parse_response(response)
except Fault:
raise
except Exception:
# All unexpected errors leave connection in
# a strange state, so we clear it.
self.close()
raise
#discard any response data and raise exception
if (response.getheader("content-length", 0)):
response.read()
raise ProtocolError(
host + handler,
response.status, response.reason,
response.msg,
)
##
# Create parser.
@@ -1239,7 +1355,7 @@ class Transport:
auth = string.join(string.split(auth), "") # get rid of whitespace
extra_headers = [
("Authorization", "Basic " + auth)
]
]
else:
extra_headers = None
@@ -1252,10 +1368,25 @@ class Transport:
# @return A connection handle.
def make_connection(self, host):
#return an existing connection if possible. This allows
#HTTP/1.1 keep-alive.
if self._connection and host == self._connection[0]:
return self._connection[1]
# create a HTTP connection object from a host descriptor
import httplib
host, extra_headers, x509 = self.get_host_info(host)
return httplib.HTTP(host)
chost, self._extra_headers, x509 = self.get_host_info(host)
#store the host argument along with the connection object
self._connection = host, httplib.HTTPConnection(chost)
return self._connection[1]
##
# Clear any cached connection object.
# Used in the event of socket errors.
#
def close(self):
if self._connection[1]:
self._connection[1].close()
self._connection = (None, None)
##
# Send request header.
@@ -1265,17 +1396,24 @@ class Transport:
# @param request_body XML-RPC body.
def send_request(self, connection, handler, request_body):
connection.putrequest("POST", handler)
if (self.accept_gzip_encoding and gzip):
connection.putrequest("POST", handler, skip_accept_encoding=True)
connection.putheader("Accept-Encoding", "gzip")
else:
connection.putrequest("POST", handler)
##
# Send host name.
#
# @param connection Connection handle.
# @param host Host name.
#
# Note: This function doesn't actually add the "Host"
# header anymore, it is done as part of the connection.putrequest() in
# send_request() above.
def send_host(self, connection, host):
host, extra_headers, x509 = self.get_host_info(host)
connection.putheader("Host", host)
extra_headers = self._extra_headers
if extra_headers:
if isinstance(extra_headers, DictType):
extra_headers = extra_headers.items()
@@ -1298,10 +1436,16 @@ class Transport:
def send_content(self, connection, request_body):
connection.putheader("Content-Type", "text/xml")
#optionally encode the request
if (self.encode_threshold is not None and
self.encode_threshold < len(request_body) and
gzip):
connection.putheader("Content-Encoding", "gzip")
request_body = gzip_encode(request_body)
connection.putheader("Content-Length", str(len(request_body)))
connection.endheaders()
if request_body:
connection.send(request_body)
connection.endheaders(request_body)
##
# Parse response.
@@ -1309,37 +1453,30 @@ class Transport:
# @param file Stream.
# @return Response tuple and target method.
def parse_response(self, file):
# compatibility interface
return self._parse_response(file, None)
def parse_response(self, response):
# read response data from httpresponse, and parse it
##
# Parse response (alternate interface). This is similar to the
# parse_response method, but also provides direct access to the
# underlying socket object (where available).
#
# @param file Stream.
# @param sock Socket handle (or None, if the socket object
# could not be accessed).
# @return Response tuple and target method.
def _parse_response(self, file, sock):
# read response from input file/socket, and parse it
# Check for new http response object, else it is a file object
if hasattr(response,'getheader'):
if response.getheader("Content-Encoding", "") == "gzip":
stream = GzipDecodedResponse(response)
else:
stream = response
else:
stream = response
p, u = self.getparser()
while 1:
if sock:
response = sock.recv(1024)
else:
response = file.read(1024)
if not response:
data = stream.read(1024)
if not data:
break
if self.verbose:
sys.stdout.write("body: %s\n" % repr(response))
p.feed(response)
print "body:", repr(data)
p.feed(data)
file.close()
if stream is not response:
stream.close()
p.close()
return u.close()
@@ -1353,18 +1490,20 @@ class SafeTransport(Transport):
# FIXME: mostly untested
def make_connection(self, host):
if self._connection and host == self._connection[0]:
return self._connection[1]
# create a HTTPS connection object from a host descriptor
# host may be a string, or a (host, x509-dict) tuple
import httplib
host, extra_headers, x509 = self.get_host_info(host)
try:
HTTPS = httplib.HTTPS
HTTPS = httplib.HTTPSConnection
except AttributeError:
raise NotImplementedError(
"your version of httplib doesn't support HTTPS"
)
)
else:
return HTTPS(host, None, **(x509 or {}))
chost, self._extra_headers, x509 = self.get_host_info(host)
self._connection = host, HTTPS(chost, None, **(x509 or {}))
return self._connection[1]
##
# Standard server proxy. This class establishes a virtual connection
@@ -1409,11 +1548,14 @@ class ServerProxy:
allow_none=0, use_datetime=0):
# establish a "logical" server connection
if isinstance(uri, unicode):
uri = uri.encode('ISO-8859-1')
# get the url
import urllib
type, uri = urllib.splittype(uri)
if type not in ("http", "https"):
raise IOError("unsupported XML-RPC protocol")
raise IOError, "unsupported XML-RPC protocol"
self.__host, self.__handler = urllib.splithost(uri)
if not self.__handler:
self.__handler = "/RPC2"
@@ -1429,6 +1571,9 @@ class ServerProxy:
self.__verbose = verbose
self.__allow_none = allow_none
def __close(self):
self.__transport.close()
def __request(self, methodname, params):
# call a method on the remote server
@@ -1440,7 +1585,7 @@ class ServerProxy:
self.__handler,
request,
verbose=self.__verbose
)
)
if len(response) == 1:
response = response[0]
@@ -1449,9 +1594,9 @@ class ServerProxy:
def __repr__(self):
return (
"<ServerProxy for %s%s>" %
(self.__host, self.__handler)
)
"<ServerProxy for %s%s>" %
(self.__host, self.__handler)
)
__str__ = __repr__
@@ -1462,6 +1607,16 @@ class ServerProxy:
# note: to call a remote object with an non-standard name, use
# result getattr(server, "strange-python-name")(args)
def __call__(self, attr):
"""A workaround to get special attributes on the ServerProxy
without interfering with the magic __getattr__
"""
if attr == "close":
return self.__close
elif attr == "transport":
return self.__transport
raise AttributeError("Attribute %r not found" % (attr,))
# compatibility
Server = ServerProxy
@@ -1471,23 +1626,16 @@ Server = ServerProxy
if __name__ == "__main__":
# simple test program (from the XML-RPC specification)
server = ServerProxy("http://localhost:8000")
# server = ServerProxy("http://localhost:8000") # local server
server = ServerProxy("http://time.xmlrpc.com/RPC2")
sys.stdout.write('%s\n' % server)
try:
sys.stdout.write('%s\n' % (server.currentTime.getCurrentTime(),))
except Error:
import traceback;traceback.print_exc()
print server
multi = MultiCall(server)
multi.currentTime.getCurrentTime()
multi.currentTime.getCurrentTime()
multi.pow(2, 9)
multi.add(5, 1)
multi.add(24, 11)
try:
for response in multi():
sys.stdout.write('%s\n' % (response,))
except Error:
import traceback;traceback.print_exc()
print response
except Error, v:
print "ERROR", v
@@ -102,23 +102,23 @@ def _maybe_compile(compiler, source, filename, symbol):
try:
code = compiler(source, filename, symbol)
except SyntaxError, err:
except SyntaxError:
pass
try:
code1 = compiler(source + "\n", filename, symbol)
except SyntaxError, err1:
except SyntaxError as err1:
pass
try:
code2 = compiler(source + "\n\n", filename, symbol)
except SyntaxError, err2:
except SyntaxError as err2:
pass
if code:
return code
if not code1 and repr(err1) == repr(err2):
raise SyntaxError, err1
raise SyntaxError(err1)
def _compile(source, filename, symbol):
return compile(source, filename, symbol, PyCF_DONT_IMPLY_DEDENT)
@@ -37,7 +37,6 @@ DONT_TRACE = {
'_pydev_saved_modules.py': PYDEV_FILE,
'_pydev_sys_patch.py': PYDEV_FILE,
'_pydev_tipper_common.py': PYDEV_FILE,
'_pydev_uuid_old.py': PYDEV_FILE,
'_pydev_xmlrpclib.py': PYDEV_FILE,
'django_debug.py': PYDEV_FILE,
'fix_getpass.py': PYDEV_FILE,
@@ -99,6 +98,7 @@ DONT_TRACE = {
'pydevd_plugin_utils.py': PYDEV_FILE,
'pydevd_plugins_django_form_str.py': PYDEV_FILE,
'pydevd_process_net_command.py': PYDEV_FILE,
'pydevd_pycharm.py': PYDEV_FILE,
'pydevd_referrers.py': PYDEV_FILE,
'pydevd_reload.py': PYDEV_FILE,
'pydevd_resolver.py': PYDEV_FILE,
@@ -106,6 +106,7 @@ DONT_TRACE = {
'pydevd_signature.py': PYDEV_FILE,
'pydevd_stackless.py': PYDEV_FILE,
'pydevd_thread_wrappers.py': PYDEV_FILE,
'pydevd_thrift.py': PYDEV_FILE,
'pydevd_trace_api.py': PYDEV_FILE,
'pydevd_trace_dispatch.py': PYDEV_FILE,
'pydevd_trace_dispatch_regular.py': PYDEV_FILE,
@@ -95,7 +95,7 @@ def glut_close():
def glut_int_handler(signum, frame):
# Catch sigint and print the defautl message
signal.signal(signal.SIGINT, signal.default_int_handler)
print '\nKeyboardInterrupt'
print('\nKeyboardInterrupt')
# Need to reprint the prompt at this stage
@@ -1,2 +1,2 @@
import add_code_to_python_process
print add_code_to_python_process.run_python_code(3736, "print(20)", connect_debugger_tracing=False)
print(add_code_to_python_process.run_python_code(3736, "print(20)", connect_debugger_tracing=False))
@@ -34,8 +34,8 @@ __revision__ = "$Id$"
def do(self, arg):
".example - This is an example plugin for the command line debugger"
print "This is an example command."
print "%s.do(%r, %r):" % (__name__, self, arg)
print " last event", self.lastEvent
print " prefix", self.cmdprefix
print " arguments", self.split_tokens(arg)
print("This is an example command.")
print("%s.do(%r, %r):" % (__name__, self, arg))
print(" last event", self.lastEvent)
print(" prefix", self.cmdprefix)
print(" arguments", self.split_tokens(arg))
@@ -37,8 +37,7 @@ from winappdbg import HexDump, Table
def do(self, arg):
".exchain - Show the SEH chain"
thread = self.get_thread_from_prefix()
print "Exception handlers for thread %d" % thread.get_tid()
print
print("Exception handlers for thread %d" % thread.get_tid())
table = Table()
table.addRow("Block", "Function")
bits = thread.get_bits()
@@ -48,4 +47,4 @@ def do(self, arg):
if seh_func is not None:
seh_func = HexDump.address(seh_func, bits)
table.addRow(seh, seh_func)
print table.getOutput()
print(table.getOutput())
@@ -43,8 +43,8 @@ def do(self, arg):
status, rule, description = crash.isExploitable()
print "-" * 79
print "Exploitability: %s" % status
print "Matched rule: %s" % rule
print "Description: %s" % description
print "-" * 79
print("-" * 79)
print("Exploitability: %s" % status)
print("Matched rule: %s" % rule)
print("Description: %s" % description)
print("-" * 79)
+3
View File
@@ -0,0 +1,3 @@
# make settrace() function available for `pydevd_pycharm`
from pydevd import settrace
+62 -24
View File
@@ -69,6 +69,7 @@ from setuptools import setup
from setuptools.dist import Distribution
from distutils.extension import Extension
import os
import sys
class BinaryDistribution(Distribution):
def is_pure(self):
@@ -84,21 +85,45 @@ def accept_file(f):
return f in ['readme', 'makefile']
data_files.append(('pydevd_attach_to_process', [os.path.join('pydevd_attach_to_process', f) for f in os.listdir('pydevd_attach_to_process') if accept_file(f)]))
for root, dirs, files in os.walk("pydevd_attach_to_process"):
for d in dirs:
data_files.append((os.path.join(root, d), [os.path.join(root, d, f) for f in os.listdir(os.path.join(root, d)) if accept_file(f)]))
import pydevd
version = pydevd.__version__
def add_directory_to_datafiles(datafiles, dir):
datafiles.append((dir, [os.path.join(dir, f) for f in os.listdir(dir) if accept_file(f)]))
for root, dirs, files in os.walk(dir):
for d in dirs:
datafiles.append((os.path.join(root, d), [os.path.join(root, d, f) for f in os.listdir(os.path.join(root, d)) if accept_file(f)]))
def accept_extension(f):
f = f.lower()
for ext in '.pyd .so'.split():
if f.endswith(ext):
return True
return False
def add_extensions_to_datafiles(datafiles, dir):
datafiles.append((dir, [os.path.join(dir, f) for f in os.listdir(dir) if accept_extension(f)]))
add_directory_to_datafiles(data_files, 'pydevd_attach_to_process')
add_extensions_to_datafiles(data_files, '_pydevd_bundle')
add_extensions_to_datafiles(data_files, '_pydevd_frame_eval')
def get_version_from_file():
with open(os.path.join(os.path.dirname(os.path.abspath(__file__)), 'VERSION')) as version_file:
version = version_file.read().strip()
return version
version = get_version_from_file()
args = dict(
name='pydevd',
name='pydevd-pycharm',
version=version,
description = 'PyDev.Debugger (used in PyDev and PyCharm)',
author='Fabio Zadrozny and others',
url='https://github.com/fabioz/PyDev.Debugger/',
license='EPL (Eclipse Public License)',
description = 'PyCharm Debugger (used in PyCharm and PyDev)',
author='JetBrains, Fabio Zadrozny and others',
url='https://github.com/JetBrains/intellij-community',
license='Apache 2.0',
packages=[
'_pydev_bundle',
'_pydev_imps',
@@ -106,11 +131,8 @@ args = dict(
'_pydevd_bundle',
'_pydevd_frame_eval',
'pydev_ipython',
# 'pydev_sitecustomize', -- Not actually a package (not added)
# 'pydevd_attach_to_process', -- Not actually a package (included in MANIFEST.in)
'pydevd_concurrency_analyser',
'pydevd_plugins',
'pydevd_plugins.extensions',
@@ -124,9 +146,10 @@ args = dict(
'pydevconsole',
'pydevd_file_utils',
'pydevd',
'pydevd_pycharm',
'pydevd_tracing',
# 'runfiles', -- Not needed for debugger
# 'setup_cython', -- Should not be included as a module
'setup_cython', # Distributed to clients. See: https://github.com/fabioz/PyDev.Debugger/issues/102
# 'setup', -- Should not be included as a module
],
classifiers=[
@@ -134,14 +157,19 @@ args = dict(
'Environment :: Console',
'Intended Audience :: Developers',
# It seems that the license is not recognized by Pypi, so, not categorizing it for now.
# https://bitbucket.org/pypa/pypi/issues/369/the-eclipse-public-license-superseeded
# 'License :: OSI Approved :: Eclipse Public License',
'Apache Software License (Apache License 2.0)',
'Operating System :: MacOS :: MacOS X',
'Operating System :: Microsoft :: Windows',
'Operating System :: POSIX',
'Programming Language :: Python',
'Programming Language :: Python :: 2',
'Programming Language :: Python :: 2.7',
'Programming Language :: Python :: 3',
'Programming Language :: Python :: 3.4',
'Programming Language :: Python :: 3.5',
'Programming Language :: Python :: 3.6',
'Programming Language :: Python :: 3.7',
'Topic :: Software Development :: Debuggers',
],
entry_points={
@@ -150,26 +178,36 @@ args = dict(
],
},
data_files=data_files,
keywords=['pydev', 'pydevd', 'pydev.debugger'],
keywords=['pydev', 'pydevd', 'pydev.debugger', 'pycharm'],
include_package_data=True,
zip_safe=False,
)
args_with_binaries = args.copy()
import sys
try:
args_with_binaries = args.copy()
if sys.platform not in ('darwin', 'win32'):
args_with_binaries.update(dict(
distclass=BinaryDistribution,
ext_modules=[
# In this setup, don't even try to compile with cython, just go with the .c file which should've
# been properly generated from a tested version.
Extension('_pydevd_bundle.pydevd_cython', ["_pydevd_bundle/pydevd_cython.c",])
Extension('_pydevd_bundle.pydevd_cython', ['_pydevd_bundle/pydevd_cython.c',])
]
))
if sys.version_info >= (3, 6):
args_with_binaries.update(dict(
distclass=BinaryDistribution,
ext_modules=[
# In this setup, don't even try to compile with cython, just go with the .c file which should've
# been properly generated from a tested version.
Extension('_pydevd_frame_eval.pydevd_frame_evaluator', ['_pydevd_frame_eval/pydevd_frame_evaluator.c',])
]
))
try:
setup(**args_with_binaries)
except:
# Compile failed: just setup without compiling cython deps.
setup(**args)
sys.stdout.write('Plain-python version of pydevd installed (cython speedups not available).\n')
sys.stdout.write('Plain-python version of pydevd-pycharm installed (cython speedups not available).\n')
+1 -1
View File
@@ -277,4 +277,4 @@ def %(method_name)s%(args)s:
for line in doc.splitlines():
lines.append(' ' + line)
doc = '\n'.join(lines)
print temp % dict(method_name=entry[0], args=entry[2] or '(self)', doc=doc)
print(temp % dict(method_name=entry[0], args=entry[2] or '(self)', doc=doc))
@@ -902,10 +902,11 @@ debug.notification.group=Python Debugger
debug.notification.title.connection.failed=Connection to Python debugger failed
remote.debug.info=Info
remote.debug.server.hint=Launch this debug configuration to start the debug server.
remote.debug.server.hint=Launch this debug configuration to start the Debug Server.
remote.debug.server.hint1.5=Update your script:
remote.debug.server.hint2=1. Add pycharm-debug.egg from the PyCharm installation to the Python path.
remote.debug.server.hint3=2. Add the following command to connect to the debug server:
remote.debug.server.hint2=1. Add pydevd-pycharm.egg from the PyCharm installation to the Python path or execute:
remote.debug.server.hint3=pip install pydevd-pycharm
remote.debug.server.hint4=2. Add the following command to connect to the Debug Server:
remote.debug.settings=Settings
remote.debug.remote.host=Remote host
remote.debug.port=Port: