Commit 08dc5d10 authored by Kirill Smelkov's avatar Kirill Smelkov

golang: Fix print(_pystr)

On Python2 without .tp_print printing _pystr crashes as:

    pygolang$ ./golang/testprog/golang_test_str.py
    Traceback (most recent call last):
      File "./golang/testprog/golang_test_str.py", line 39, in <module>
        main()
      File "./golang/testprog/golang_test_str.py", line 34, in main
        print("print(qq(b)):", qq(sb))
    RuntimeError: print recursion

See added comments for details.
parent 2a35ef5b
...@@ -914,6 +914,27 @@ cdef class _pyunicode(unicode): ...@@ -914,6 +914,27 @@ cdef class _pyunicode(unicode):
else: else:
return pyb(self) return pyb(self)
# initialize .tp_print for _pystr so that this type could be printed.
# If we don't - printing it will result in `RuntimeError: print recursion`
# because str of this type never reaches real bytes or unicode.
# Do it only on python2, because python3 does not use tp_print at all.
# NOTE _pyunicode does not need this because on py2 str(_pyunicode) returns _pystr.
IF PY2:
# NOTE Cython does not define tp_print for PyTypeObject - do it ourselves
from libc.stdio cimport FILE
cdef extern from "Python.h":
ctypedef int (*printfunc)(PyObject *, FILE *, int) except -1
ctypedef struct PyTypeObject:
printfunc tp_print
cdef PyTypeObject *Py_TYPE(object)
cdef int _pystr_tp_print(PyObject *obj, FILE *f, int nesting) except -1:
o = <bytes>obj
o = bytes(buffer(o)) # change tp_type to bytes instead of _pystr
return Py_TYPE(o).tp_print(<PyObject*>o, f, nesting)
Py_TYPE(_pystr()).tp_print = _pystr_tp_print
# __pystr converts obj to str of current python: # __pystr converts obj to str of current python:
# #
......
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# Copyright (C) 2018-2021 Nexedi SA and Contributors. # Copyright (C) 2018-2022 Nexedi SA and Contributors.
# Kirill Smelkov <kirr@nexedi.com> # Kirill Smelkov <kirr@nexedi.com>
# #
# This program is free software: you can Use, Study, Modify and Redistribute # This program is free software: you can Use, Study, Modify and Redistribute
...@@ -1784,6 +1784,15 @@ def test_strings(): ...@@ -1784,6 +1784,15 @@ def test_strings():
assert isinstance(_, unicode) assert isinstance(_, unicode)
assert u(_) is _ assert u(_) is _
# verify print for _pystr and _pyunicode
def test_strings_print():
outok = readfile(dir_testprog + "/golang_test_str.txt")
retcode, stdout, stderr = _pyrun(["golang_test_str.py"],
cwd=dir_testprog, stdout=PIPE, stderr=PIPE)
assert retcode == 0, (stdout, stderr)
assert stderr == b""
assertDoc(outok, stdout)
def test_qq(): def test_qq():
# NOTE qq is also tested as part of strconv.quote # NOTE qq is also tested as part of strconv.quote
......
...@@ -246,9 +246,13 @@ def Extension(name, sources, **kw): ...@@ -246,9 +246,13 @@ def Extension(name, sources, **kw):
# provide POSIX/PYPY/... defines to Cython # provide POSIX/PYPY/... defines to Cython
POSIX = ('posix' in sys.builtin_module_names) POSIX = ('posix' in sys.builtin_module_names)
PYPY = (platform.python_implementation() == 'PyPy') PYPY = (platform.python_implementation() == 'PyPy')
PY2 = (sys.version_info.major < 3)
PY3 = (not PY2)
pyxenv = kw.get('cython_compile_time_env', {}) pyxenv = kw.get('cython_compile_time_env', {})
pyxenv.setdefault('POSIX', POSIX) pyxenv.setdefault('POSIX', POSIX)
pyxenv.setdefault('PYPY', PYPY) pyxenv.setdefault('PYPY', PYPY)
pyxenv.setdefault('PY2', PY2)
pyxenv.setdefault('PY3', PY3)
gverhex = _gevent_version_hex() gverhex = _gevent_version_hex()
if gverhex is not None: if gverhex is not None:
pyxenv.setdefault('GEVENT_VERSION_HEX', gverhex) pyxenv.setdefault('GEVENT_VERSION_HEX', gverhex)
......
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# Copyright (C) 2022 Nexedi SA and Contributors.
# Kirill Smelkov <kirr@nexedi.com>
#
# This program is free software: you can Use, Study, Modify and Redistribute
# it under the terms of the GNU General Public License version 3, or (at your
# option) any later version, as published by the Free Software Foundation.
#
# You can also Link and Combine this program with other software covered by
# the terms of any of the Free Software licenses or any of the Open Source
# Initiative approved licenses and Convey the resulting work. Corresponding
# source of such a combination shall include the source code for all other
# software used.
#
# This program is distributed WITHOUT ANY WARRANTY; without even the implied
# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
#
# See COPYING file for full licensing terms.
# See https://www.nexedi.com/licensing for rationale and options.
"""This program helps to verify _pystr and _pyunicode.
It complements golang_test.test_strings.
"""
from __future__ import print_function, absolute_import
from golang import b, u
from golang.gcompat import qq
def main():
sb = b("привет b")
su = u("привет u")
print("print(qq(b)):", qq(sb))
print("print(qq(u)):", qq(su))
if __name__ == '__main__':
main()
print(qq(b)): "привет b"
print(qq(u)): "привет u"
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment