def next_w(self, space): w_line = space.call_method(self, "readline") if space.len_w(w_line) == 0: raise OperationError(space.w_StopIteration, space.w_None) return w_line
def wrap(self, x): "Wraps the Python value 'x' into one of the wrapper classes." # You might notice that this function is rather conspicuously # not RPython. We can get away with this because the function # is specialized (see after the function body). Also worth # noting is that the isinstance's involving integer types # behave rather differently to how you might expect during # annotation (see pypy/annotation/builtin.py) if x is None: return self.w_None if isinstance(x, W_Object): raise TypeError, "attempt to wrap already wrapped object: %s" % ( x, ) if isinstance(x, OperationError): raise TypeError, ("attempt to wrap already wrapped exception: %s" % (x, )) if isinstance(x, int): if isinstance(x, bool): return self.newbool(x) else: return self.newint(x) if isinstance(x, str): from pypy.objspace.std.stringtype import wrapstr return wrapstr(self, x) if isinstance(x, unicode): from pypy.objspace.std.unicodetype import wrapunicode return wrapunicode(self, x) if isinstance(x, float): return W_FloatObject(x) if isinstance(x, Wrappable): w_result = x.__spacebind__(self) #print 'wrapping', x, '->', w_result return w_result if isinstance(x, base_int): return W_LongObject.fromrarith_int(x) # _____ below here is where the annotator should not get _____ # wrap() of a container works on CPython, but the code is # not RPython. Don't use -- it is kept around mostly for tests. # Use instead newdict(), newlist(), newtuple(). if isinstance(x, dict): items_w = [(self.wrap(k), self.wrap(v)) for (k, v) in x.iteritems()] r = self.newdict() r.initialize_content(items_w) return r if isinstance(x, tuple): wrappeditems = [self.wrap(item) for item in list(x)] return self.newtuple(wrappeditems) if isinstance(x, list): wrappeditems = [self.wrap(item) for item in x] return self.newlist(wrappeditems) # The following cases are even stranger. # Really really only for tests. if type(x) is long: return W_LongObject.fromlong(x) if isinstance(x, slice): return W_SliceObject(self.wrap(x.start), self.wrap(x.stop), self.wrap(x.step)) if isinstance(x, complex): return W_ComplexObject(x.real, x.imag) if isinstance(x, set): wrappeditems = [self.wrap(item) for item in x] return W_SetObject(self, wrappeditems) if isinstance(x, frozenset): wrappeditems = [self.wrap(item) for item in x] return W_FrozensetObject(self, wrappeditems) if x is __builtin__.Ellipsis: # '__builtin__.Ellipsis' avoids confusion with special.Ellipsis return self.w_Ellipsis if self.config.objspace.nofaking: # annotation should actually not get here. If it does, you get # an error during rtyping because '%r' is not supported. It tells # you that there was a space.wrap() on a strange object. raise OperationError( self.w_RuntimeError, self.wrap("nofaking enabled: refusing " "to wrap cpython value %r" % (x, ))) if isinstance(x, type(Exception)) and issubclass(x, Exception): w_result = self.wrap_exception_cls(x) if w_result is not None: return w_result #print "fake-wrapping", x from fake import fake_object return fake_object(self, x)
def check_class(space, w_obj, msg): if not abstract_isclass_w(space, w_obj): raise OperationError(space.w_TypeError, space.newtext(msg))
def fget(space, obj): w_value = getattr(obj, name) if w_value is None: raise OperationError(space.w_AttributeError, space.newtext(name)) else: return w_value
def fdel(space, obj): w_value = getattr(obj, name) if w_value is None: raise OperationError(space.w_AttributeError, space.newtext(name)) setattr(obj, name, None)
def coerce(space, w_obj1, w_obj2): w_res = space.try_coerce(w_obj1, w_obj2) if w_res is None: raise OperationError(space.w_TypeError, space.wrap("coercion failed")) return w_res
class PyFrame(eval.Frame): """Represents a frame for a regular Python function that needs to be interpreted. See also pyopcode.PyStandardFrame and pynestedscope.PyNestedScopeFrame. Public fields: * 'space' is the object space this frame is running in * 'code' is the PyCode object this frame runs * 'w_locals' is the locals dictionary to use * 'w_globals' is the attached globals dictionary * 'builtin' is the attached built-in module * 'valuestack_w', 'blockstack', control the interpretation """ __metaclass__ = extendabletype frame_finished_execution = False last_instr = -1 last_exception = None f_back = None w_f_trace = None # For tracing instr_lb = 0 instr_ub = -1 instr_prev = -1 def __init__(self, space, code, w_globals, closure): self = hint(self, access_directly=True) assert isinstance(code, pycode.PyCode) self.pycode = code eval.Frame.__init__(self, space, w_globals, code.co_nlocals) self.valuestack_w = [None] * code.co_stacksize self.valuestackdepth = 0 self.blockstack = [] if space.config.objspace.honor__builtins__: self.builtin = space.builtin.pick_builtin(w_globals) # regular functions always have CO_OPTIMIZED and CO_NEWLOCALS. # class bodies only have CO_NEWLOCALS. self.initialize_frame_scopes(closure) self.fastlocals_w = [None] * self.numlocals self.f_lineno = self.pycode.co_firstlineno def get_builtin(self): if self.space.config.objspace.honor__builtins__: return self.builtin else: return self.space.builtin def initialize_frame_scopes(self, closure): # regular functions always have CO_OPTIMIZED and CO_NEWLOCALS. # class bodies only have CO_NEWLOCALS. # CO_NEWLOCALS: make a locals dict unless optimized is also set # CO_OPTIMIZED: no locals dict needed at all # NB: this method is overridden in nestedscope.py flags = self.pycode.co_flags if flags & pycode.CO_OPTIMIZED: return if flags & pycode.CO_NEWLOCALS: self.w_locals = self.space.newdict() else: assert self.w_globals is not None self.w_locals = self.w_globals def run(self): """Start this frame's execution.""" if self.pycode.co_flags & pycode.CO_GENERATOR: from pypy.interpreter.generator import GeneratorIterator return self.space.wrap(GeneratorIterator(self)) else: return self.execute_frame() def execute_generator_frame(self, w_inputvalue): # opcode semantic change in CPython 2.5: we must pass an input value # when resuming a generator, which goes into the value stack. # (it's always w_None for now - not implemented in generator.py) if self.pycode.magic >= 0xa0df294 and self.last_instr != -1: self.pushvalue(w_inputvalue) return self.execute_frame() def execute_frame(self): """Execute this frame. Main entry point to the interpreter.""" from pypy.rlib import rstack # the following 'assert' is an annotation hint: it hides from # the annotator all methods that are defined in PyFrame but # overridden in the FrameClass subclass of PyFrame. assert isinstance(self, self.space.FrameClass) executioncontext = self.space.getexecutioncontext() executioncontext.enter(self) try: executioncontext.call_trace(self) # Execution starts just after the last_instr. Initially, # last_instr is -1. After a generator suspends it points to # the YIELD_VALUE instruction. next_instr = self.last_instr + 1 w_exitvalue = self.dispatch(self.pycode, next_instr, executioncontext) rstack.resume_point("execute_frame", self, executioncontext, returns=w_exitvalue) executioncontext.return_trace(self, w_exitvalue) # on exit, we try to release self.last_exception -- breaks an # obvious reference cycle, so it helps refcounting implementations self.last_exception = None finally: executioncontext.leave(self) return w_exitvalue execute_frame.insert_stack_check_here = True # stack manipulation helpers def pushvalue(self, w_object): depth = self.valuestackdepth self.valuestack_w[depth] = w_object self.valuestackdepth = depth + 1 def popvalue(self): depth = self.valuestackdepth - 1 assert depth >= 0, "pop from empty value stack" w_object = self.valuestack_w[depth] self.valuestack_w[depth] = None self.valuestackdepth = depth return w_object def popstrdictvalues(self, n): dic_w = {} while True: n -= 1 if n < 0: break hint(n, concrete=True) w_value = self.popvalue() w_key = self.popvalue() key = self.space.str_w(w_key) dic_w[key] = w_value return dic_w def popvalues(self, n): values_w = [None] * n while True: n -= 1 if n < 0: break hint(n, concrete=True) values_w[n] = self.popvalue() return values_w def peekvalues(self, n): values_w = [None] * n base = self.valuestackdepth - n assert base >= 0 while True: n -= 1 if n < 0: break hint(n, concrete=True) values_w[n] = self.valuestack_w[base + n] return values_w def dropvalues(self, n): finaldepth = self.valuestackdepth - n assert finaldepth >= 0, "stack underflow in dropvalues()" while True: n -= 1 if n < 0: break hint(n, concrete=True) self.valuestack_w[finaldepth + n] = None self.valuestackdepth = finaldepth def pushrevvalues(self, n, values_w): # n should be len(values_w) while True: n -= 1 if n < 0: break hint(n, concrete=True) self.pushvalue(values_w[n]) def dupvalues(self, n): delta = n - 1 while True: n -= 1 if n < 0: break hint(n, concrete=True) w_value = self.peekvalue(delta) self.pushvalue(w_value) def peekvalue(self, index_from_top=0): index = self.valuestackdepth + ~index_from_top assert index >= 0, "peek past the bottom of the stack" return self.valuestack_w[index] def settopvalue(self, w_object, index_from_top=0): index = self.valuestackdepth + ~index_from_top assert index >= 0, "settop past the bottom of the stack" self.valuestack_w[index] = w_object def dropvaluesuntil(self, finaldepth): depth = self.valuestackdepth - 1 while depth >= finaldepth: self.valuestack_w[depth] = None depth -= 1 self.valuestackdepth = finaldepth def savevaluestack(self): return self.valuestack_w[:self.valuestackdepth] def restorevaluestack(self, items_w): assert None not in items_w self.valuestack_w[:len(items_w)] = items_w self.dropvaluesuntil(len(items_w)) def make_arguments(self, nargs): if we_are_jitted(): return Arguments(self.space, self.peekvalues(nargs)) else: return ArgumentsFromValuestack(self.space, self, nargs) def descr__reduce__(self, space): from pypy.interpreter.mixedmodule import MixedModule from pypy.module._pickle_support import maker # helper fns w_mod = space.getbuiltinmodule('_pickle_support') mod = space.interp_w(MixedModule, w_mod) new_inst = mod.get('frame_new') w = space.wrap nt = space.newtuple cells = self._getcells() if cells is None: w_cells = space.w_None else: w_cells = space.newlist([space.wrap(cell) for cell in cells]) if self.w_f_trace is None: f_lineno = self.get_last_lineno() else: f_lineno = self.f_lineno values_w = self.valuestack_w[0:self.valuestackdepth] w_valuestack = maker.slp_into_tuple_with_nulls(space, values_w) w_blockstack = nt( [block._get_state_(space) for block in self.blockstack]) w_fastlocals = maker.slp_into_tuple_with_nulls(space, self.fastlocals_w) if self.last_exception is None: w_exc_value = space.w_None w_tb = space.w_None else: w_exc_value = self.last_exception.w_value w_tb = w(self.last_exception.application_traceback) tup_state = [ w(self.f_back), w(self.get_builtin()), w(self.pycode), w_valuestack, w_blockstack, w_exc_value, # last_exception w_tb, # self.w_globals, w(self.last_instr), w(self.frame_finished_execution), w(f_lineno), w_fastlocals, space.w_None, #XXX placeholder for f_locals #f_restricted requires no additional data! space.w_None, ## self.w_f_trace, ignore for now w(self.instr_lb), #do we need these three (that are for tracing) w(self.instr_ub), w(self.instr_prev), w_cells, ] return nt([new_inst, nt([]), nt(tup_state)]) def descr__setstate__(self, space, w_args): from pypy.module._pickle_support import maker # helper fns from pypy.interpreter.pycode import PyCode from pypy.interpreter.module import Module args_w = space.unpackiterable(w_args) w_f_back, w_builtin, w_pycode, w_valuestack, w_blockstack, w_exc_value, w_tb,\ w_globals, w_last_instr, w_finished, w_f_lineno, w_fastlocals, w_f_locals, \ w_f_trace, w_instr_lb, w_instr_ub, w_instr_prev, w_cells = args_w new_frame = self pycode = space.interp_w(PyCode, w_pycode) if space.is_w(w_cells, space.w_None): closure = None cellvars = [] else: from pypy.interpreter.nestedscope import Cell cells_w = space.unpackiterable(w_cells) cells = [space.interp_w(Cell, w_cell) for w_cell in cells_w] ncellvars = len(pycode.co_cellvars) cellvars = cells[:ncellvars] closure = cells[ncellvars:] # do not use the instance's __init__ but the base's, because we set # everything like cells from here PyFrame.__init__(self, space, pycode, w_globals, closure) new_frame.f_back = space.interp_w(PyFrame, w_f_back, can_be_None=True) new_frame.builtin = space.interp_w(Module, w_builtin) new_frame.blockstack = [ unpickle_block(space, w_blk) for w_blk in space.unpackiterable(w_blockstack) ] values_w = maker.slp_from_tuple_with_nulls(space, w_valuestack) for w_value in values_w: new_frame.pushvalue(w_value) if space.is_w(w_exc_value, space.w_None): new_frame.last_exception = None else: from pypy.interpreter.pytraceback import PyTraceback tb = space.interp_w(PyTraceback, w_tb) new_frame.last_exception = OperationError(space.type(w_exc_value), w_exc_value, tb) new_frame.last_instr = space.int_w(w_last_instr) new_frame.frame_finished_execution = space.is_true(w_finished) new_frame.f_lineno = space.int_w(w_f_lineno) new_frame.fastlocals_w = maker.slp_from_tuple_with_nulls( space, w_fastlocals) if space.is_w(w_f_trace, space.w_None): new_frame.w_f_trace = None else: new_frame.w_f_trace = w_f_trace new_frame.instr_lb = space.int_w(w_instr_lb) #the three for tracing new_frame.instr_ub = space.int_w(w_instr_ub) new_frame.instr_prev = space.int_w(w_instr_prev) self._setcellvars(cellvars) space.frame_trace_action.fire() def hide(self): return self.pycode.hidden_applevel def getcode(self): return hint(hint(self.pycode, promote=True), deepfreeze=True) def getfastscope(self): "Get the fast locals as a list." return self.fastlocals_w def setfastscope(self, scope_w): """Initialize the fast locals from a list of values, where the order is according to self.pycode.signature().""" scope_len = len(scope_w) if scope_len > len(self.fastlocals_w): raise ValueError, "new fastscope is longer than the allocated area" self.fastlocals_w[:scope_len] = scope_w self.init_cells() def init_cells(self): """Initialize cellvars from self.fastlocals_w This is overridden in nestedscope.py""" pass def getclosure(self): return None def _getcells(self): return None def _setcellvars(self, cellvars): pass ### line numbers ### # for f*_f_* unwrapping through unwrap_spec in typedef.py def fget_f_lineno(space, self): "Returns the line number of the instruction currently being executed." if self.w_f_trace is None: return space.wrap(self.get_last_lineno()) else: return space.wrap(self.f_lineno) def fset_f_lineno(space, self, w_new_lineno): "Returns the line number of the instruction currently being executed." try: new_lineno = space.int_w(w_new_lineno) except OperationError, e: raise OperationError(space.w_ValueError, space.wrap("lineno must be an integer")) if self.w_f_trace is None: raise OperationError( space.w_ValueError, space.wrap("f_lineo can only be set by a trace function.")) if new_lineno < self.pycode.co_firstlineno: raise OperationError( space.w_ValueError, space.wrap("line %d comes before the current code." % new_lineno)) code = self.pycode.co_code addr = 0 line = self.pycode.co_firstlineno new_lasti = -1 offset = 0 lnotab = self.pycode.co_lnotab for offset in xrange(0, len(lnotab), 2): addr += ord(lnotab[offset]) line += ord(lnotab[offset + 1]) if line >= new_lineno: new_lasti = addr new_lineno = line break if new_lasti == -1: raise OperationError( space.w_ValueError, space.wrap("line %d comes after the current code." % new_lineno)) # Don't jump to a line with an except in it. if ord(code[new_lasti]) in (DUP_TOP, POP_TOP): raise OperationError( space.w_ValueError, space.wrap( "can't jump to 'except' line as there's no exception")) # Don't jump into or out of a finally block. f_lasti_setup_addr = -1 new_lasti_setup_addr = -1 blockstack = [] addr = 0 while addr < len(code): op = ord(code[addr]) if op in (SETUP_LOOP, SETUP_EXCEPT, SETUP_FINALLY): blockstack.append([addr, False]) elif op == POP_BLOCK: setup_op = ord(code[blockstack[-1][0]]) if setup_op == SETUP_FINALLY: blockstack[-1][1] = True else: blockstack.pop() elif op == END_FINALLY: if len(blockstack) > 0: setup_op = ord(code[blockstack[-1][0]]) if setup_op == SETUP_FINALLY: blockstack.pop() if addr == new_lasti or addr == self.last_instr: for ii in range(len(blockstack)): setup_addr, in_finally = blockstack[~ii] if in_finally: if addr == new_lasti: new_lasti_setup_addr = setup_addr if addr == self.last_instr: f_lasti_setup_addr = setup_addr break if op >= HAVE_ARGUMENT: addr += 3 else: addr += 1 assert len(blockstack) == 0 if new_lasti_setup_addr != f_lasti_setup_addr: raise OperationError( space.w_ValueError, space.wrap( "can't jump into or out of a 'finally' block %d -> %d" % (f_lasti_setup_addr, new_lasti_setup_addr))) if new_lasti < self.last_instr: min_addr = new_lasti max_addr = self.last_instr else: min_addr = self.last_instr max_addr = new_lasti delta_iblock = min_delta_iblock = 0 addr = min_addr while addr < max_addr: op = ord(code[addr]) if op in (SETUP_LOOP, SETUP_EXCEPT, SETUP_FINALLY): delta_iblock += 1 elif op == POP_BLOCK: delta_iblock -= 1 if delta_iblock < min_delta_iblock: min_delta_iblock = delta_iblock if op >= opcode.HAVE_ARGUMENT: addr += 3 else: addr += 1 f_iblock = len(self.blockstack) min_iblock = f_iblock + min_delta_iblock if new_lasti > self.last_instr: new_iblock = f_iblock + delta_iblock else: new_iblock = f_iblock - delta_iblock if new_iblock > min_iblock: raise OperationError( space.w_ValueError, space.wrap("can't jump into the middle of a block")) while f_iblock > new_iblock: block = self.blockstack.pop() block.cleanup(self) f_iblock -= 1 self.f_lineno = new_lineno self.last_instr = new_lasti
def typeoffsetof_field(self, fieldname, following): space = self.space msg = "with a field name argument, expected a struct or union ctype" raise OperationError(space.w_TypeError, space.wrap(msg))
def typeoffsetof_index(self, index): space = self.space msg = "with an integer argument, expected an array or pointer ctype" raise OperationError(space.w_TypeError, space.wrap(msg))
def raiseWindowsError(space, errcode, context): message = rwin32.FormatError(errcode) raise OperationError( space.w_WindowsError, space.newtuple2(space.newint(errcode), space.newtext(message)))
def digest_type_by_name(self, space): digest_type = ropenssl.EVP_get_digestbyname(self.name) if not digest_type: raise OperationError(space.w_ValueError, space.wrap("unknown hash function")) return digest_type
raise raise OperationError(space.w_ValueError, space.wrap("__package__ set to non-string")) if ctxt_package is not None: # __package__ is set, so use it if ctxt_package == '' and level < 0: return None, 0 dot_position = _get_dot_position(ctxt_package, level - 1) if dot_position < 0: if len(ctxt_package) == 0: msg = "Attempted relative import in non-package" else: msg = "Attempted relative import beyond toplevel package" raise OperationError(space.w_ValueError, w(msg)) # Try to import parent package try: absolute_import(space, ctxt_package, 0, None, tentative=False) except OperationError, e: if not e.match(space, space.w_ImportError): raise if level > 0: raise OperationError( space.w_SystemError, space.wrap("Parent module '%s' not loaded, " "cannot perform relative import" % ctxt_package)) else: msg = ("Parent module '%s' not found while handling absolute "
def handle_exception(self, space, e): try: if not we_are_translated(): raise raise e except KeyboardInterrupt: raise OperationError(space.w_KeyboardInterrupt, space.w_None) except MemoryError: raise OperationError(space.w_MemoryError, space.w_None) except rstackovf.StackOverflow, e: rstackovf.check_stack_overflow() raise space.prebuilt_recursion_error except RuntimeError: # not on top of py.py raise OperationError(space.w_RuntimeError, space.w_None) # (verbose) performance hack below class BuiltinCodePassThroughArguments0(BuiltinCode): _immutable_ = True def funcrun(self, func, args): space = func.space try: w_result = self.func__args__(space, args) except DescrMismatch: return args.firstarg().descr_call_mismatch(space, self.descrmismatch_op, self.descr_reqcls, args)
def unsupported(space, message): w_exc = space.getattr(space.getbuiltinmodule('_io'), space.newtext('UnsupportedOperation')) return OperationError(w_exc, space.newtext(message))
def fget(space, w_obj): from pypy.objspace.std.sliceobject import W_SliceObject if not isinstance(w_obj, W_SliceObject): raise OperationError(space.w_TypeError, space.wrap("descriptor is for 'slice'")) return getattr(w_obj, name)
def rawaddressof(self, cdata, offset): space = self.space raise OperationError(space.w_TypeError, space.wrap("expected a pointer ctype"))
self.mmap.move(dest, src, count) except RValueError, v: raise mmap_error(self.space, v) @unwrap_spec(newsize=int) def resize(self, newsize): self.check_valid() self.check_resizeable() try: self.mmap.resize(newsize) except OSError, e: raise mmap_error(self.space, e) except RValueError, e: # obscure: in this case, RValueError translates to an app-level # SystemError. raise OperationError(self.space.w_SystemError, self.space.wrap(e.message)) def __len__(self): return self.space.wrap(self.mmap.size) def check_valid(self): try: self.mmap.check_valid() except RValueError, v: raise mmap_error(self.space, v) def check_writeable(self): try: self.mmap.check_writeable() except RMMapError, v: raise mmap_error(self.space, v)
def wrap_parsestringerror(space, e, w_source): if isinstance(e, InvalidBaseError): raise OperationError(space.w_ValueError, space.newtext(e.msg)) else: raise oefmt(space.w_ValueError, '%s: %R', e.msg, w_source)
def issubtype_allow_override(space, w_sub, w_type): w_check = space.lookup(w_type, "__subclasscheck__") if w_check is None: raise OperationError(space.w_TypeError, space.wrap("issubclass not supported here")) return space.get_and_call_function(w_check, w_type, w_sub)
def next_w(self): result = self._next if result == self._stop: raise OperationError(self.space.w_StopIteration, self.space.w_None) self._next = rffi.ptradd(result, self.ctitem.size) return self.ctitem.convert_to_object(result)
def missing_operation(space): return OperationError(space.w_NotImplementedError, space.wrap("operation not implemented by this GC"))
def _check_closed(self, space, message=None): if self.is_closed(): if message is None: message = "I/O operation on closed file" raise OperationError(space.w_ValueError, space.wrap(message))
def _check_closed(self, space, message=None): if message is None: message = "I/O operation on closed file" if self.fd < 0: raise OperationError(space.w_ValueError, space.newtext(message))
def ssl_error(space, msg, errno=0): w_exception_class = get_error(space) w_exception = space.call_function(w_exception_class, space.wrap(errno), space.wrap(msg)) return OperationError(w_exception_class, w_exception)
def load_dynamic(space, w_modulename, filename, w_file=None): if not space.config.objspace.usemodules.cpyext: raise OperationError(space.w_ImportError, space.wrap("Not implemented")) importing.load_c_extension(space, filename, space.str_w(w_modulename)) return importing.check_sys_modules(space, w_modulename)
def raise_exception(space, msg): raise OperationError(space.w_ValueError, space.wrap(msg))
def raise_key_error(self, w_key): e = self.call_function(self.w_KeyError, w_key) raise OperationError(self.w_KeyError, e)
def descr_next(self, space): if self.iter.done(self.state): raise OperationError(space.w_StopIteration, space.w_None) w_res = self.iter.getitem(self.state) self.iter.next(self.state, mutate=True) return w_res
def descr__reduce__(self, space): raise OperationError( space.w_TypeError, space.wrap("_stackless.clonable instances are " "not picklable"))
else: w_errors = space.w_None # - unicode is disallowed # - raise TypeError for non-string types if space.isinstance_w(w_obj, space.w_unicode): w_meth = None else: try: w_meth = space.getattr(w_obj, space.wrap('decode')) except OperationError, e: if not e.match(space, space.w_AttributeError): raise w_meth = None if w_meth is None: raise OperationError(space.w_TypeError, space.wrap("decoding Unicode is not supported")) return space.call_function(w_meth, w_encoding, w_errors) @cpython_api([PyObject, PyObjectP], rffi.INT_real, error=0) def PyUnicode_FSConverter(space, w_obj, result): """ParseTuple converter: encode str objects to bytes using PyUnicode_EncodeFSDefault(); bytes objects are output as-is. result must be a PyBytesObject* which must be released when it is no longer used. """ if not w_obj: # Implement ParseTuple cleanup support Py_DecRef(space, result[0]) return 1 if space.isinstance_w(w_obj, space.w_bytes):