mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
PY-27650 Create a pip package consistent with PyCharm updates
This commit is contained in:
@@ -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:
|
||||
|
||||
@@ -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
|
||||
@@ -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))
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
|
||||
# make settrace() function available for `pydevd_pycharm`
|
||||
from pydevd import settrace
|
||||
@@ -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')
|
||||
|
||||
@@ -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:
|
||||
|
||||
Reference in New Issue
Block a user