- 27 Jun, 2023 7 commits
-
-
Kirill Smelkov authored
Add type annotations and use C-level objects instead of py-ones where it is easy to do. We are not all-good yet, but this already brings some noticable speedup: name old time/op new time/op delta quote[a] 786µs ± 1% 10µs ± 0% -98.76% (p=0.016 n=4+5) quote[\u03b1] 1.12ms ± 0% 0.41ms ± 0% -63.37% (p=0.008 n=5+5) quote[\u65e5] 738µs ± 2% 258µs ± 0% -65.07% (p=0.016 n=4+5) quote[\U0001f64f] 920µs ± 1% 78µs ± 0% -91.46% (p=0.016 n=5+4) stdquote 1.19µs ± 0% 1.19µs ± 0% ~ (p=0.794 n=5+5) unquote[a] 1.08ms ± 0% 1.08ms ± 1% ~ (p=0.548 n=5+5) unquote[\u03b1] 797µs ± 0% 807µs ± 1% +1.23% (p=0.008 n=5+5) unquote[\u65e5] 522µs ± 0% 520µs ± 1% ~ (p=0.056 n=5+5) unquote[\U0001f64f] 3.21ms ± 0% 3.14ms ± 0% -2.13% (p=0.008 n=5+5) stdunquote 815ns ± 0% 836ns ± 0% +2.63% (p=0.008 n=5+5)
-
Kirill Smelkov authored
Since 50b8cb7e (strconv: Move functionality related to UTF8 encode/decode into _golang_str) both golang_str and strconv import each other. Before this patch that import was done at py level at runtime from outside to workaround the import cycle. This results in that strconv functionality is not available while golang is only being imported. So far it was not a problem, but when builtin string types will become patched with bstr and ustr, that will become a problem because string repr starts to be used at import time, which for pybstr is implemented via strconv.quote . -> Fix this by switching golang and strconv to cimport each other at pyx level. There, similarly to C, the cycle works just ok out of the box. This also automatically helps performance a bit: name old time/op new time/op delta quote[a] 805µs ± 0% 786µs ± 1% -2.40% (p=0.016 n=5+4) quote[\u03b1] 1.21ms ± 0% 1.12ms ± 0% -7.47% (p=0.008 n=5+5) quote[\u65e5] 785µs ± 0% 738µs ± 2% -5.97% (p=0.016 n=5+4) quote[\U0001f64f] 1.04ms ± 0% 0.92ms ± 1% -11.73% (p=0.008 n=5+5) stdquote 1.18µs ± 0% 1.19µs ± 0% +0.54% (p=0.008 n=5+5) unquote[a] 1.26ms ± 0% 1.08ms ± 0% -14.66% (p=0.008 n=5+5) unquote[\u03b1] 911µs ± 1% 797µs ± 0% -12.55% (p=0.008 n=5+5) unquote[\u65e5] 592µs ± 0% 522µs ± 0% -11.81% (p=0.008 n=5+5) unquote[\U0001f64f] 3.46ms ± 0% 3.21ms ± 0% -7.34% (p=0.008 n=5+5) stdunquote 812ns ± 1% 815ns ± 0% ~ (p=0.183 n=5+5)
-
Kirill Smelkov authored
So far this is plain code movement with no type annotations added and internal from-strconv imports still being done via py level. As expected this does not help practically for performance yet: name old time/op new time/op delta quote[a] 910µs ± 0% 805µs ± 0% -11.54% (p=0.008 n=5+5) quote[\u03b1] 1.23ms ± 0% 1.21ms ± 0% -1.24% (p=0.008 n=5+5) quote[\u65e5] 800µs ± 0% 785µs ± 0% -1.86% (p=0.016 n=4+5) quote[\U0001f64f] 1.06ms ± 1% 1.04ms ± 0% -1.92% (p=0.008 n=5+5) stdquote 1.17µs ± 0% 1.18µs ± 0% +0.80% (p=0.008 n=5+5) unquote[a] 1.33ms ± 1% 1.26ms ± 0% -5.13% (p=0.008 n=5+5) unquote[\u03b1] 952µs ± 2% 911µs ± 1% -4.25% (p=0.008 n=5+5) unquote[\u65e5] 613µs ± 2% 592µs ± 0% -3.48% (p=0.008 n=5+5) unquote[\U0001f64f] 3.62ms ± 1% 3.46ms ± 0% -4.32% (p=0.008 n=5+5) stdunquote 788ns ± 0% 812ns ± 1% +3.07% (p=0.016 n=4+5)
-
Kirill Smelkov authored
We will soon need to use error rune codepoint from both golang_str.pyx and strconv.pyx - so we need to move that definition into shared place. What fits best is unicode/utf8, so start that package and move the constant there.
-
Kirill Smelkov authored
We added byte and rune types in the previous patch. Let's use them now throughout whole codebase where appropriate. Currently the only place where unicode-codepoint is used is _utf8_decode_rune. uint8_t was used in many places.
-
Kirill Smelkov authored
Those types are the base when working with byte- and unicode strings. It will be clearer to use them explicitly instead of uint8_t and int32_t when processing string.
-
Kirill Smelkov authored
This functions are currently relatively slow. They were initially used in zodbdump and zodbrestore, where their speed did not matter much, but with bstr and ustr, since e.g. quote is used in repr, not having them to perform with speed similar to builtin string escaping starts to be an issue. Tatuya Kamada reports at nexedi/pygolang!21 (comment 170833) : ### 3. `u` seems slow with large arrays especially when `repr` it I have faced a slowness while testing `u`, `b` with python 2.7, especially with `repr`. ```python >>> timeit.timeit("from golang import b,u; u('あ'*199998)", number=10) 2.02020001411438 >>> timeit.timeit("from golang import b,u; repr(u('あ'*199998))", number=10) 54.60263395309448 ``` `bytes`(str) is very fast. ```python >>> timeit.timeit("from golang import b,u; bytes('あ'*199998)", number=10) 0.000392913818359375 >>> timeit.timeit("from golang import b,u; repr(bytes('あ'*199998))", number=10) 0.4604980945587158 ``` `b` is much faster than `u`, but still the repr seems slow. ``` >>> timeit.timeit("from golang import b,u; b('あ'*199998)", number=10) 0.0009968280792236328 >>> timeit.timeit("from golang import b,u; repr(b('あ'*199998))", number=10) 25.498882055282593 ``` The "repr" part of this problem is due to that both bstr.__repr__ and ustr.__repr__ use custom quoting routines which currently are implemented in pure python in strconv module: https://lab.nexedi.com/kirr/pygolang/blob/300d7dfa/golang/_golang_str.pyx#L282-291 https://lab.nexedi.com/kirr/pygolang/blob/300d7dfa/golang/_golang_str.pyx#L582-591 https://lab.nexedi.com/kirr/pygolang/blob/300d7dfa/golang/_golang_str.pyx#L941-970 https://lab.nexedi.com/kirr/pygolang/blob/300d7dfa/golang/strconv.py#L31-92 The fix would be to move strconv.py to Cython and to correspondingly rework it to avoid using python-level constructs during quoting internally. Working on that was not a priority, but soon I will need to move strconv to Cython for another reason: to be able to break import cycle in between _golang and strconv. So it makes sense to add strconv benchmark first - since we'll start moving it to Cython anyway - to see where we are and how further changes will help performance-wise. Currently we are at name time/op quote[a] 910µs ± 0% quote[\u03b1] 1.23ms ± 0% quote[\u65e5] 800µs ± 0% quote[\U0001f64f] 1.06ms ± 1% stdquote 1.17µs ± 0% unquote[a] 1.33ms ± 1% unquote[\u03b1] 952µs ± 2% unquote[\u65e5] 613µs ± 2% unquote[\U0001f64f] 3.62ms ± 1% stdunquote 788ns ± 0% i.e. on py2 quoting is ~ 1000x slower than builtin string escaping, and unquoting is even slower. on py3 the situation is better, but still not good: name time/op quote[a] 579µs ± 1% quote[\u03b1] 942µs ± 1% quote[\u65e5] 595µs ± 0% quote[\U0001f64f] 274µs ± 1% stdquote 2.70µs ± 0% unquote[a] 696µs ± 1% unquote[\u03b1] 763µs ± 0% unquote[\u65e5] 474µs ± 1% unquote[\U0001f64f] 187µs ± 0% stdunquote 808ns ± 0% δ(py2, py3) for the reference: name py2 time/op py3 time/op delta quote[a] 910µs ± 0% 579µs ± 1% -36.42% (p=0.008 n=5+5) quote[\u03b1] 1.23ms ± 0% 0.94ms ± 1% -23.17% (p=0.008 n=5+5) quote[\u65e5] 800µs ± 0% 595µs ± 0% -25.63% (p=0.016 n=4+5) quote[\U0001f64f] 1.06ms ± 1% 0.27ms ± 1% -74.23% (p=0.008 n=5+5) stdquote 1.17µs ± 0% 2.70µs ± 0% +129.71% (p=0.008 n=5+5) unquote[a] 1.33ms ± 1% 0.70ms ± 1% -47.71% (p=0.008 n=5+5) unquote[\u03b1] 952µs ± 2% 763µs ± 0% -19.82% (p=0.008 n=5+5) unquote[\u65e5] 613µs ± 2% 474µs ± 1% -22.76% (p=0.008 n=5+5) unquote[\U0001f64f] 3.62ms ± 1% 0.19ms ± 0% -94.84% (p=0.016 n=5+4) stdunquote 788ns ± 0% 808ns ± 0% +2.59% (p=0.016 n=4+5)
-
- 23 Jun, 2023 3 commits
-
-
Kirill Smelkov authored
And let pybstr/pyustr point to version of bstr/ustr types that is actually in use: - when bytes/unicode are not patched -> to _pybstr/_pyustr - when bytes/unicode will be patched -> to bytes/unicode to where original _pybstr/_pyustr were copied during bytes/unicode patching. at runtime the code uses pybstr/pyustr instead of _pybstr/_pyustr.
-
Kirill Smelkov authored
GPython will patch builtin bytes and unicode types. zbytes and zunicode will refer to original unpatched types. We will use them to invoke original bytes/unicode methods. NOTE we will test against bytes/unicode - not zbytes/zunicode - when inspecting type of objects. In other words we will use original bytes/unicode types only to refer to their original methods and code.
-
Kirill Smelkov authored
For gpython to switch builtin str/unicode to bstr/ustr we will need bstr/ustr to have exactly the same C layout as builtin string types. This is possible to achieve only via `cdef class`. It is also good to switch to `cdef class` for RAM savings - from https://github.com/cython/cython/pull/5212#issuecomment-1387659026 : # what Cython does at runtime for `class MyBytes(bytes)` In [3]: MyBytes = type('MyBytes', (bytes,), {'__slots__': ()}) In [4]: MyBytes Out[4]: __main__.MyBytes In [5]: a = bytes(b'123') In [6]: b = MyBytes(b'123') In [7]: a Out[7]: b'123' In [8]: b Out[8]: b'123' In [9]: a == b Out[9]: True In [10]: import sys In [11]: sys.getsizeof(a) Out[11]: 36 In [12]: sys.getsizeof(b) Out[12]: 52 So with `cdef class` we gain more control and optimize memory usage. This was not done before because cython forbids to `cdef class X(bytes)` due to https://github.com/cython/cython/issues/711. We work it around in setup.py with draft for proper patch pre-posted to upstream in https://github.com/cython/cython/pull/5212 .
-
- 01 May, 2023 6 commits
-
-
Kirill Smelkov authored
Before: (z-dev) kirr@deca:~/src/tools/go/pygolang$ gpython -X gpython.zzz Traceback (most recent call last): File "/home/kirr/src/wendelin/venv/z-dev/bin/gpython", line 3, in <module> from gpython import main; main() File "/home/kirr/src/tools/go/pygolang/gpython/__init__.py", line 397, in main raise RuntimeError('gpython: unknown -X option %s' % opt) RuntimeError: gpython: unknown -X option -X <-- NOTE After: (z-dev) kirr@deca:~/src/tools/go/pygolang$ gpython -X gpython.zzz Traceback (most recent call last): File "/home/kirr/src/wendelin/venv/z-dev/bin/gpython", line 3, in <module> from gpython import main; main() File "/home/kirr/src/tools/go/pygolang/gpython/__init__.py", line 397, in main raise RuntimeError('gpython: unknown -X option %s' % arg) RuntimeError: gpython: unknown -X option gpython.zzz <-- NOTE
-
Kirill Smelkov authored
gpython: Fix `gpython -X gpython.runtime=threads` to spawn subinterpreters with threads runtime by default Previously it was not the case and gpython with default being gevent runtime was spawned even if parent gpython was instructed to use threads runtime: (z-dev) kirr@deca:~/src/tools/go/pygolang$ gpython -X gpython.runtime=threads Python 2.7.18 (default, Apr 28 2021, 17:39:59) [GCC 10.2.1 20210110] [GPython 0.1] [threads] on linux2 Type "help", "copyright", "credits" or "license" for more information. (InteractiveConsole) >>> import sys >>> sys.version '2.7.18 (default, Apr 28 2021, 17:39:59) \n[GCC 10.2.1 20210110] [GPython 0.1] [threads]' <-- NOTE threads >>> import subprocess subprocess.call(sys.executable)ble) Python 2.7.18 (default, Apr 28 2021, 17:39:59) [GCC 10.2.1 20210110] [GPython 0.1] [gevent 21.1.2] on linux2 <-- NOTE gevent Type "help", "copyright", "credits" or "license" for more information. (InteractiveConsole) >>>
-
Kirill Smelkov authored
Factor-out subroutine to run tfunc in subprocess interpreter spawned with `-X xopt=xval`. This helps clarity and later in addition to `-X gpython.runtime` we will also need it to verify `-X gpython.strings`.
-
Kirill Smelkov authored
Previously test_strings_methods was testing a method via comparing bstr and ustr results of .method() with similar result of unicode.method(). This works reasonably ok. However under gpython, when unicode will be replaced with ustr, it will no longer compare results of bstr/ustr methods with something good and external - indeed in that case bstr/ustr .method() will be compared to result of ustr.method() which opens the door for bugs to stay unnoticed. -> Adjust the test to explicitly provide expected result for all entries in the test vector. We make sure those results are good and match std python because we also assert that unicode.method() matches it.
-
Kirill Smelkov authored
On py2 str.decode('string-escape') returns str, not unicode and this property is actually being used and relied upon by Lib/pickle.py: https://github.com/python/cpython/blob/v2.7.18-0-g8d21aa21f2c/Lib/pickle.py#L967-L977 We promised bstr to be drop-in replacement for str on py2, so let's adjust its behaviour to match the original because if we do not, unpickling strings will break when str is replaced by bstr under gpython. Do not add bstr.encode yet until we hit a real case where it is actually used.
-
Kirill Smelkov authored
repr(ustr|bstr) will change behaviour depending on whether we are running under regular python, or gpython with string types replaced by bstr/ustr. But this test is completely orthogonal to that. -> Let's untie it from particular repr behaviour by emitting verified items in quoted form + asserting their types in the code.
-
- 30 Apr, 2023 3 commits
-
-
Kirill Smelkov authored
In ebd18f3f the code was ok but there is a thinko in test: it needs to test all pickle protocols from 0 to _including_ HIGHEST_PROTOCOL.
-
Kirill Smelkov authored
+ ./trun python -m pytest -vvsx golang/golang_str_test.py ==================================== test session starts ===================================== platform linux2 -- Python 2.7.18, pytest-4.6.11, py-1.11.0, pluggy-0.13.1 -- /home/kirr/src/tools/go/py2d.venv2023/bin/python cachedir: .pytest_cache rootdir: /home/kirr/src/tools/go/pygolang-xgpystr collected 64 items golang/golang_str_test.py::test_strings_basic Traceback (most recent call last): File "golang/_golang_str.pyx", line 2270, in golang._golang._xuniord return ord(u) ValueError: only single character unicode strings can be converted to Py_UCS4, got length 2 Exception ValueError: 'only single character unicode strings can be converted to Py_UCS4, got length 2' in 'golang._golang._utf8_decode_rune' ignored (py2d.venv2023) kirr@deca:~/src/tools/go/pygolang-xgpystr$ python Python 2.7.18 (tags/2.7-dirty:8d21aa21f2c, Mar 30 2023, 07:38:40) [GCC 10.2.1 20210110] on linux2 Type "help", "copyright", "credits" or "license" for more information. >>> from pygolang import * Traceback (most recent call last): File "<stdin>", line 1, in <module> ImportError: No module named pygolang >>> from golang import * >>> ord('xy') Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: ord() expected a character, but string of length 2 found >>> ord(b'xy') Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: ord() expected a character, but string of length 2 found >>> ord(u'xy') Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: ord() expected a character, but string of length 2 found >>> ord(b('xy')) Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: ord() expected a character, but string of length 2 found >>> ord(u('xy')) Traceback (most recent call last): File "golang/_golang_str.pyx", line 2270, in golang._golang._xuniord return ord(u) ValueError: only single character unicode strings can be converted to Py_UCS4, got length 2 Exception ValueError: 'only single character unicode strings can be converted to Py_UCS4, got length 2' in 'golang._golang._utf8_decode_rune' ignored Traceback (most recent call last): File "<stdin>", line 1, in <module> File "golang/_golang_str.pyx", line 157, in golang._golang.pyu us = _pyu(pyustr, s) File "golang/_golang_str.pyx", line 195, in golang._golang._pyu s = _utf8_decode_surrogateescape(s) File "golang/_golang_str.pyx", line 2198, in golang._golang._utf8_decode_surrogateescape emit(_xunichr(r)) File "golang/_golang_str.pyx", line 2286, in golang._golang._xunichr return unichr(0xd800 + (uh >> 10)) + \ ValueError: unichr() arg not in range(0x10000) (narrow Python build) It was broken in 50b8cb7e (strconv: Move functionality related to UTF8 encode/decode into _golang_str)
-
Kirill Smelkov authored
-
- 27 Apr, 2023 21 commits
-
-
Kirill Smelkov authored
Pygolang stopped to work on Windows in 2019 starting from 8fa3c15b (Start using Cython and providing Cython/nogil API). Restore it now.
-
Kirill Smelkov authored
Linux and macOS was working before. And we just added Windows support in the previous patches.
-
Kirill Smelkov authored
When underlying pygfobj is FileObjectThread its .readinto() leads to deadlock because it is no cooperative(*). This manifests as test_pyx_os_pipe_cpp hang when run by gpython on windows. -> Workaround this by reading first into intermediate buffer and then copying data to buffer that user provided. After this the deadlock is gone but test_pyx_os_pipe_cpp starts to fail and crash randomly. That's because similarly to channels we need to care and not access a buffer if it is located on stack and owning greenlet is inactive. Because when a greenlet is inactive, its stack is reused by another active greenlet and writing/reading to on-stack memory accesses that second greenlet stack, corrupting it on write. -> do the same what we do in chan operations: use intermediate on-heap buffer to protect original user's buffer to be accesses because it might be located on stack. That's what actually happens in test_pyx_os_pipe_cpp where two goroutines read and write to each other via pipe and using on-stack located buffers. And becuase on windows pipes, like regular files, are wrapped with FileObjectThread, when reading greenlet becomes suspended waiting for read reasul, it will be another greenlet to run on its stack, write to another end of a pipe, wakeup IO thread, which will write the data to requested buffer on G1 stack and oops - it was G2 there. (*) see https://github.com/gevent/gevent/pull/1948 for details
-
Kirill Smelkov authored
Because on Windows it is \ and using / for it to scan in path fails and leads to test_pymain_opt failure: E Full diff: E [ E 'sys.flags.debug: 0', E 'sys.flags.optimize: 0', E '__debug__: True', E 'assert: True', E 'docstrings: True', E 'import mod.py: ' E - 'C:\\users\\kirr\\Temp\\modpy_imports_fromvmgs8go4\\__pycache__/mod.cpython-310.pyc', E ? ^^ ---- E + 'C:\\users\\kirr\\Temp\\modpy_imports_from850gb81s\\__pycache__/mod.cpython-310.pyc', E ? ^^^ +++ E ] Here the difference is because gpython/testprog/print_opt.py failed to detect tmpd prefix and strip it.
-
Kirill Smelkov authored
In several places we were preparing repr of a string as '%s' which works ok most of the time but leads to failure if string contains '\' characters e.g. if it represents a path and we are running on windows: def test_pymain(): from golang import b .... # -m <module> _ = pyout(['-m', 'hello', 'abc', 'def'], cwd=testdata) # realpath rewrites e.g. `local/lib -> lib` if local/lib is symlink hellopy = realpath(join(testdata, 'hello.py')) > assert _ == b"hello\nworld\n['%s', 'abc', 'def']\n" % b(hellopy) E assert b"hello\nworld\n['Z:\\\\home\\\\kirr\\\\src\\\\tools\\\\go\\\\pygo-win\\\\pygolang\\\\gpython\\\\testdata\\\\hello.py', 'abc', 'def' ]\n" == b"hello\nworld\n['Z:\\home\\kirr\\src\\tools\\go\\pygo-win\\pygolang\\gpython\\testdata\\hello.py', 'abc', 'def']\n" E At index 17 diff: b'\\' != b'h' E Full diff: E ( E - b"hello\nworld\n['Z:\\home\\kirr\\src\\tools\\go\\pygo-win\\pygolang\\gpytho" E ? ------------ E + b"hello\nworld\n['Z:\\\\home\\\\kirr\\\\src\\\\tools\\\\go\\\\pygo-win\\\\pygo" E ? ++ ++ ++ ++ ++ ++ ++ E - b"n\\testdata\\hello.py', 'abc', 'def']\n", E + b"lang\\\\gpython\\\\testdata\\\\hello.py', 'abc', 'def']\n", E ? ++ ++++++++++++++ ++ E ) gpython\gpython_test.py:183: AssertionError -> Fix it by preparing repr via repr(...) properly.
-
Kirill Smelkov authored
On Windows if geventmp is present gpython startup fails: (1.wenv) Z:\home\kirr\src\tools\go\pygo-win\pygolang>gpython Traceback (most recent call last): File "C:\Program Files\Python310\lib\runpy.py", line 196, in _run_module_as_main return _run_code(code, main_globals, None, File "C:\Program Files\Python310\lib\runpy.py", line 86, in _run_code exec(code, run_globals) File "Z:\home\kirr\src\tools\go\pygo-win\1.wenv\Scripts\gpython.exe\__main__.py", line 7, in <module> File "Z:\home\kirr\src\tools\go\pygo-win\pygolang\gpython\__init__.py", line 450, in main pymain(argv, init) File "Z:\home\kirr\src\tools\go\pygo-win\pygolang\gpython\__init__.py", line 223, in pymain init() File "Z:\home\kirr\src\tools\go\pygo-win\pygolang\gpython\__init__.py", line 428, in init _ = monkey.patch_all(thread=patch_thread) # XXX sys=True ? File "Z:\home\kirr\src\tools\go\pygo-win\1.wenv\lib\site-packages\gevent\monkey.py", line 1255, in patch_all _notify_patch(events.GeventWillPatchAllEvent(modules_to_patch, kwargs), _warnings) File "Z:\home\kirr\src\tools\go\pygo-win\1.wenv\lib\site-packages\gevent\monkey.py", line 190, in _notify_patch notify_and_call_entry_points(event) File "Z:\home\kirr\src\tools\go\pygo-win\1.wenv\lib\site-packages\gevent\events.py", line 105, in notify_and_call_entry_points subscriber(event) File "Z:\home\kirr\src\tools\go\pygo-win\1.wenv\lib\site-packages\geventmp\monkey.py", line 160, in _patch_mp _patch_module("_mp.3._mp_util", _patch_module=True, _package_prefix='geventmp.') File "Z:\home\kirr\src\tools\go\pygo-win\1.wenv\lib\site-packages\geventmp\monkey.py", line 121, in _patch_module gevent_module = import_module(_package_prefix + name) File "C:\Program Files\Python310\lib\importlib\__init__.py", line 126, in import_module return _bootstrap._gcd_import(name[level:], package, level) File "<frozen importlib._bootstrap>", line 1050, in _gcd_import File "<frozen importlib._bootstrap>", line 1027, in _find_and_load File "<frozen importlib._bootstrap>", line 1006, in _find_and_load_unlocked File "<frozen importlib._bootstrap>", line 688, in _load_unlocked File "<frozen importlib._bootstrap_external>", line 883, in exec_module File "<frozen importlib._bootstrap>", line 241, in _call_with_frames_removed File "Z:\home\kirr\src\tools\go\pygo-win\1.wenv\lib\site-packages\geventmp\_mp\3\_mp_util.py", line 16, in <module> from gevent.os import _watch_child ImportError: cannot import name '_watch_child' from 'gevent.os' (Z:\home\kirr\src\tools\go\pygo-win\1.wenv\lib\site-packages\gevent\os.py) That happens because geventmp does not support windows actually. -> Fix it by requiring geventmp to be present only on non-windows. Adjust related comment as https://github.com/karellen/geventmp/pull/2 has been merged long ago.
-
Kirill Smelkov authored
On windows setuptools install gpython.exe and gpython-script.py while pip/distlib install gpython.exe with gpython-script sometimes embedded into gpython.exe itself with argv[0] pointing to 'gpython' without .exe suffix. This leads to gpython startup failure: (1.wenv) Z:\home\kirr\src\tools\go\pygo-win\pygolang>gpython Traceback (most recent call last): File "C:\Program Files\Python310\lib\runpy.py", line 196, in _run_module_as_main return _run_code(code, main_globals, None, File "C:\Program Files\Python310\lib\runpy.py", line 86, in _run_code exec(code, run_globals) File "Z:\home\kirr\src\tools\go\pygo-win\1.wenv\Scripts\gpython.exe\__main__.py", line 7, in <module> File "Z:\home\kirr\src\tools\go\pygo-win\pygolang\gpython\__init__.py", line 437, in main pymain(argv, init) File "Z:\home\kirr\src\tools\go\pygo-win\pygolang\gpython\__init__.py", line 79, in pymain if not _is_buildout_script(exe): File "Z:\home\kirr\src\tools\go\pygo-win\pygolang\gpython\__init__.py", line 442, in _is_buildout_script with open(path, 'rb') as f: FileNotFoundError: [Errno 2] No such file or directory: 'Z:\\home\\kirr\\src\\tools\\go\\pygo-win\\1.wenv\\Scripts\\gpython' (1.wenv) Z:\home\kirr\src\tools\go\pygo-win\pygolang>dir ../1.wenv/scripts/gpython* Directory of Z:\home\kirr\src\tools\go\pygo-win\1.wenv\scripts 26.04.2023 14:17 108,404 gpython.exe 1 file 108,404 bytes 0 directories 88,508,866,560 bytes free -> Adjust pymain to handle this case accordingly.
-
Kirill Smelkov authored
On windows upon terminating signal reception exict code of the process is always 3 instead of -signo. And so test_signal_all was failing as def test_signal_all(): retcode, out, _ = _pyrun([dir_testprog + "/signal_test_all.py"], stdout=PIPE) assert b"ok (notify)" in out assert b"ok (ignore)" in out assert b"terminating ..." in out > assert retcode == -syscall.SIGTERM.signo E assert 3 == -15 E + where 15 = os.Signal(15).signo E + where os.Signal(15) = syscall.SIGTERM
-
Kirill Smelkov authored
- There is no e.g. signal.SIGKILL on windows: golang/os/signal_test.py::test_signal_all Traceback (most recent call last): File "Z:\home\kirr\src\tools\go\pygo-win\pygolang\golang\os\testprog\signal_test_all.py", line 82, in <module> main() File "Z:\home\kirr\src\tools\go\pygo-win\pygolang\golang\os\testprog\signal_test_all.py", line 39, in main allsigv.remove(syscall.SIGKILL) # SIGKILL/SIGSTOP cannot be caught AttributeError: module 'golang.syscall' has no attribute 'SIGKILL'. Did you mean: 'SIGILL'? -> filter-out signals conditionally depending on their presence. - Need to also filter-out SIGILL/SIGABRT because upon reception MSVC runtime terminates process.
-
Kirill Smelkov authored
Because on Windows os.kill unconditionally terminates target process, even if own self, instead of sending it any kind of signal.
-
Kirill Smelkov authored
We use SIGUSR1/SIGUSR2 mainly in this test, but those signals are not available on Windows: @func def test_signal(): # Notify/Stop with wrong chan dtype -> panic _ = panics("pychan: channel type mismatch") > with _: signal.Notify(chan(2), syscall.SIGUSR1) E AttributeError: module 'golang.syscall' has no attribute 'SIGUSR1' -> Use SIGTERM/SIGINT if SIGUSR1/SIGUSR2 are not available. Don't want to use SIGTERM/SIGINT unconditionally because those signals are better to leave for the job control so that e.g. nxdtest can properly kill spawned pygolang tests.
-
Kirill Smelkov authored
On Windows in text mode files are opened with encoding=locale.getdefaultlocale() which is CP125X instead of UTF-8 even if $PYTHONIOENCODING=UTF-8. This way e.g. test_strings_print fail as: E Failed: not equal: E Expected: E print(qq(b)): "привет О±ОІОі b" E print(qq(u)): "привет О±ОІОі u" E Got: E print(qq(b)): "привет αβγ b" E print(qq(u)): "привет αβγ u" where "Expected" was read from golang/testprog/golang_test_str.txt and decoded wrongly. -> Fix it by always opening files for reading in binary mode and utf8-decoding manually, if needed, everywhere.
-
Kirill Smelkov authored
golang: tests: Spawn subprocess python with $PYTHONIOENCODING set to encoding of stdin/stdout/stderr We need to do it because on Windows `python x.py | ...` runs with stdio encoding set to cp125X even if just `python x.py` runs with stdio encoding=UTF-8. (1.wenv) Z:\home\kirr\src\tools\go\pygo-win\pygolang\golang\testprog>python golang_test_str.py print(qq(b)): "привет b" print(qq(u)): "привет u" (1.wenv) Z:\home\kirr\src\tools\go\pygo-win\pygolang\golang\testprog>python golang_test_str.py |more print(qq(b)): "яЁштхЄ b" print(qq(u)): "яЁштхЄ u" (1.wenv) Z:\home\kirr\src\tools\go\pygo-win\pygolang\golang\testprog>python golang_test_str.py >aaa.txt (1.wenv) Z:\home\kirr\src\tools\go\pygo-win\pygolang\golang\testprog>type aaa.txt print(qq(b)): "яЁштхЄ b" print(qq(u)): "яЁштхЄ u" Which leads to the following test_strings_print failure: E Failed: not equal: E Expected: E print(qq(b)): "привет b" E print(qq(u)): "привет u" E Got: E print(qq(b)): "������ b" E print(qq(u)): "������ u" We also change golang_test_str.py to print not only russian and english letters, but also greek ones. This is to make sure that stdout IO encoding would not go cp125X unnoticed because then printing will fail with UnicodeEncodeError. Note: in the above example both got and expected are wrong. Via $PYTHONIOENCODING we only fix "got" and we will fix "expected" in the followup patch. After current patch test_strings_print result is E Failed: not equal: E Expected: E print(qq(b)): "привет О±ОІОі b" E print(qq(u)): "привет О±ОІОі u" E Got: E print(qq(b)): "привет αβγ b" E print(qq(u)): "привет αβγ u"
-
Kirill Smelkov authored
Apparently on Windows pytest detects terminal width differently than on Linux/macOS and the test fails as E Failed: not equal: E Differences (unified diff with -expected +actual): E @@ -1,5 +1,12 @@ E -... E -_____________________________________ main _____________________________________ E -../__init__.py:...: in _ E +============================= test session starts ============================= E +platform win32 -- Python 3.10.11, pytest-7.3.1, pluggy-1.0.0 E +rootdir: PYGOLANG E +collected 1 item E +<BLANKLINE> E +golang_test_defer_excchain.py F [100%] E +<BLANKLINE> E +================================== FAILURES =================================== E +____________________________________ main _____________________________________ E +../__init__.py:106: in _ E return f(*argv, **kw) E golang_test_defer_excchain.py:42: in main E @@ -8,6 +15,6 @@ E <BLANKLINE> E During handling of the above exception, another exception occurred: E -../__init__.py:...: in __exit__ E - ... E +../__init__.py:183: in __exit__ E + d() E golang_test_defer_excchain.py:31: in d1 E raise RuntimeError("d1: aaa") E @@ -15,9 +22,9 @@ E <BLANKLINE> E During handling of the above exception, another exception occurred: E -../__init__.py:...: in __exit__ E - ... E +../__init__.py:183: in __exit__ E + d() E golang_test_defer_excchain.py:33: in d2 E 1/0 E -E ZeroDivisionError: ... E +E ZeroDivisionError: division by zero E <BLANKLINE> E During handling of the above exception, another exception occurred: E @@ -25,3 +32,5 @@ E raise RuntimeError("d3: bbb") E E RuntimeError: d3: bbb E -=========================== ... E +=========================== short test summary info =========================== E +FAILED golang_test_defer_excchain.py::main - RuntimeError: d3: bbb E +============================== 1 failed in 1.45s ============================== -> Fix it by not requesting header to be of particular width.
-
Kirill Smelkov authored
On windows print emits \r\n instead of just \n. Here is how e.g. test_defer_excchain_dump fails without normalization: E Failed: not equal: E Differences (unified diff with -expected +actual): E @@ -1,42 +1,43 @@ E -Traceback (most recent call last): E - File "PYGOLANG/golang/__init__.py", line ..., in _ E - return f(*argv, **kw) E - File "PYGOLANG/golang/testprog/golang_test_defer_excchain.py", line 42, in main E - raise RuntimeError("err") E -RuntimeError: err E -<BLANKLINE> E -During handling of the above exception, another exception occurred: E -<BLANKLINE> E -Traceback (most recent call last): E - File "PYGOLANG/golang/__init__.py", line ..., in __exit__ E - ... E - File "PYGOLANG/golang/testprog/golang_test_defer_excchain.py", line 31, in d1 E - raise RuntimeError("d1: aaa") E -RuntimeError: d1: aaa E -<BLANKLINE> E -During handling of the above exception, another exception occurred: E -<BLANKLINE> E -Traceback (most recent call last): E - File "PYGOLANG/golang/__init__.py", line ..., in __exit__ E - ... E - File "PYGOLANG/golang/testprog/golang_test_defer_excchain.py", line 33, in d2 E - 1/0 E -ZeroDivisionError: ... E -<BLANKLINE> E -During handling of the above exception, another exception occurred: E -<BLANKLINE> E -Traceback (most recent call last): E - ... "PYGOLANG/golang/testprog/golang_test_defer_excchain.py", line 45, in <module> E - main() E - ... E - File "PYGOLANG/golang/__init__.py", line ..., in _ E - with __goframe__: E - File "PYGOLANG/golang/__init__.py", line ..., in __exit__ E - ... E - File "PYGOLANG/golang/__init__.py", line ..., in __exit__ E - ... E - File "PYGOLANG/golang/__init__.py", line ..., in __exit__ E - ... E - File "PYGOLANG/golang/testprog/golang_test_defer_excchain.py", line 35, in d3 E - raise RuntimeError("d3: bbb") E -RuntimeError: d3: bbb E +Traceback (most recent call last): E + File "PYGOLANG/golang/__init__.py", line 106, in _ E + return f(*argv, **kw) E + File "PYGOLANG/golang/testprog/golang_test_defer_excchain.py", line 42, in main E + raise RuntimeError("err") E +RuntimeError: err E + E +During handling of the above exception, another exception occurred: E + E +Traceback (most recent call last): E + File "PYGOLANG/golang/__init__.py", line 183, in __exit__ E + d() E + File "PYGOLANG/golang/testprog/golang_test_defer_excchain.py", line 31, in d1 E + raise RuntimeError("d1: aaa") E +RuntimeError: d1: aaa E + E +During handling of the above exception, another exception occurred: E + E +Traceback (most recent call last): E + File "PYGOLANG/golang/__init__.py", line 183, in __exit__ E + d() E + File "PYGOLANG/golang/testprog/golang_test_defer_excchain.py", line 33, in d2 E + 1/0 E +ZeroDivisionError: division by zero E + E +During handling of the above exception, another exception occurred: E + E +Traceback (most recent call last): E + File "PYGOLANG/golang/testprog/golang_test_defer_excchain.py", line 45, in <module> E + main() E + File "Z:\home\kirr\src\tools\go\pygo-win\1.wenv\lib\site-packages/decorator.py", line 232, in fun E + return caller(func, *(extras + args), **kw) E + File "PYGOLANG/golang/__init__.py", line 105, in _ E + with __goframe__: E + File "PYGOLANG/golang/__init__.py", line 182, in __exit__ E + with __goframe__: E + File "PYGOLANG/golang/__init__.py", line 182, in __exit__ E + with __goframe__: E + File "PYGOLANG/golang/__init__.py", line 183, in __exit__ E + d() E + File "PYGOLANG/golang/testprog/golang_test_defer_excchain.py", line 35, in d3 E + raise RuntimeError("d3: bbb") E +RuntimeError: d3: bbb
-
Kirill Smelkov authored
Else on Windows e.g. test_defer_excchain_traceback fails as E Failed: not equal: E Differences (unified diff with -expected +actual): E @@ -1,8 +1,8 @@ E Traceback (most recent call last): E - File "PYGOLANG/golang/golang_test.py", line ..., in test_defer_excchain_traceback E + File "PYGOLANG\golang\golang_test.py", line 1524, in test_defer_excchain_traceback E alpha() E - File "PYGOLANG/golang/golang_test.py", line ..., in alpha E + File "PYGOLANG\golang\golang_test.py", line 1521, in alpha E beta() E - File "PYGOLANG/golang/golang_test.py", line ..., in beta E + File "PYGOLANG\golang\golang_test.py", line 1520, in beta E raise RuntimeError("gamma") E RuntimeError: gamma
-
Kirill Smelkov authored
Else it fails to import on Windows: collecting ... 05c8:err:module:import_dll Library libgolang.dll (which is needed by L"Z:\\home\\kirr\\src\\tools\\go\\pygo-win\\pygolang\\golang\\_golang.cp310-win_amd64.pyd") not found collected 0 items / 1 error =========================================================== ERRORS =========================================================== ___________________________________________ ERROR collecting golang/golang_test.py ___________________________________ ImportError while importing test module 'Z:\home\kirr\src\tools\go\pygo-win\pygolang\golang\golang_test.py'. Hint: make sure your test modules/packages have valid Python names. Traceback: C:\Program Files\Python310\lib\importlib\__init__.py:126: in import_module return _bootstrap._gcd_import(name[level:], package, level) golang\__init__.py:45: in <module> from golang._golang import _pysys_exc_clear as _sys_exc_clear E ImportError: DLL load failed while importing _golang: Модуль не найден. We need to increase required setuptools_dso version because dylink_prepare_dso and generation of *_dsoinfo.py modules was done after setuptools_dso 2.
-
Kirill Smelkov authored
On Windows this files are generated when linking alongside *.dll files if there are exported symbols. See also https://github.com/mdavidsaver/setuptools_dso/pull/25.
-
Kirill Smelkov authored
Libpyxruntime by definition contains python-specific code and we already compile it with include path having python includes in it. However on windows pyconfig.h contains #pragma comment(lib,"python3.lib") which instructs the linker to automatically link to that library. And without proper library path the link fails: Z:\home\kirr\src\tools\go\pygo-win\BuildTools\vc\tools\msvc\14.35.32215\bin\Hostx64\x64\link.exe /nologo /INCREMENTAL:NO /LTCG /DLL /MANIFEST:EMBED,ID=2 /MANIFESTUAC:NO /LIBPATH:build\lib.win-amd64-cpython-31 0\golang\runtime /LIBPATH:z:\home\kirr\src\tools\go\pygo-win\BuildTools\vc\tools\msvc\14.35.32215\lib\x64 /LIBPATH:z:\home\kirr\src\tools\go\pygo-win\BuildTools\kits\10\lib\10.0.22000.0\ucrt\x64 /LIBPATH:z:\h ome\kirr\src\tools\go\pygo-win\BuildTools\kits\10\lib\10.0.22000.0\um\x64 libgolang.lib build\temp.win-amd64-cpython-310\Release\golang/runtime/libpyxruntime.obj /OUT:build\lib.win-amd64-cpython-310\golang\ru ntime\libpyxruntime.dll /IMPLIB:build\lib.win-amd64-cpython-310\golang\runtime\libpyxruntime.lib LINK : fatal error LNK1104: cannot open file 'python310.lib' -> Fix it by providing proper library path for python.dll . We need to do it ourselves only for libpyxruntime dso because for py extensions this is automatically done by distutils out of the box.
-
Kirill Smelkov authored
On Windows rthere is no fcntl golang/runtime\_runtime_gevent.cpp(4811): error C3861: 'S_ISBLK': identifier not found golang/runtime\_runtime_gevent.cpp(4823): error C2039: 'Fcntl': is not a member of 'golang::internal::syscall' .\golang/runtime/internal/syscall.h(36): note: see declaration of 'golang::internal::syscall' golang/runtime\_runtime_gevent.cpp(4823): error C2065: 'F_GETFL': undeclared identifier golang/runtime\_runtime_gevent.cpp(4823): error C3861: 'Fcntl': identifier not found golang/runtime\_runtime_gevent.cpp(4870): error C2065: 'O_ACCMODE': undeclared identifier golang/runtime\_runtime_gevent.cpp(4889): error C2039: 'Fcntl': is not a member of 'golang::internal::syscall' .\golang/runtime/internal/syscall.h(36): note: see declaration of 'golang::internal::syscall' golang/runtime\_runtime_gevent.cpp(4889): error C2065: 'F_SETFL': undeclared identifier golang/runtime\_runtime_gevent.cpp(4889): error C2065: 'O_NONBLOCK': undeclared identifier golang/runtime\_runtime_gevent.cpp(4889): error C3861: 'Fcntl': identifier not found and even if there would be gevent does not provide cooperative version of FileObject for non-POSIX platforms. -> Always use FileObjectThread on windows even for pipes.
-
Kirill Smelkov authored
There is no fcntl on windows. Named pipes can be set into nonblocking mode via SetNamedPipeHandleState(PIPE_NOWAIT).
-