pygolang:pygolang-0.0.6.post2 commitshttps://lab.nexedi.com/nexedi/pygolang/-/commits/pygolang-0.0.6.post22020-04-16T16:57:11+03:00https://lab.nexedi.com/nexedi/pygolang/-/commit/283a155828d20935f75c79828141d08c03f99f24pygolang v0.0.6.post22020-04-16T16:57:11+03:00Kirill Smelkovkirr@nexedi.com
A build fix wrt gevent-1.5 + benchmarks for nogil go and channels.https://lab.nexedi.com/nexedi/pygolang/-/commit/4d667fa3dca61caccc0c9d1c9dc91a7c39f38126Fix build for gevent-1.52020-04-16T16:56:49+03:00Kirill Smelkovkirr@nexedi.com
Starting from gevent >= 1.5 '*.pxd' files for gevent API are no longer
provided, at least in released gevent wheels. This broke pygolang:
Error compiling Cython file:
------------------------------------------------------------
...
# Gevent runtime uses gevent's greenlets and semaphores.
# When sema.acquire() blocks, gevent switches us from current to another greenlet.
IF not PYPY:
from gevent._greenlet cimport Greenlet
^
------------------------------------------------------------
golang/runtime/_runtime_gevent.pyx:28:4: 'gevent/_greenlet.pxd' not found
Since gevent upstream refuses to restore Cython level access[1], let's fix the
build by using gevent bits via Python-level.
Even when used via py import gevent-1.5 brings speed improvement compared to
gevent-1.4 (used via cimport):
(on i7@2.6GHz, gevent runtime)
gevent-1.4 gevent-1.5
(cimport) (py import)
name old time/op new time/op delta
pyx_select_nogil 9.47µs ± 0% 8.74µs ± 0% -7.70% (p=0.000 n=10+9)
pyx_go_nogil 14.3µs ± 1% 12.0µs ± 1% -16.52% (p=0.000 n=10+10)
pyx_chan_nogil 7.10µs ± 1% 6.32µs ± 1% -10.89% (p=0.000 n=10+10)
go 16.0µs ± 2% 13.4µs ± 1% -16.37% (p=0.000 n=10+10)
chan 7.50µs ± 0% 6.79µs ± 0% -9.53% (p=0.000 n=10+10)
select 10.8µs ± 1% 10.0µs ± 1% -6.78% (p=0.000 n=10+10)
Using gevent-1.5 could have been even faster via cimport (it is still
possible to compile and test against gevent installed in development
mode via `pip install -e` because pxd files are there in gevent worktree
and tarball):
gevent-1.5 gevent-1.5
(py import) (cimport)
name old time/op new time/op delta
pyx_select_nogil 8.74µs ± 0% 7.90µs ± 1% -9.60% (p=0.000 n=9+10)
pyx_go_nogil 12.0µs ± 1% 11.2µs ± 2% -6.35% (p=0.000 n=10+10)
pyx_chan_nogil 6.32µs ± 1% 5.89µs ± 0% -6.80% (p=0.000 n=10+9)
go 13.4µs ± 1% 12.4µs ± 1% -7.54% (p=0.000 n=10+9)
chan 6.79µs ± 0% 6.42µs ± 0% -5.47% (p=0.000 n=10+10)
select 10.0µs ± 1% 9.4µs ± 1% -6.39% (p=0.000 n=10+10)
but we cannot use cimport to access gevent-1.5 universally, since pxd are not
shipped in gevent wheel releases.
In the future we might want to change plain version check into compile time
check whether gevent/_greenlet.pxd is actually present or not and use faster
access if yes. Requesting gevent to be installed in non-binary form
might be also an option worth trying.
However plain version check should be ok for now.
[1] <a href="https://github.com/gevent/gevent/issues/1568" rel="nofollow noreferrer noopener" target="_blank">https://github.com/gevent/gevent/issues/1568</a>https://lab.nexedi.com/nexedi/pygolang/-/commit/2114a5603d1cf79bb316271abf26b2fcb31bcb1cgolang: Add benchmarks for nogil go and channels2020-04-16T14:11:48+03:00Kirill Smelkovkirr@nexedi.com
on i7@2.6GHz it looks like:
thread runtime:
name time/op
pyx_select_nogil 2.70µs ±13%
pyx_go_nogil 15.9µs ± 1%
pyx_chan_nogil 2.79µs ± 2%
go 17.6µs ± 0%
chan 3.05µs ± 4%
select 3.62µs ± 4%
gevent runtime (gevent-1.4.0):
name time/op
pyx_select_nogil 9.39µs ± 1%
pyx_go_nogil 15.1µs ± 2%
pyx_chan_nogil 7.10µs ± 1%
go 16.6µs ± 1%
chan 7.47µs ± 1%
select 10.7µs ± 0%https://lab.nexedi.com/nexedi/pygolang/-/commit/874371e29de892fb25163105f0b9f978ece3d38dpygolang v0.0.6.post12020-04-15T17:54:03+03:00Kirill Smelkovkirr@nexedi.com
Just a single change to expose time constants to C++ users (<a href="/nexedi/pygolang/-/commit/2476f47eb2b5e8e6b849d662475e4ca38bb9e06a" data-original="2476f47e" data-link="false" data-link-reference="false" data-project="1156" data-commit="2476f47eb2b5e8e6b849d662475e4ca38bb9e06a" data-reference-type="commit" data-container="body" data-placement="top" data-html="true" title="time: Move constants .pxd -> .h" class="gfm gfm-commit has-tooltip">2476f47e</a>).https://lab.nexedi.com/nexedi/pygolang/-/commit/2476f47eb2b5e8e6b849d662475e4ca38bb9e06atime: Move constants .pxd -> .h2020-03-05T15:14:57+03:00Kirill Smelkovkirr@nexedi.com
This makes them available for C++ users as well.https://lab.nexedi.com/nexedi/pygolang/-/commit/5e1cb5ea6806dd21bcf2806696b57fa801c6b3e7pygolang v0.0.62020-02-28T19:44:06+03:00Kirill Smelkovkirr@nexedi.comhttps://lab.nexedi.com/nexedi/pygolang/-/commit/0561926a15ee63c31b9fe926613b15ab3e34e9abstrconv: Fix b & friends on macos/windows2020-02-28T19:38:07+03:00Kirill Smelkovkirr@nexedi.com
On macos and windows, Python2 is built with --enable-unicode=ucs2, which
makes it to use UTF-16 encoding for unicode characters, and so for
characters higher than U+10000 it uses surrogate encoding with _2_
unicode points, for example:
>>> import sys
>>> sys.maxunicode
65535 <-- NOTE indicates UCS2 build
>>> s = u'\U00012345'
>>> s
u'\U00012345'
>>> s.encode('utf-8')
'\xf0\x92\x8d\x85'
>>> len(s)
2 <-- NOTE _not_ 1
>>> s[0]
u'\ud808'
>>> s[1]
u'\udf45'
This leads to e.g. b tests failing for
# tbytes tunicode
(b"\xf0\x90\x8c\xbc", u'\U0001033c'), # Valid 4 Octet Sequence '𐌼'
> assert b(tunicode) == tbytes
E AssertionError: assert '\xed\xa0\x80\xed\xbc\xbc' == '\xf0\x90\x8c\xbc'
E - \xed\xa0\x80\xed\xbc\xbc
E + \xf0\x90\x8c\xbc
because on UCS2 python build u'\U0001033c' is represented as 2 unicode
points:
>>> s = u'\U0001033c'
>>> len(s)
2
>>> s[0]
u'\ud800'
>>> s[1]
u'\udf3c'
>>> s[0].encode('utf-8')
'\xed\xa0\x80'
>>> s[1].encode('utf-8')
'\xed\xbc\xbc'
-> Fix it by detecting UCS2 build and working around by manually
combining such surrogate unicode pairs appropriately.
A reference on the subject:
<a href="https://matthew-brett.github.io/pydagogue/python_unicode.html#utf-16-ucs2-builds-of-python-and-32-bit-unicode-code-points" rel="nofollow noreferrer noopener" target="_blank">https://matthew-brett.github.io/pydagogue/python_unicode.html#utf-16-ucs2-builds-of-python-and-32-bit-unicode-code-points</a>https://lab.nexedi.com/nexedi/pygolang/-/commit/5cc679ac973d52bf3b6fc83ad807e4da37fc1d5dstrconv: Switch _utf8_decode_rune to return rune ordinal instead of unicode c...2020-02-28T19:38:07+03:00Kirill Smelkovkirr@nexedi.com
This is a preparatory step for the next patch where we'll be fixing
strconv for Python2 builds with --enable-unicode=ucs2, where a unicode
character can be taking _2_ unicode points.
In that general case relying on unicode objects to represent runes is
not good, because many things generally do not work for U+10000 and
above, e.g. ord breaks:
>>> import sys
>>> sys.maxunicode
65535 <-- NOTE indicates UCS2 build
>>> s = u'\U00012345'
>>> s
u'\U00012345'
>>> s.encode('utf-8')
'\xf0\x92\x8d\x85'
>>> len(s)
2 <-- NOTE _not_ 1
>>> ord(s)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: ord() expected a character, but string of length 2 found
so we switch to represent runes as integer, similarly to what Go does.https://lab.nexedi.com/nexedi/pygolang/-/commit/cd67996e4a711282ddf9a0a1a0665f49e61800d9pyx.build: Fix hang under gpython2020-02-28T19:37:30+03:00Kirill Smelkovkirr@nexedi.com
Commit <a href="/nexedi/pygolang/-/commit/8af78fc5a0e16095c1226dbab42707a45a59d0c8" data-original="8af78fc5" data-link="false" data-link-reference="false" data-project="1156" data-commit="8af78fc5a0e16095c1226dbab42707a45a59d0c8" data-reference-type="commit" data-container="body" data-placement="top" data-html="true" title="pyx.build: v↑ setuptools_dso (1.2 -> 1.4)" class="gfm gfm-commit has-tooltip">8af78fc5</a> (pyx.build: v↑ setuptools_dso (1.2 -> 1.4)) upgraded
setuptools_dso to 1.4, but since from
<a href="https://github.com/mdavidsaver/setuptools_dso/commit/3f3ff746" rel="nofollow noreferrer noopener" target="_blank">https://github.com/mdavidsaver/setuptools_dso/commit/3f3ff746</a>
setuptools_dso started to use multiprocessing, pyx.build, when running
under gpython, started to hang, which is a known gevent problem - see
e.g. here: <a href="https://github.com/gevent/gevent/issues/993" rel="nofollow noreferrer noopener" target="_blank">https://github.com/gevent/gevent/issues/993</a>. The problem was
manifesting itself as pyx.build unit test hanging under Python3.
Fix it by installing gevent multiprocessing plugin which is
automatically used/activated by gevent.monkey.patch_all().
geventmp says it is pre-alpha, but by using it we can unhang pyx.build
tests, which is better state than before. The other future possibility
would be to use <a href="https://github.com/jgehrcke/gipc" rel="nofollow noreferrer noopener" target="_blank">https://github.com/jgehrcke/gipc</a> wrapped into
multiprocessing compatible API.https://lab.nexedi.com/nexedi/pygolang/-/commit/80ab5863da765cd0f02c011af28359c0fdc001f5golang, errors, fmt: Provide top-level documentation for error chaining2020-02-27T21:12:23+03:00Kirill Smelkovkirr@nexedi.com
This is top-level documentation for error chaining that was promised
and marked as TODO in
- <a href="/nexedi/pygolang/-/commit/fd95c88a7d97fead98b7ac1efd1d2854833f4203" data-original="fd95c88a" data-link="false" data-link-reference="false" data-project="1156" data-commit="fd95c88a7d97fead98b7ac1efd1d2854833f4203" data-reference-type="commit" data-container="body" data-placement="top" data-html="true" title="golang, errors, fmt: Error chaining (C++/Pyx)" class="gfm gfm-commit has-tooltip">fd95c88a</a> (golang, errors, fmt: Error chaining (C++/Pyx))
- <a href="/nexedi/pygolang/-/commit/177984420ba5b076e4dd79b64334e333b3ed37ce" data-original="17798442" data-link="false" data-link-reference="false" data-project="1156" data-commit="177984420ba5b076e4dd79b64334e333b3ed37ce" data-reference-type="commit" data-container="body" data-placement="top" data-html="true" title="golang: Expose error at Py level" class="gfm gfm-commit has-tooltip">17798442</a> (golang: Expose error at Py level)
- <a href="/nexedi/pygolang/-/commit/78d0c76f8a004adaf4fe2bf30373c0ba9025e5bc" data-original="78d0c76f" data-link="false" data-link-reference="false" data-project="1156" data-commit="78d0c76f8a004adaf4fe2bf30373c0ba9025e5bc" data-reference-type="commit" data-container="body" data-placement="top" data-html="true" title="golang: Teach pyerror to be a base class" class="gfm gfm-commit has-tooltip">78d0c76f</a> (golang: Teach pyerror to be a base class)
- <a href="/nexedi/pygolang/-/commit/337de0d74265b7bd5a13e7c51eb7be1000ac25a7" data-original="337de0d7" data-link="false" data-link-reference="false" data-project="1156" data-commit="337de0d74265b7bd5a13e7c51eb7be1000ac25a7" data-reference-type="commit" data-container="body" data-placement="top" data-html="true" title="golang, errors, fmt: Error chaining (Python)" class="gfm gfm-commit has-tooltip">337de0d7</a> (golang, errors, fmt: Error chaining (Python))
- <a href="/nexedi/pygolang/-/commit/03f88c0b1dd98176dbef31255118b05a941544ec" data-original="03f88c0b" data-link="false" data-link-reference="false" data-project="1156" data-commit="03f88c0b1dd98176dbef31255118b05a941544ec" data-reference-type="commit" data-container="body" data-placement="top" data-html="true" title="errors: Take .__cause__ into account" class="gfm gfm-commit has-tooltip">03f88c0b</a> (errors: Take .__cause__ into account)https://lab.nexedi.com/nexedi/pygolang/-/commit/073d81a84cf0ad70da580a21ac6c03e446687ed6golang: Provide top-level documentation for b and u2020-02-27T21:08:55+03:00Kirill Smelkovkirr@nexedi.com
This provides top-level documentation for b and u that was promised and
marked as TODO in <a href="/nexedi/pygolang/-/commit/bcb95cd55731676911459742abc1284e1e24837a" data-original="bcb95cd5" data-link="false" data-link-reference="false" data-project="1156" data-commit="bcb95cd55731676911459742abc1284e1e24837a" data-reference-type="commit" data-container="body" data-placement="top" data-html="true" title="golang: Provide b, u for strings" class="gfm gfm-commit has-tooltip">bcb95cd5</a> (golang: Provide b, u for strings).https://lab.nexedi.com/nexedi/pygolang/-/commit/66e112763c8f742e377e0a11b4834115d60b4730golang: Make sure that pychan != pychan works correctly2020-02-27T15:02:47+03:00Kirill Smelkovkirr@nexedi.com
Pychan provides __eq__ (see <a href="/nexedi/pygolang/-/commit/2c8063f46dac6059e7e27c24db9999b7ab615cc6" data-original="2c8063f4" data-link="false" data-link-reference="false" data-project="1156" data-commit="2c8063f46dac6059e7e27c24db9999b7ab615cc6" data-reference-type="commit" data-container="body" data-placement="top" data-html="true" title='*: Channels must be compared by ==, not by "is" even for nilchan' class="gfm gfm-commit has-tooltip">2c8063f4</a> "*: Channels must be compared by
==, not by "is" even for nilchan"), but does not provide __ne__. At the
same time in <a href="/nexedi/pygolang/-/commit/177984420ba5b076e4dd79b64334e333b3ed37ce" data-original="17798442" data-link="false" data-link-reference="false" data-project="1156" data-commit="177984420ba5b076e4dd79b64334e333b3ed37ce" data-reference-type="commit" data-container="body" data-placement="top" data-html="true" title="golang: Expose error at Py level" class="gfm gfm-commit has-tooltip">17798442</a> (golang: Expose error at Py level) we had to
define both pyerror.__eq__ and pyerror.__ne__ because without __ne__
pyerror != pyerror was not working correctly.
As it turns out pychan != pychan already works ok, because pychan does
not have base class and for that case cython automatically generates
__ne__ based on __eq__:
<a href="https://github.com/cython/cython/blob/0.29.14-629-ga73815042/Cython/Compiler/ModuleNode.py#L1963-L1976" rel="nofollow noreferrer noopener" target="_blank">https://github.com/cython/cython/blob/0.29.14-629-ga73815042/Cython/Compiler/ModuleNode.py#L1963-L1976</a>
<a href="https://github.com/cython/cython/commit/b75d2942afab" rel="nofollow noreferrer noopener" target="_blank">https://github.com/cython/cython/commit/b75d2942afab</a>
Add corresponding comment and extend tests to make sure it is indeed so.https://lab.nexedi.com/nexedi/pygolang/-/commit/a9345a9888c5e4941dcc52961bbf081a7df17946sync.RWMutex: Teach it to downgrade from write-locked into read-locked state2020-02-20T18:15:28+03:00Kirill Smelkovkirr@nexedi.com
Go version does not provide this, but the topic of sync.RWMutex
downgrading was raised up several times, at least
<a href="https://github.com/golang/go/issues/4026" rel="nofollow noreferrer noopener" target="_blank">https://github.com/golang/go/issues/4026</a>
<a href="https://github.com/golang/go/issues/23513" rel="nofollow noreferrer noopener" target="_blank">https://github.com/golang/go/issues/23513</a>
<a href="https://groups.google.com/forum/#!topic/golang-nuts/MmIDUzl8HA0" rel="nofollow noreferrer noopener" target="_blank">https://groups.google.com/forum/#!topic/golang-nuts/MmIDUzl8HA0</a>
...
Atomic downgrading is often useful to avoid race window in between
Unlock and RLock and, as consequence, having the need to recheck things
after RLock.
We can put this complexity and logic into well-defined RWMutex primitive
instead of throwing it to be solved by every RWMutex user.https://lab.nexedi.com/nexedi/pygolang/-/commit/1ad3c2d5cc0a9321cbd773c2723633fe725f06f0sync += RWMutex2020-02-17T14:03:48+03:00Kirill Smelkovkirr@nexedi.com
Provide sync.RWMutex that can be useful for cases when there are
multiple simultaneous readers and more seldom writer(s).
This implements readers-writer mutex with preference for writers
similarly to Go version.https://lab.nexedi.com/nexedi/pygolang/-/commit/36ab859c047f50576b028c0ef194e01926aa85abio: New package that mirrors Go's io (stub)2020-02-12T13:56:42+03:00Kirill Smelkovkirr@nexedi.com
Only io.EOF and io.ErrUnexpectedEOF for now.
Moved here from wcfs from wendelin.core.https://lab.nexedi.com/nexedi/pygolang/-/commit/03f88c0b1dd98176dbef31255118b05a941544ecerrors: Take .__cause__ into account2020-02-11T13:33:07+03:00Kirill Smelkovkirr@nexedi.com
A Python error can have links to other errors by means of both .Unwrap()
and .__cause__ . These ways are both explicit and so should be treated
by e.g. errors.Is as present in error's error chain.
It is a bit unclear, at least initially, how to linearise and order
error chain traversal in divergence points - for exception objects where
both .Unwrap() and .__cause__ are !None. However more closer look
suggests linearisation rule to traverse into .__cause__ after going
through .Unwrap() part - please see details in documentation added into
_error.pyx
-> Teach errors.Is to do this traversal, and this way now e.g. exception
raised as
raise X from Y
will be treated by errors.Is as being both X and Y, even if any of X or Y
also has its own error chain via .Unwrap().
Top-level documentation is TODO.https://lab.nexedi.com/nexedi/pygolang/-/commit/337de0d74265b7bd5a13e7c51eb7be1000ac25a7golang, errors, fmt: Error chaining (Python)2020-02-11T13:24:32+03:00Kirill Smelkovkirr@nexedi.com
Following errors model in Go and <a href="/nexedi/pygolang/-/commit/fd95c88a7d97fead98b7ac1efd1d2854833f4203" data-original="fd95c88a" data-link="false" data-link-reference="false" data-project="1156" data-commit="fd95c88a7d97fead98b7ac1efd1d2854833f4203" data-reference-type="commit" data-container="body" data-placement="top" data-html="true" title="golang, errors, fmt: Error chaining (C++/Pyx)" class="gfm gfm-commit has-tooltip">fd95c88a</a> (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 <a href="https://blog.golang.org/go1.13-errors" rel="nofollow noreferrer noopener" target="_blank">https://blog.golang.org/go1.13-errors</a> for error chaining overview.https://lab.nexedi.com/nexedi/pygolang/-/commit/78d0c76f8a004adaf4fe2bf30373c0ba9025e5bcgolang: Teach pyerror to be a base class2020-02-11T09:42:04+03:00Kirill Smelkovkirr@nexedi.com
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).https://lab.nexedi.com/nexedi/pygolang/-/commit/177984420ba5b076e4dd79b64334e333b3ed37cegolang: Expose error at Py level2020-02-10T21:36:40+03:00Kirill Smelkovkirr@nexedi.com
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.https://lab.nexedi.com/nexedi/pygolang/-/commit/fd95c88a7d97fead98b7ac1efd1d2854833f4203golang, errors, fmt: Error chaining (C++/Pyx)2020-02-06T18:47:36+03:00Kirill Smelkovkirr@nexedi.com
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 <a href="https://blog.golang.org/go1.13-errors" rel="nofollow noreferrer noopener" target="_blank">https://blog.golang.org/go1.13-errors</a> for error chaining overview.https://lab.nexedi.com/nexedi/pygolang/-/commit/58fcdd87e63cf67b4b545f260729ce388d7efbfacxx: Correct dict interface2020-02-04T10:52:56+03:00Kirill Smelkovkirr@nexedi.com
Package cxx was added in <a href="/nexedi/pygolang/-/commit/9785f2d324ab91375c3f369bf0a24bcb64aaf97a" data-original="9785f2d3" data-link="false" data-link-reference="false" data-project="1156" data-commit="9785f2d324ab91375c3f369bf0a24bcb64aaf97a" data-reference-type="commit" data-container="body" data-placement="top" data-html="true" title="cxx: New package" class="gfm gfm-commit has-tooltip">9785f2d3</a> (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.https://lab.nexedi.com/nexedi/pygolang/-/commit/dbd051f10e733088fc89eb3ce98c3fac7af704f6golang: fmt.pxd -> _fmt.pxd + fmt.pxd import redirector2020-02-04T10:52:56+03:00Kirill Smelkovkirr@nexedi.com
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 .https://lab.nexedi.com/nexedi/pygolang/-/commit/288e16a7c037d36993a099649c707931dd0fc51eerrors: Test for New (C++)2020-02-04T10:52:56+03:00Kirill Smelkovkirr@nexedi.com
errors.New was added in <a href="/kirr/pygolang/-/commit/a245ab56e1c8b555ed01e091b55b9f80d88e3dee" data-original="a245ab56" data-link="false" data-link-reference="false" data-project="1158" data-commit="a245ab56e1c8b555ed01e091b55b9f80d88e3dee" data-reference-type="commit" data-container="body" data-placement="top" data-html="true" title="errors: New package" class="gfm gfm-commit has-tooltip">a245ab56</a> (errors: New package) without test.https://lab.nexedi.com/nexedi/pygolang/-/commit/c7c07828db411e4e87d9269bf0197bc81729c033fmt: tests: Move into fmt_test.cpp from <- libgolang_test.cpp2020-02-04T10:52:56+03:00Kirill Smelkovkirr@nexedi.comhttps://lab.nexedi.com/nexedi/pygolang/-/commit/666bc325b357a0f3f84e9d3b1ec800e032144eecstrings: tests: Move into strings_test.cpp from <- libgolang_test.cpp2020-02-04T10:52:56+03:00Kirill Smelkovkirr@nexedi.comhttps://lab.nexedi.com/nexedi/pygolang/-/commit/617b51b26d5e8ea6ea2c3493e04be8c1c8a3a75esync: tests: Move into sync_test.cpp from <- libgolang_test.cpp2020-02-04T10:52:56+03:00Kirill Smelkovkirr@nexedi.comhttps://lab.nexedi.com/nexedi/pygolang/-/commit/ff2ed5fe260be5fb983bf73947accbd6f97f0931golang: testing: Provide file and line for a failing ASSERT_EQ2020-02-04T10:52:56+03:00Kirill Smelkovkirr@nexedi.com
Makes understanding which test is it and where when one fails.https://lab.nexedi.com/nexedi/pygolang/-/commit/46a6f424a084e1a921b5d74c5339bbdca166734clibgolang: tests: Factor out common testing functionality into shared place2020-02-04T10:52:56+03:00Kirill Smelkovkirr@nexedi.com
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.https://lab.nexedi.com/nexedi/pygolang/-/commit/e028cf28d17fd36707d3283886d2e956f739f4e7golang: qq: Don't depend on six2020-02-04T10:52:56+03:00Kirill Smelkovkirr@nexedi.com
Just use builtins and cimported things that we have at pyx level.https://lab.nexedi.com/nexedi/pygolang/-/commit/3073ac988481b2dfbd8742175838f0d77824649dgolang: qq: Use u for UTF-8 decoding2020-02-04T10:52:56+03:00Kirill Smelkovkirr@nexedi.com
U is preffered way to make sure an object is unicode string.https://lab.nexedi.com/nexedi/pygolang/-/commit/8c459a99a24ca491dd2732f7683425b98f00f9fbgcompat: Move qq into golang2020-02-04T10:52:56+03:00Kirill Smelkovkirr@nexedi.com
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.https://lab.nexedi.com/nexedi/pygolang/-/commit/bcb95cd55731676911459742abc1284e1e24837agolang: Provide b, u for strings2020-02-04T10:52:56+03:00Kirill Smelkovkirr@nexedi.com
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] <a href="https://lab.nexedi.com/nexedi/zodbtools/merge_requests/13" data-original="https://lab.nexedi.com/nexedi/zodbtools/merge_requests/13" data-link="false" data-link-reference="true" data-project="462" data-merge-request="3004" data-project-path="nexedi/zodbtools" data-iid="13" data-mr-title="More python3 compatibility" data-reference-type="merge_request" data-container="body" data-placement="top" data-html="true" title="" class="gfm gfm-merge_request">nexedi/zodbtools!13</a>https://lab.nexedi.com/nexedi/pygolang/-/commit/230c81c4e37a179d2070415f92bc4f53aadb98f5libgolang: Provide Nil as alias for std::nullptr_t2020-02-04T10:52:56+03:00Kirill Smelkovkirr@nexedi.com
This continues <a href="/kirr/pygolang/-/commit/60f6db6ff3bda1b88ec958e7f55e45fa5ce13eaf" data-original="60f6db6f" data-link="false" data-link-reference="false" data-project="1158" data-commit="60f6db6ff3bda1b88ec958e7f55e45fa5ce13eaf" data-reference-type="commit" data-container="body" data-placement="top" data-html="true" title="libgolang: Provide nil as alias for nullptr and NULL" class="gfm gfm-commit has-tooltip">60f6db6f</a> (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:
<a href="https://en.cppreference.com/w/cpp/types/nullptr_t" rel="nofollow noreferrer noopener" target="_blank">https://en.cppreference.com/w/cpp/types/nullptr_t</a>
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.https://lab.nexedi.com/nexedi/pygolang/-/commit/b5a2f9dc81303efe582a84ab45e7f7a95c65cdc3golang: tests: pypanicWhenBlocked: Fix thinko in __exit__2020-02-04T10:52:56+03:00Kirill Smelkovkirr@nexedi.com
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 <a href="/kirr/pygolang/-/commit/3b241983814e5836abae004d8549a68572731328" data-original="3b241983" data-link="false" data-link-reference="false" data-project="1158" data-commit="3b241983814e5836abae004d8549a68572731328" data-reference-type="commit" data-container="body" data-placement="top" data-html="true" title="Port/move channels to C/C++/Pyx" class="gfm gfm-commit has-tooltip">3b241983</a> (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 <a href="https://github.com/cython/cython/issues/3314" rel="nofollow noreferrer noopener" target="_blank">https://github.com/cython/cython/issues/3314</a>.https://lab.nexedi.com/nexedi/pygolang/-/commit/9b63ec01fca5e0474bbf15da69f4d9b1a2874905time: Kill unused nullptr_t cimport2020-02-04T10:52:56+03:00Kirill Smelkovkirr@nexedi.com
It's a leftover originating from <a href="/kirr/pygolang/-/commit/b073f6df1caee2a2ce7974e777da7d4c8f6c4360" data-original="b073f6df" data-link="false" data-link-reference="false" data-project="1158" data-commit="b073f6df1caee2a2ce7974e777da7d4c8f6c4360" data-reference-type="commit" data-container="body" data-placement="top" data-html="true" title="time: Move/Port timers to C++/Pyx nogil" class="gfm gfm-commit has-tooltip">b073f6df</a> (time: Move/Port timers to
C++/Pyx nogil).https://lab.nexedi.com/nexedi/pygolang/-/commit/371d50b59914e1105a71d4daaa28f6c9b2174c66context: Fix thinko/typo in PyContext.__dealloc__2020-02-04T10:52:33+03:00Kirill Smelkovkirr@nexedi.com
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__
<a href="https://github.com/cython/cython/blob/0.29.14-11-g8c620c388/Cython/Compiler/ModuleNode.py#L1477-L1478" rel="nofollow noreferrer noopener" target="_blank">https://github.com/cython/cython/blob/0.29.14-11-g8c620c388/Cython/Compiler/ModuleNode.py#L1477-L1478</a>
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 <a href="/nexedi/pygolang/-/commit/2a359791b31edaac43763570f879503ea4cb9b77" data-original="2a359791" data-link="false" data-link-reference="false" data-project="1156" data-commit="2a359791b31edaac43763570f879503ea4cb9b77" data-reference-type="commit" data-container="body" data-placement="top" data-html="true" title="context: Move/Port context package to C++/Pyx nogil" class="gfm gfm-commit has-tooltip">2a359791</a> (context: Move/Port context package to
C++/Pyx nogil).https://lab.nexedi.com/nexedi/pygolang/-/commit/01ade7ac3b06eb6fecc733f1ee00efc50d5a8632*: NULL -> nil (Pyx and only where we can)2020-01-17T12:57:02+03:00Kirill Smelkovkirr@nexedi.com
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:
<a href="https://github.com/cython/cython/issues/3314" rel="nofollow noreferrer noopener" target="_blank">https://github.com/cython/cython/issues/3314</a>https://lab.nexedi.com/nexedi/pygolang/-/commit/fc1c3e24f5a885ab9140017592c2115934500620*: NULL/nullptr -> nil (C++ only)2020-01-17T12:04:58+03:00Kirill Smelkovkirr@nexedi.com
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 *'
<a href="https://github.com/cython/cython/issues/3314" rel="nofollow noreferrer noopener" target="_blank">https://github.com/cython/cython/issues/3314</a>https://lab.nexedi.com/nexedi/pygolang/-/commit/60f6db6ff3bda1b88ec958e7f55e45fa5ce13eaflibgolang: Provide nil as alias for nullptr and NULL2020-01-17T11:59:15+03:00Kirill Smelkovkirr@nexedi.com
Nil is more native to Go.https://lab.nexedi.com/nexedi/pygolang/-/commit/d0179796d994b26154423983bb705cef77a2737async: Refer to go123 who now provides xsync.WorkGroup2020-01-13T15:20:43+03:00Kirill Smelkovkirr@nexedi.com
<a href="https://godoc.org/lab.nexedi.com/kirr/go123/xsync#WorkGroup" rel="nofollow noreferrer noopener" target="_blank">https://godoc.org/lab.nexedi.com/kirr/go123/xsync#WorkGroup</a>
<a href="https://lab.nexedi.com/kirr/go123/commit/515a6d14" data-original="https://lab.nexedi.com/kirr/go123/commit/515a6d14" data-link="false" data-link-reference="true" data-project="480" data-commit="515a6d14aa6b3aa346702367e787cc2729bb34bc" data-reference-type="commit" data-container="body" data-placement="top" data-html="true" title="xsync: New package with xsync.WorkGroup" class="gfm gfm-commit has-tooltip">kirr/go123@515a6d14</a>