[Ironpython-users] Differences with pyc-compiled assemblies?

Nicholas Devenish misnomer at gmail.com
Mon Nov 12 02:43:46 CET 2012


On 11 Nov 2012, at 23:06, Jeff Hardy <jdhardy at gmail.com> wrote:
> SQLAlchemy works on IronPython? I didn't know that. Very cool. Is
> there anything that has to be done or does it just work out of the
> box?

It's supposed to work out of the box - one of the reasons I decided to go with IronPython for my current project. I haven't stress tested it, but importing the (source) package and running some simple operations on an in-memory sqlite database all works without issue.

>> Traceback (most recent call last):
>>  File "<stdin>", line 1, in <module>
>>  File "sqlalchemy\__init__.py", line 52, in <module>
>>  File "sqlalchemy\types", line 27, in <module>
>>  File "sqlalchemy\schema", line 2670, in <module>
>>  File "sqlalchemy\schema", line 2706, in DDLElement
>>  File "sqlalchemy\util\deprecations", line 45, in decorate
>>  File "sqlalchemy\util\deprecations", line 116, in _decorate_with_warning
>>  File "sqlalchemy\util\langhelpers", line 41, in decorate
>>  File "c:\Program Files\IronPython 2.7\Lib\inspect.py", line 814, in getargspec
>>  File "c:\Program Files\IronPython 2.7\Lib\inspect.py", line 758, in getargs
>> IndexError: index out of range: 2
> In inspect.py, just before line 758, it looks at co.co_argcount and
> co.co_varnames and assumes that they are the same length, but my guess
> is that they might not be when compiled with pyc. If you can figure
> out exactly what getargspec is being called on, that might help make a
> simpler reproduction that I can work off of.

So, I've traced down the stack trace with some tested output. This is what it seems to be doing:

> Starting with the wrapped function (though the line number seems off slightly, 
> everything else in the stack trace and debug output before the exception matches
> up exactly):
> 
>     @util.deprecated("0.7", "(deprecated message)")
>     def execute_at(self, event_name, target):
>         def call_event(target, connection, **kw):
>             if self._should_execute_deprecated(event_name,
>                                     target, connection, **kw):
>                 return connection.execute(self.against(target))
>         event.listen(target, "" + event_name.replace('-', '_'), call_event)
> 
> 
> the deprecated decorator returns this function as the decorator:
> 
>     def decorate(fn):
>         print "In deprecated decorator: {}, {}".format(fn, message % dict(func=fn.__name__))
>         return _decorate_with_warning(
>             fn, exc.SADeprecationWarning,
>             message % dict(func=fn.__name__), header)
> 
> and this calls through to _decorate_with_warning:
> 
>     def _decorate_with_warning(func, wtype, message, docstring_header=None):
>         ...
>         @decorator
>         def warned(fn, *args, **kwargs):
>             warnings.warn(wtype(message), stacklevel=3)
>             return fn(*args, **kwargs)
> 
>         decorated = warned(func)
>         ... (above line triggers the decorator)
> 
> 
> The @decorator is:
> 
>     def decorator(target):
>         """A signature-matching decorator factory."""
> 
>         def decorate(fn):
>             if not inspect.isfunction(fn):
>                 raise Exception("not a decoratable function")
>             print "Decorating: {}".format(fn)
>             spec = inspect_getfullargspec(fn)
>             .........
>         return update_wrapper(decorate, target)
>         # update_wrapper is from python's functools
> 
> And decorate calls through into inspect.py's aliased getfullargspec:
> 
>     def getargspec(func):
>         if ismethod(func):
>             func = func.im_func
>         if not isfunction(func):
>             raise TypeError('{!r} is not a Python function'.format(func))
>         args, varargs, varkw = getargs(func.func_code)
> 
> That calls getargs:
> 
>     def getargs(co):
>         if not iscode(co):
>             raise TypeError('{!r} is not a code object'.format(co))
> 
>         nargs = co.co_argcount
>         names = co.co_varnames
>         args = list(names[:nargs])
>         step = 0
> 
>         for i in range(nargs):
>             if args[i][:1] in ('', '.'):
> 
> With values for the variables:
> 
>     print "getargs:"
>     print " args:  {}".format(args)
>     print " nargs: {}".format(nargs)
>     print " names: {}".format(names)
> 
> And the output from these print statements:
> 
>     getargs:
>      args:  ['target', 'call_event']
>      nargs: 3
>      names: ('target', 'call_event')


Is this any help? It's 2am now, but I'll continue poking at this tomorrow.

Thanks,

Nick


More information about the Ironpython-users mailing list