- 11 Feb, 2020 2 commits
-
-
Kirill Smelkov authored
Following errors model in Go and fd95c88a (golang, errors, fmt: Error chaining (C++/Pyx)) let's add support at Python-level for errors to wrap each other and to be inspected/unwrapped: - an error can additionally provide way to unwrap itself, if it provides .Unwrap() method. .__cause__ is not taken into account yet, but will be in a follow-up patch; - errors.Is(err) tests whether an item in error's chain matches target; - `fmt.Errorf("... : %w", ... err)` is similar to `"... : %s" % (..., err)` but resulting error, when unwrapped, will return err. - errors.Unwrap is not exposed as chaining through both .Unwrap() and .__cause__ will need more than just "current element" as unwrapping state (i.e. errors.Unwrap API is insufficient - see next patch), and in practice users of errors.Unwrap() are very seldom. Support for error chaining through .__cause__ will follow in the next patch. Top-level documentation is TODO. See https://blog.golang.org/go1.13-errors for error chaining overview.
-
Kirill Smelkov authored
It is surprising to have an exception class that cannot be derived from. Besides, in the future we'll use subclassing from golang.error as an indicator that an error is a "well-defined" (in simple words - does not need traceback to be interpreted).
-
- 10 Feb, 2020 1 commit
-
-
Kirill Smelkov authored
The first step to expose errors and error chaining to Python: - Add pyerror that wraps a pyx/nogil C-level error and is exposed as golang.error at py level. - py errors must be compared by ==, not by "is" - Add (py) errors.New to create a new error from text. - a C-level error that has .Unwrap, is exposed with .Unwrap at py level, but full py-level chaining will be implemented in a follow-up patch. - py error does not support inheritance yet. Top-level documentation is TODO.
-
- 06 Feb, 2020 1 commit
-
-
Kirill Smelkov authored
Following errors model in Go, let's add support for errors to wrap other errors and to be inspected/unwrapped: - an error can additionally provide way to unwrap itself, if it implements errorWrapper interface; - errors.Unwrap(err) tries to extract wrapped error; - errors.Is(err) tests whether an item in error's chain matches target; - `fmt.errorf("... : %w", ... err)` is similar to `fmt.errorf("... : %s", ... err.c_str())` but resulting error, when unwrapped, will return err. Add C++ implementation for the above + tests. Python analogs will follow in the next patches. Top-level documentation is TODO. See https://blog.golang.org/go1.13-errors for error chaining overview.
-
- 04 Feb, 2020 16 commits
-
-
Kirill Smelkov authored
Package cxx was added in 9785f2d3 (cxx: New package), but the interface that cxx:dict provided turned out to be not optimal: dict.get was returning (v, ok), and dict.pop ----//--- Correct dict.get and dict.pop to return just value, and, similarly to channels API, provide additional dict.get_ and dict.pop_ - extended versions that also return ok: dict.get(k) -> v dict.pop(k) -> v dict.get_(k) -> (v, ok) dict.pop_(k) -> (v, ok) This time add tests.
-
Kirill Smelkov authored
Follow the scheme established and used for all other packages, because we will soon have fmt pyx part which, if named as fmt.pyx, will intersect and conflict with fmt.py .
-
Kirill Smelkov authored
errors.New was added in a245ab56 (errors: New package) without test.
-
Kirill Smelkov authored
-
Kirill Smelkov authored
-
Kirill Smelkov authored
-
Kirill Smelkov authored
Makes understanding which test is it and where when one fails.
-
Kirill Smelkov authored
Currently libgolang_test.cpp contains tests for code in libgolang.cpp and for code that lives in other libgolang packages - sync, fmt, etc. It is becoming tight and we are going to split libgolang_test.cpp and move package tests to their corresponing files - e.g. to sync_test.cpp and the like. Move common assertion utilities into shared header before that as a preparatory step.
-
Kirill Smelkov authored
Just use builtins and cimported things that we have at pyx level.
-
Kirill Smelkov authored
U is preffered way to make sure an object is unicode string.
-
Kirill Smelkov authored
This will allow to integrate qq with u in the next patch. Moving to compiled code for string processing functions is also generally better for performance.
-
Kirill Smelkov authored
With Python3 I've got tired to constantly use .encode() and .decode(); getting exception if original argument was unicode on e.g. b.decode(); getting exception on raw bytes that are invalid UTF-8, not being able to use bytes literal with non-ASCII characters, etc. So instead of this pain provide two functions that make sure an object is either bytes or unicode: - b converts str/unicode/bytes s to UTF-8 encoded bytestring. Bytes input is preserved as-is: b(bytes_input) == bytes_input Unicode input is UTF-8 encoded. The encoding always succeeds. b is reverse operation to u - the following invariant is always true: b(u(bytes_input)) == bytes_input - u converts str/unicode/bytes s to unicode string. Unicode input is preserved as-is: u(unicode_input) == unicode_input Bytes input is UTF-8 decoded. The decoding always succeeds and input information is not lost: non-valid UTF-8 bytes are decoded into surrogate codes ranging from U+DC80 to U+DCFF. u is reverse operation to b - the following invariant is always true: u(b(unicode_input)) == unicode_input NOTE: encoding _and_ decoding *never* fail nor loose information. This is achieved by using 'surrogateescape' error handler on Python3, and providing manual fallback that behaves the same way on Python2. The naming is chosen with the idea so that b(something) resembles b"something", and u(something) resembles u"something". This, even being only a part of strings solution discussed in [1], should help handle byte- and unicode- strings in more robust and distraction free way. Top-level documentation is TODO. [1] zodbtools!13
-
Kirill Smelkov authored
This continues 60f6db6f (libgolang: Provide nil as alias for nullptr and NULL): I've tried to compile pygolang with Clang on my Debian 10 workstation and got: $ CC=clang CXX=clang++ python setup.py build_dso -i In file included from ./golang/fmt.h:32: ./golang/libgolang.h:381:11: error: unknown type name 'nullptr_t'; did you mean 'std::nullptr_t'? constexpr nullptr_t nil = nullptr; ^~~~~~~~~ std::nullptr_t /usr/bin/../lib/gcc/x86_64-linux-gnu/8/../../../../include/x86_64-linux-gnu/c++/8/bits/c++config.h:242:29: note: 'std::nullptr_t' declared here typedef decltype(nullptr) nullptr_t; ^ : In file included from ./golang/context.h In file included from golang/runtime/libgolang.cpp:30: ./golang/libgolang.h:381:11: error: unknown type name 'nullptr_t'; did you mean 'std::nullptr_t'? constexpr nullptr_t nil = nullptr; ^~~~~~~~~ std::nullptr_t /usr/bin/../lib/gcc/x86_64-linux-gnu/8/../../../../include/x86_64-linux-gnu/c++/8/bits/c++config.h:242:29: note: 'std::nullptr_t' declared here typedef decltype(nullptr) nullptr_t; ^ :39: ./golang/libgolang.h:381:11: error: unknown type In file included from golang/fmt.cpp:25: In file included from ./golang/fmt.h:32: ./golang/libgolang.h:421:17: error: unknown type name 'nullptr_t'; did you mean 'std::nullptr_t'? inline chan(nullptr_t) { _ch = nil; } ^~~~~~~~~ std::nullptr_t ... It seems with GCC and Clang under macOS nullptr_t is automatically provided in builtin namespace, while with older Clang on Linux (clang version 7.0.1-8) only in std:: namespace - rightfully as nullptr_t is described to be present there: https://en.cppreference.com/w/cpp/types/nullptr_t This way we either have to correct all occurrences of nullptr_t to std::nullptr_t, or do something similar with providing nil under golang:: . To reduce noise I prefer the later and let it be named as Nil.
-
Kirill Smelkov authored
The code was assigning nil to local, _not_ global _tblockforever. As a result _tblockforever was left set with a test hook even after leaving test context. Fix it. The bug was there starting from 3b241983 (Port/move channels to C/C++/Pyx). Had to change `= nil` to `= NULL` because with nil Cython complains as def __exit__(pypanicWhenBlocked t, typ, val, tb): global _tblockforever _tblockforever = nil ^ ------------------------------------------------------------ golang/_golang_test.pyx:86:25: Cannot assign type 'nullptr_t' to 'void (*)(void) nogil' This is https://github.com/cython/cython/issues/3314.
-
Kirill Smelkov authored
It's a leftover originating from b073f6df (time: Move/Port timers to C++/Pyx nogil).
-
Kirill Smelkov authored
Instead of `pyctx.ctx = nil` it was just `ctx = nil` - i.e. assign nil to local variable instead of changing pyctx instance data. We were not observing this bug because Cython, for C++ fields of cdef classes, automatically emits in-place destructor calls in generated __dealloc__ https://github.com/cython/cython/blob/0.29.14-11-g8c620c388/Cython/Compiler/ModuleNode.py#L1477-L1478 and so this way there was no leak. However we want to be explicit and the code was not correct. Fix it. The bug was there from 2a359791 (context: Move/Port context package to C++/Pyx nogil).
-
- 17 Jan, 2020 3 commits
-
-
Kirill Smelkov authored
Convert Pyx part of the project to use nil instead of NULL. Not every usage of NULL was converted and some places were left to use NULL where changing it to nil currently hits Cython compilation error: https://github.com/cython/cython/issues/3314
-
Kirill Smelkov authored
Convert C++ part of the project to use nil instead of NULL/nullptr. We do not convert pyx part yet, because Cython currently does not understand that nullptr_t has properties of NULL and with e.g. the following change --- a/golang/_context.pyx +++ b/golang/_context.pyx @@ -116,7 +116,7 @@ cdef cppclass _PyValue (_interface, gobject) nogil: __dealloc__(): with gil: obj = <object>this.pyobj - this.pyobj = NULL + this.pyobj = nil Py_DECREF(obj) errors as Error compiling Cython file: ------------------------------------------------------------ ... if __decref(): del self __dealloc__(): with gil: obj = <object>this.pyobj this.pyobj = nil ^ ------------------------------------------------------------ golang/_context.pyx:119:25: Cannot assign type 'nullptr_t' to 'PyObject *' https://github.com/cython/cython/issues/3314
-
Kirill Smelkov authored
Nil is more native to Go.
-
- 13 Jan, 2020 1 commit
-
- 08 Jan, 2020 1 commit
-
-
Kirill Smelkov authored
Projects that use pyx.build (ex. wendelin.core) need recent setuptools_dso fixes: https://github.com/mdavidsaver/setuptools_dso/issues/5 https://github.com/mdavidsaver/setuptools_dso/commit/67d717a6 https://github.com/mdavidsaver/setuptools_dso/commit/e40f5883 https://github.com/mdavidsaver/setuptools_dso/commit/40b492ab Increase setuptools_dso version in pygolang's build requirement for uniformity as well.
-
- 06 Dec, 2019 1 commit
-
-
Kirill Smelkov authored
Providing pygolang-specific DSO is needed because using just setuptools_dso.DSO in external project will result in that e.g. "<golang/libgolang.h>" won't be found.
-
- 27 Nov, 2019 9 commits
-
-
Kirill Smelkov authored
This release is driven by wendelin.core v2 needs with one of the changes being that now most of the library was moved into nogil code and can be used fully from inside nogil world(*). Python modules are now just wrappers of their nogil counterparts. The way for Python and nogil worlds to communicate is also provided. The move to nogil required many other enhancements along the way. Please see CHANGELOG for overview. The move to nogil brought some speedup automatically. Below are benchmark results of this release compared to pygolang v0.0.4 (1573d101) for python-level benchmarks (we have only those at present): (on i7@2.6GHz) thread runtime: name old time/op new time/op delta go 18.3µs ± 0% 18.3µs ± 1% ~ (p=1.000 n=10+10) chan 2.91µs ± 3% 2.99µs ± 5% +2.73% (p=0.022 n=10+10) select 3.57µs ± 3% 3.57µs ± 4% ~ (p=0.720 n=9+10) def 55.0ns ± 0% 54.0ns ± 0% -1.82% (p=0.002 n=8+10) func_def 43.8µs ± 2% 44.1µs ± 1% +0.64% (p=0.035 n=10+9) call 64.0ns ± 0% 66.3ns ± 1% +3.59% (p=0.000 n=10+10) func_call 1.05µs ± 1% 1.24µs ± 0% +17.80% (p=0.000 n=10+7) try_finally 138ns ± 0% 137ns ± 1% -0.51% (p=0.003 n=10+10) defer 2.32µs ± 1% 2.63µs ± 1% +13.52% (p=0.000 n=10+10) workgroup_empty 38.0µs ± 1% 24.1µs ± 1% -36.43% (p=0.000 n=10+10) workgroup_raise 47.7µs ± 1% 28.2µs ± 0% -40.76% (p=0.000 n=10+10) gevent runtime: name old time/op new time/op delta go 16.9µs ± 1% 17.2µs ± 2% +1.94% (p=0.000 n=10+10) chan 7.43µs ± 0% 7.82µs ± 0% +5.34% (p=0.000 n=10+7) select 10.5µs ± 0% 11.2µs ± 0% +6.74% (p=0.000 n=10+10) def 63.0ns ± 0% 57.6ns ± 1% -8.57% (p=0.000 n=9+10) func_def 44.0µs ± 1% 44.2µs ± 1% ~ (p=0.063 n=10+10) call 67.0ns ± 0% 64.0ns ± 0% -4.48% (p=0.002 n=8+10) func_call 1.06µs ± 1% 1.23µs ± 1% +16.50% (p=0.000 n=10+10) try_finally 144ns ± 0% 136ns ± 0% -5.90% (p=0.000 n=10+10) defer 2.37µs ± 1% 2.61µs ± 1% +10.07% (p=0.000 n=10+10) workgroup_empty 57.0µs ± 0% 55.0µs ± 2% -3.53% (p=0.000 n=10+9) workgroup_raise 72.4µs ± 0% 69.6µs ± 6% -3.95% (p=0.035 n=9+10) workgroup_* changes for thread runtime is the speedup I am talking about. defer/func_call slowdown is due to added exception chaining. We did not optimize Python-level defer yet, and if/when that would be needed, it should be possible to optimize by moving pydefer implementation into Cython. (*) go and channels were moved into nogil world in Pygolang v0.0.3 + v0.0.4 . Now it is the rest of the library that was moved with packages like context, time, sync etc. wendelin.core v2 needs nogil to run pinner thread on client side to support isolation property in cooperation with wcfs: since there is a `client -> wcfs -> pinner` loop: - - - - - - | | pinner <------. | | wcfs client -------^ | | - - - - - - client process the pinner thread would deadlock if it tries to take the GIL because client thread can be holding GIL already while accessing wcfs-mmaped memory (think doing e.g. `x = A[i]` in Python).
-
Kirill Smelkov authored
For base functionality we have overview in the readme itself, but for packages we have only their listing with brief overview and no documentation for in-package functionality. Let's have at least links to .h/.pxd/.py where package functionality is documented.
-
Kirill Smelkov authored
See commit 5a99b769 (libgolang: Start providing interfaces) for context.
-
Kirill Smelkov authored
Provide top-level documentation for memory management facilities that was marked as TODO in refptr & co matches. See e.g. the following commits for context: - e82b4fab (libgolang: Objects refcounting (initial draft)) - b2253abf (libgolang: Rename refobj -> object) - fd2a6fab (libgolang: Fix globals atexit race condition of ~refptr vs access from another thread)
-
Kirill Smelkov authored
defer is now part of libgolang API (see 1d153a45 "libgolang: Expose defer as public C++ API"). It should be explained in top-level overview.
-
Kirill Smelkov authored
This amends commit b073f6df: clang was complaining that _Ticker/_Timer were forward-declared as class, but later declared as struct: ./golang/time.h:107:1: warning: '_Ticker' defined as a struct here but previously declared as a class [-Wmismatched-tags] struct _Ticker : object { ^ ./golang/time.h:77:1: note: did you mean struct here? class _Ticker; ^~~~~ struct ./golang/time.h:140:1: warning: '_Timer' defined as a struct here but previously declared as a class [-Wmismatched-tags] struct _Timer : object { ^ ./golang/time.h:78:1: note: did you mean struct here? class _Timer; ^~~~~ struct -> Fix it by using struct. Also used inline style inside refptr.
-
Kirill Smelkov authored
Race condition inside PyThread_release_lock should have been fixed on both CPython/darwin and PyPy/darwin: https://github.com/python/cpython/commit/c5abd63e94fc https://bitbucket.org/pypy/pypy/commits/6cd7a0d1a940 https://bitbucket.org/pypy/pypy/commits/a9d36d6af872 The bug is explained here: https://bugs.python.org/issue38106 https://bitbucket.org/pypy/pypy/issues/3072 The following commits added tests for the bug on Pygolang side: 34b7a1f4 (golang: Expose Sema and Mutex as public Python and Cython/nogil API) 5142460d (libgolang/thread: Add links to upstream PyThread_release_lock bug)
-
Kirill Smelkov authored
Provide string utilities to verify whether string has suffix/prefix, trim it, and split string by a delimiter. The code originated in wcfs codebase in wendelin.core . Pyx/nogil only.
-
Kirill Smelkov authored
With fmt.sprintf() and fmt.errorf() to format strings and errors. The code was extracted from wcfs in wendelin.core . Pyx/nogil only.
-
- 26 Nov, 2019 1 commit
-
-
Kirill Smelkov authored
std::string is frequently too cumbersome. Providing string in golang:: namespace allows to have a more closer feel of a Go environment after `using namespace golang`.
-
- 25 Nov, 2019 2 commits
-
-
Kirill Smelkov authored
This ammends 33cf3113: Kill now unused imports.
-
Kirill Smelkov authored
It was all working on Debian 10, but running tests on Ubuntu 16.04 turned out to fail: $ python -m pytest ================================== test session starts =================================== platform linux2 -- Python 2.7.12, pytest-4.6.6, py-1.8.0, pluggy-0.13.0 rootdir: /home/kirr/src/pygolang collected 0 items / 10 errors ========================================= ERRORS ========================================= ________________________ ERROR collecting golang/_gopath_test.py _________________________ ImportError while importing test module '/home/kirr/src/pygolang/golang/_gopath_test.py'. Hint: make sure your test modules/packages have valid Python names. Traceback: golang/__init__.py:42: in <module> from golang._golang import _pysys_exc_clear as _sys_exc_clear golang/_golang.pyx:35: in init golang._golang _init_libpyxruntime() golang/_golang.pyx:532: in golang._golang._init_libpyxruntime import golang.pyx.runtime E ImportError: /home/kirr/src/pygolang/golang/pyx/../runtime/liblibpyxruntime.so.0.1: undefined symbol: _ZN6golang4sync9WaitGroup3addEi $ c++filt _ZN6golang4sync9WaitGroup3addEi golang::sync::WaitGroup::add(int) So since libpyxruntime is using sync.WaitGroup (and sync.Mutex etc) it should be linking to libgolang where those symbols are provided. Fix it. Fixes: 4fc6e49c (time: Factor-out PyFunc into shared library libpyxruntime.so)
-
- 22 Nov, 2019 2 commits
-
-
Kirill Smelkov authored
A deferred function can raise exception and this exception itself can have .__context__ - consider for example if B1 is raised and its chain is B1->B2->B3. Before calling that deferred function, we save then-current exception A1 into GoFrame.exc_ctx and link-to .exc_ctx after the call. We were previously trying to link-to .exc_ctx from raised exception itself - i.e. B1 in the above example which is not correct: B1 was raised while B2 was being raised ... etc and it was B3 who was raised after A1. The consequence was that A1 was list, since B1 already had non-empty .__context__ -> Fix it by linking-to A1 from B3, not from B1. In other words by linking-to .exc_ctx chain from tail of exception chain of raised exception. We can be sure that updated test is correct because it passes under Python3 where exception chaining is implemented natively. Fixes: bb9a94c3 (golang: Teach defer to chain exceptions (PEP 3134) even on Python2)
-
Kirill Smelkov authored
Defer support for exception chaining on Python2 (see bb9a94c3 "golang: Teach defer to chain exceptions (PEP 3134) even on Python2") simulates PEP 3134 by manually setting and chaining exc .__context__, .__cause__ and .__traceback__: if exceptions are thrown by several deferred functions they are linked into exception chain via .__context__ attribute. Defer support in @func also makes sure that any exception that comes out of a function has all those PEP 3134 attributes and presets them to their default values if exception object did not have them initially. In particular .__context__ is preset to None for first raised exception. There was a logic error in chaining handling: .__context__ was glued to previously raised exception only if current exception object did not have .__context__ attribute at all. And this was failing to chain them if current exception was raised from under another function wrapped in @func, because GoFrame wrapping that function makes sure to set curexc.__context__=None and oops - it was not changed later. -> Fix chaining implementation by gluing .__context__ either if there is no such attribute in current exception, or if .__context__ is None. This is correct to do since .__context__, by its definition, represents implicitly / automatically chained exceptions - contrary to .__cause__ which is explicitly set and would be incorrect to automatically change from None to something. We also know that the end result is the same as Python3 behaviour since updated tests (see bellow) pass OK also when run under Python3 where exceptions chaining is implemented by Python runtime natively. Update test_defer_excchain() in golang_test.py, which verifies how raised exceptions are chained. No need to update testprog/golang_test_defer_excchain.{py,txt} since the test there verifies that our traceback dumper is correctly hooked into Python interpreter - where we know that exceptions are already chained correctly and we verify only that automatic traceback dump takes this chaining into account. Fixes: bb9a94c3 (golang: Teach defer to chain exceptions (PEP 3134) even on Python2)
-