1. 11 Dec, 2020 2 commits
    • Kirill Smelkov's avatar
      sync.WorkGroup: Provide "with" support · 6eb80104
      Kirill Smelkov authored
      So that it becomes possible to write
      
          with WorkGroup(ctx) as wg:
              wg.go(f1)
              wg.go(f2)
      
      instead of
      
          wg = WorkGroup(ctx)
          defer(wg.wait)
          wg.go(f1)
          wg.go(f2)
      
      or
      
          wg = WorkGroup(ctx)
          wg.go(f1)
          wg.go(f2)
          wg.wait()
      
      This is sometimes handy and is referred to as "structured concurrency"
      in Python world.
      
      sync.Sema, sync.Mutex, sync.RWMutex already support "with".
      sync.WaitGroup is imho too low-level, but we might consider adding
      "with" support for it in the future as well.
      
      In general pygolang way is to use defer instead of plugging all classes
      with __enter__/__exit__ "with" support, but for small well-known class of
      concurrency-related things its seems "with" support is worth it:
      
      - having "with" for sync.Mutex+co allows it to be used as a drop-in
        replacement instead of threading.Lock+co, and
      - having "with" for sync.WorkGroup - the most commonly-used tool to
        spawn jobs and wait for their completion - makes it on-par with
        "structured concurrency".
      
      /reviewed-on nexedi/pygolang!12
      6eb80104
    • Kirill Smelkov's avatar
      sync.WorkGroup: Fix typo in wait · 85257b2a
      Kirill Smelkov authored
      WorkGroup methods work on PyWorkGroup, not on PyWaitGroup.
      This probably used to work because Cython ignores (?) provided type of self?
      
      /reviewed-on nexedi/pygolang!12
      85257b2a
  2. 10 Dec, 2020 1 commit
    • Kirill Smelkov's avatar
      gpython: tests: Skip test_pymain_run_via_relpath on SlapOS · f15459b9
      Kirill Smelkov authored
      Similarly to test_pymain_syspath we cannot run this test on SlapOS because with
      buildout raw underlying python interpreter does not have access to eggs with
      which gpython script was generated.
      
      See 0fa9d6e7 and 92bb5bcc for details.
      
      Without this patch running pygolang tests fails on SlapOS as shown below:
      
          (pygolang-env) slapuser34@vifibcloud-rapidspace-hosting-007:~/srv/runner/software/44fe7dd3f13ecd100894c6368a35c055/parts/pygolang-dev$ gpython -m pytest -vsx -k relpath
          ================================================= test session starts ==================================================
          platform linux2 -- Python 2.7.18, pytest-4.6.11, py-1.9.0, pluggy-0.13.1 -- /srv/slapgrid/slappart34/srv/runner/software/44fe7dd3f13ecd100894c6368a35c055/bin/gpython
          cachedir: .pytest_cache
          rootdir: /srv/slapgrid/slappart34/srv/runner/software/44fe7dd3f13ecd100894c6368a35c055/parts/pygolang-dev
          collected 115 items / 114 deselected / 1 selected
      
          gpython/gpython_test.py::test_pymain_run_via_relpath Traceback (most recent call last):
            File "./__init__.py", line 511, in <module>
              main()
            File "./__init__.py", line 395, in main
              pymain(argv, init)
            File "./__init__.py", line 217, in pymain
              init()
            File "./__init__.py", line 364, in init
              import gevent
          ImportError: No module named gevent
          FAILED
      
          ======================================================= FAILURES =======================================================
          _____________________________________________ test_pymain_run_via_relpath ______________________________________________
      
              @gpython_only
              def test_pymain_run_via_relpath():
                  argv = ['-c',  'import sys; print(sys.version)']
                  out1 = pyout(                    argv, pyexe=sys.executable)
          >       out2 = pyout(['./__init__.py'] + argv, pyexe=sys._gpy_underlying_executable, cwd=here)
      
          gpython/gpython_test.py:301:
          _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
          golang/golang_test.py:1842: in pyout
              return pyrun(argv, stdin=stdin, stdout=stdout, stderr=stderr, **kw)
          _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
      
          argv = ['./__init__.py', '-c', 'import sys; print(sys.version)'], stdin = None, stdout = '', stderr = None
          kw = {'cwd': '/srv/slapgrid/slappart34/srv/runner/software/44fe7dd3f13ecd100894c6368a35c055/parts/pygolang-dev/gpython', 'pyexe': '/srv/slapgrid/slappart34/srv//runner//shared/python2.7/44578f5389723084b136574c34bc8023/bin/python2.7'}
          retcode = 1
      
              def pyrun(argv, stdin=None, stdout=None, stderr=None, **kw):
                  retcode, stdout, stderr = _pyrun(argv, stdin=stdin, stdout=stdout, stderr=stderr, **kw)
                  if retcode:
          >           raise RuntimeError(' '.join(argv) + '\n' + (stderr and str(stderr) or '(failed)'))
          E           RuntimeError: ./__init__.py -c import sys; print(sys.version)
          E           (failed)
      
          golang/golang_test.py:1836: RuntimeError
          ======================================= 1 failed, 114 deselected in 0.73 seconds =======================================
      
      Fixes 076cdd8f (gpython: Fix crash when invoked as e.g. ./bin/gpython).
      
      /reviewed-on nexedi/pygolang!11
      f15459b9
  3. 06 Dec, 2020 1 commit
  4. 02 Dec, 2020 2 commits
  5. 01 Dec, 2020 1 commit
  6. 27 Nov, 2020 1 commit
  7. 26 Nov, 2020 7 commits
    • Kirill Smelkov's avatar
      gpython: Implement -O · 8564dfdd
      Kirill Smelkov authored
      Let's teach gpython and pymain about -O because buildout calls `python -O`
      to byte-compile python sources in optimized mode:
      
      slapos!862 (comment 121470)
      
      When seeing -O, we take the approach to reexecute underlying python with
      -O, so that e.g.
      
      	gpython -O file.py
      
      becomes executed as
      
      	python -O gpython file.py
      
      This ensures correctness. The same approach could be used to implement
      support for e.g. -S and other low-level options.
      
      An earlier attempt to implement -O without reexecution can be seen at
      
      !7
      
      together with list of problems that arise via that way.
      
      Original idea to reexecute itself come from @jerome.
      8564dfdd
    • Kirill Smelkov's avatar
      gpython: Fix crash when invoked as e.g. ./bin/gpython · 076cdd8f
      Kirill Smelkov authored
      There was an assert because sys.path[0] is setup as realpath (real, not
      relative), but if exe was given as relative path it was raising like
      below:
      
          gpython/gpython_test.py::test_pymain_run_via_relpath GPython 0.0.7.post1 [gevent 20.9.0] / CPython 3.8.6
          Traceback (most recent call last):
            File "./__init__.py", line 482, in <module>
              main()
            File "./__init__.py", line 366, in main
              pymain(argv, init)
            File "./__init__.py", line 82, in pymain
              raise RuntimeError('pymain: internal error: sys.path[0] was not set by underlying python to dirname(exe):'
          RuntimeError: pymain: internal error: sys.path[0] was not set by underlying python to dirname(exe):
      
                  exe:    ./__init__.py
                  sys.path[0]:    /home/kirr/src/tools/go/pygolang-master/gpython
          FAILED
      
      -> Fix it by setting up exe as realpath.
      076cdd8f
    • Kirill Smelkov's avatar
      gpython: Move sys.executable setup from main to pymain · 11b367c6
      Kirill Smelkov authored
      This is generic step and should be done under both gpython and standard
      python. Handling sys.executable inside pymain offloads users from
      setting up sys.executable by themselves, e.g. as in here:
      
      https://lab.nexedi.com/nexedi/slapos/blob/46ed2afe/component/pygolang/buildout.cfg#L39-43
      11b367c6
    • Kirill Smelkov's avatar
      gpython: Rework pymain interface to accept python exe as argv[0] · 21756bd3
      Kirill Smelkov authored
      In other words pymain now requires to be passed in full argv when
      called. We will need exe=argv[0] in a followup patch to be able to
      reexecute underlying python interpreter when given options like -O, -S,
      etc...
      
      This is change in behaviour and in general must come with changing
      pymain name - e.g. to pymain2 - so that old pymain continues to work as
      before. However since there are not so many known pymain users, we can
      probably do this change in place since we'll care ourselves about all
      those users:
      
      - [python-interpreter] in SlapOS:
        https://lab.nexedi.com/nexedi/slapos/blob/46ed2afe/component/pygolang/buildout.cfg#L30-53
      
      - pyruntraced in Go123:
        https://lab.nexedi.com/kirr/go123/blob/96046edf/tracing/cmd/pyruntraced
      
      - zobjtrace in ZODB:
        https://lab.nexedi.com/kirr/ZODB/blob/07c21671/zobjtrace
      
      So I hope it is ok.
      21756bd3
    • Kirill Smelkov's avatar
      gpython: Factor-out options parsing into getopt-style _IGetOpt helper · 26058b5b
      Kirill Smelkov authored
      Python allows multiple single-letter options and their arguments to be
      coming on single argument, for example:
      
      	python -OQc'print 1'
      	python -OQc 'print 1'
      	python -OQ -c 'print 1'
      	etc...
      
      We are currently trying to handle that at every option, but even though
      it kind of works, it is limited and will break once we will start adding
      options.
      
      -> Refactor options parsing into getopt-style helper. We cannot use
      getopt itself because it will complain e.g. on `gpython file.py
      --my-custom-opt` that my-custom-opt is unexpected.
      26058b5b
    • Jérome Perrin's avatar
      gpython: tests: check command executed with -c do not use print function on PY2 · 167912d3
      Jérome Perrin authored
      follow up of 64088e8a (gpython: Don't inherit __future__ when executing
      scripts, 2020-11-26)
      
      /reviewed-by @kirr
      /reviewed-on nexedi/pygolang!9
      167912d3
    • Jérome Perrin's avatar
      gpython: Don't inherit __future__ when executing scripts · 64088e8a
      Jérome Perrin authored
      Because we use execfile to emulate "python script.py" invocation, future
      enabled in gpython main script are also enabled in "script.py" and because
      we use print_function feature, it was also applied in "script.py".
      On python 2 when "script.py" uses print statements they were considered as
      SyntaxError.
      
      Hopefuly, compile has a `dont_inherit` flag which does exactly what we need
      here: compile the script without inheriting futures enabled, so we use
      compile with this flag.
      
      /reviewed-by @kirr
      /reviewed-on nexedi/pygolang!8
      64088e8a
  8. 02 Nov, 2020 1 commit
  9. 14 Oct, 2020 5 commits
  10. 22 Sep, 2020 6 commits
    • Kirill Smelkov's avatar
      pygolang v0.0.7 · 73fdea50
      Kirill Smelkov authored
      73fdea50
    • Kirill Smelkov's avatar
      gpython: Fix pymain to properly setup sys.path (take 2) · fb98e594
      Kirill Smelkov authored
      This continues 6b4990f6 (gpython: Fix pymain to properly setup
      sys.path[0]) - now we add test and verify that gpython actually sets
      sys.path in the same way as underlying python does:
      
      - don't add directory of gpython to sys.path
      - for `gpython file` add to sys.path[0] realpath(dir(file)) instead of
        dir(file)  (see PySys_SetArgvEx for the reference, and else - if we do
        not make this change - added test breaks)
      - for `gpython -m mod` add to sys.path[0] realpath('') instead of ''.
        This exactly matches PY3 behaviour, while PY2 behaviour is to add ''
        However PY3 behaviour
      
          * is more sane, and
          * fixes test_defer_excchain_traceback on py27-gevent
      
        -> so we stick to it.
      
      Now all tests pass again.
      fb98e594
    • Kirill Smelkov's avatar
      gpython: Preimport golang and gevent from exactly the same place as std python would do · 1f6f31cd
      Kirill Smelkov authored
      GPython preimports golang and gevent, but until now, it was preimporting
      them before adjusting sys.path according to given -c/-m/file/... And
      this was leading to difference in behaviour with standard Python where
      e.g. `import golang` might result in different files loaded if e.g.
      golang/ is there on cwd and -c/-m was given.
      
      -> Rework gpython startup so that golang/gevent preimport happens after
      sys.path initialization.
      
      This fixes `tox -e py27-gevent` which was previously failing on
      test_defer_excchain_dump_pytest / test_defer_excchain_dump_ipython
      because dumped paths were different than expected ones.
      
      It, however, breaks test_defer_excchain_traceback on py27-gevent.  ->
      We'll do more fixups to sys.path handling in the next patch which will
      fix that failure as well.
      1f6f31cd
    • Kirill Smelkov's avatar
      gpython: Move code to handle -V to "start interpreter" phase · 51925488
      Kirill Smelkov authored
      We'll need this in the next patch, where golang/gevent preimport will be
      moved from "before call to pymain", to "in between option parsing and
      interpreter start".
      51925488
    • Kirill Smelkov's avatar
      golang: tests: Fix Pytest integration wrt python3-dbg · a1ac2a45
      Kirill Smelkov authored
      There, with pytest 6.0.x, pytest emits its internal deprecation warning
      (the usage of deprecated attribute is inside pytest):
      
          .../_pytest/compat.py:340: PytestDeprecationWarning: The TerminalReporter.writer attribute is deprecated, use TerminalReporter._tw instead at your own risk.
          See https://docs.pytest.org/en/stable/deprecations.html#terminalreporter-writer for more information.
            return getattr(object, name, default)
      
      Which leads to test_defer_excchain_dump_pytest failure since this test
      verifies stderr to be empty:
      
              def test_defer_excchain_dump_pytest():
                  tbok = readfile(dir_testprog + "/golang_test_defer_excchain.txt-pytest")
                  retcode, stdout, stderr = _pyrun(["-m", "pytest", "-o", "python_functions=main",
                                              "--tb=short", "golang_test_defer_excchain.py"],
                                              cwd=dir_testprog, stdout=PIPE, stderr=PIPE)
                  assert retcode != 0, (stdout, stderr)
          >       assert stderr == b""
          E       AssertionError: assert b'/home/kirr/...e, default)\n' == b''
          E         Full diff:
          E         - b''
          E         + (
          E         +  b'/home/kirr/src/tools/go/py3dbg.venv/lib/python3.8/site-packages/_pytest/comp'
          E         +  b'at.py:340: PytestDeprecationWarning: The TerminalReporter.writer attribute i'
          E         +  b's deprecated, use TerminalReporter._tw instead at your own risk.\nSee htt'
          E         +  b'ps://docs.pytest.org/en/stable/deprecations.html#terminalreporter-writer for'...
          E
          E         ...Full output truncated (3 lines hidden), use '-vv' to show
      
      -> Fix it by not letting spawned pytest to emit deprecation warnings in that test.
      a1ac2a45
    • Kirill Smelkov's avatar
      gpython: Implement -W · a0016938
      Kirill Smelkov authored
      We'll need warnings control in the next patch to fix Pytest integration
      wrt python3-dbg with `-W ignore::DeprecationWarning`.
      a0016938
  11. 21 Sep, 2020 1 commit
    • Kirill Smelkov's avatar
      gpython: Reorganize options parsing · b47edf42
      Kirill Smelkov authored
      Reorganize parsiong of command line options so that first all options are
      parsed in a loop, and only after that a module/file/command is executed.
      
      This is needed as preparatory step for next patch: there we'll add
      support for -W, and `-W arg` can be given multiple times and has to be
      processed multiple times by creating multiple corresponding warning
      filters. Because those warning filters has to be applied uniformly to
      all 4 codepaths of execution phase (-m/-c/file/interactive console), it
      makes sense to move execution phase to after options parsing and inject
      common runtime preparatory steps right before that.
      
      This logic generally applies not only to -W, but to all other python
      options - e.g. -Q,-u,...
      b47edf42
  12. 18 Sep, 2020 3 commits
    • Kirill Smelkov's avatar
      golang: tests: Fix TSAN/ASAN wrt Debian testing · 49bb8dcd
      Kirill Smelkov authored
      Current Debian testing builds libtsan/libasan with --as-needed, which
      leads to libstdc++.so not being linked in. Compare Debian 10:
      
          kirr@link:~/src/tools/go/pygolang$ ldd /usr/lib/x86_64-linux-gnu/libasan.so.5
              linux-vdso.so.1 (0x00007ffe7e97f000)
              libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f00ad9d5000)
              librt.so.1 => /lib/x86_64-linux-gnu/librt.so.1 (0x00007f00ad9cb000)
              libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f00ad9aa000)
              libstdc++.so.6 => /usr/lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007f00ad7d2000)		<-- libstdc++
              libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f00ad64f000)
              libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f00ad48e000)
              libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007f00ad472000)
              /lib64/ld-linux-x86-64.so.2 (0x00007f00ae7c8000)
      
      to Debian testing:
      
          kirr@deco:~/src/tools/go/pygolang$ ldd /usr/lib/x86_64-linux-gnu/libasan.so.6
              linux-vdso.so.1 (0x00007ffe15d0b000)
              libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f53ba069000)
              libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f53ba047000)
              libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f53b9f03000)
              libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f53b9d3e000)
              libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007f53b9d24000)
              /lib64/ld-linux-x86-64.so.2 (0x00007f53baa6b000)
      
      where libstdc++ is not being linked to libasan.so
      
      This leads to the following crash:
      
          golang/golang_test.py::test_pyx_select_inplace ==181237==AddressSanitizer CHECK failed: ../../../../src/libsanitizer/asan/asan_interceptors.cpp:333 "((__interception::real___cxa_throw)) != (0)" (0x0, 0x0)
              #0 0x7f76aa9f4657  (/usr/lib/x86_64-linux-gnu/libasan.so.6+0xb2657)
              #1 0x7f76aaa11d5a  (/usr/lib/x86_64-linux-gnu/libasan.so.6+0xcfd5a)
              #2 0x7f76aa97ac14 in __cxa_throw (/usr/lib/x86_64-linux-gnu/libasan.so.6+0x38c14)
              #3 0x7f76a497a9ef in panic golang/runtime/libgolang.cpp:79
              #4 0x7f76a497e9a9 in _chanselect golang/runtime/libgolang.cpp:956
              #5 0x7f76a455573c in select<1> golang/libgolang.h:535
              #6 0x7f76a454fa4b in _test_select_inplace() golang/runtime/libgolang_test.cpp:417
              #7 0x7f76a452781e in __pyx_pf_6golang_12_golang_test_30test_select_inplace golang/_golang_test.cpp:4859
              #8 0x7f76a45277db in __pyx_pw_6golang_12_golang_test_31test_select_inplace golang/_golang_test.cpp:4821
      
      explained by https://github.com/google/sanitizers/issues/934
      
      -> work it around by manually preloading libstdc++ as well.
      49bb8dcd
    • Kirill Smelkov's avatar
      golang: tests: Fix IPython integration test wrt TSAN/ASAN · b938af8b
      Kirill Smelkov authored
      test_defer_excchain_dump_ipython was setting fresh env anew, thus not
      propagating $LD_PRELOAD that trun sets when libgolang was built with
      thread or address sanitizer. This way the subprocess spawned for IPython
      was failing with e.g.
      
              ==152924==ASan runtime does not come first in initial library list; you should either link runtime to your application or manually preload it with LD_PRELOAD.
      
      -> Fix it by only adjusting environment for spawned IPython instead of
      setting it completely anew.
      
      Fixes: 09629367 (golang: tests: Add tests for IPython and Pytest
      integration patches)
      b938af8b
    • Kirill Smelkov's avatar
      golang: tests: Don't hide output details in assert on retcode of spawned command · 6e31304d
      Kirill Smelkov authored
      For example if test_defer_excchain_dump_ipython fails the output was:
      
          >       assert retcode == 0
          E       assert 1 == 0
      
      and it was unclear what was going on. Now the output is e.g.
      
          >       assert retcode == 0, (stdout, stderr)
          E       AssertionError: ('', '==152924==ASan runtime does not come first in initial library list; you should either link runtime to your application or manually preload it with LD_PRELOAD.
          E         ')
          E       assert 1 == 0
      
      Amends: 09629367 (golang: tests: Add tests for IPython and Pytest
      integration patches) and bb9a94c3 (golang: Teach defer to chain
      exceptions (PEP 3134) even on Python2).
      6e31304d
  13. 30 Jul, 2020 4 commits
    • Kirill Smelkov's avatar
      gpython: Add way to run it with threads runtime · a6b993c8
      Kirill Smelkov authored
      Until now gpython was always activating gevent on startup + adding
      goodness such as "always UTF-8 default encoding"; go, chan, b/u and
      friends available from builtin namespace, etc... While those goodness
      are sometimes useful on their own, it is not always appropriate to force
      a project to switch from threads to gevent.
      
      For this reason add a flag to select which runtime - either gevent
      or threads - gpython should use.
      
      	gpython -Xgpython.runtime=gevent	selects gevent,
      
      while
      
      	gpython -Xgpython.runtime=threads	selects threads.
      
      Gevent remains the default.
      
      It is also possible to specify desired runtime via $GPYTHON_RUNTIME
      environment variable.
      
      /reviewed-on nexedi/pygolang!5
      a6b993c8
    • Kirill Smelkov's avatar
      gpython: Reorganize main a bit · c0282565
      Kirill Smelkov authored
      Restructure code a bit to prepare it for the next patch.
      Plain code movement.
      
      /reviewed-on nexedi/pygolang!5
      c0282565
    • Kirill Smelkov's avatar
      gpython: Add support for -V / --version · 70c4c82f
      Kirill Smelkov authored
      On CPython:
      
      	$ python -V
      	Python 2.7.18
      
      	$ gpython -V
      	GPython 0.0.6.post2 [gevent 20.6.2] / CPython 2.7.18
      
      On PyPy:
      
      	$ python -V
              Python 3.6.9 (2ad108f17bdb, Apr 07 2020, 02:59:05)
              [PyPy 7.3.1 with GCC 7.3.1 20180303 (Red Hat 7.3.1-5)]
      
      	$ gpython -V
      	GPython 0.0.6.post2 [gevent 20.5.0] / PyPy 7.3.1 / Python 3.6.9
      
      /reviewed-on !5
      70c4c82f
    • Kirill Smelkov's avatar
      gpython: Support -c<command>, not only -c <command> · e6714e49
      Kirill Smelkov authored
      And same for -m<module> - becuase Python supports it this way.
      
      Before the patch:
      
      	$ python '-cprint "hello world"'
      	hello world
      	$ gpython '-cprint "hello world"'
      	unknown option: '-cprint "hello world"'
      
      After the patch:
      
      	$ python '-cprint "hello world"'
      	hello world
      	$ gpython '-cprint "hello world"'
      	hello world
      
      /reviewed-on !5
      e6714e49
  14. 07 Jul, 2020 3 commits
  15. 29 May, 2020 1 commit
    • Kirill Smelkov's avatar
      gpython: Include gevent version into banner · 0e3da017
      Kirill Smelkov authored
      Gevent is major component gpython builds on - it deserves to be included
      into version and is handy to know if one hits a bug with gpython - to
      see in which particular runtime environment the bug was hit.
      
      Before:
      
          $ gpython
          Python 3.7.3 (default, Dec 20 2019, 18:57:59)
          [GCC 8.3.0] [GPython 0.0.6.post2] on linux
          Type "help", "copyright", "credits" or "license" for more information.
          (InteractiveConsole)
          >>>
      
      After:
      
          $ gpython
          Python 3.7.3 (default, Dec 20 2019, 18:57:59)
          [GCC 8.3.0] [GPython 0.0.6.post2] [gevent 20.5.1] on linux
          Type "help", "copyright", "credits" or "license" for more information.
          (InteractiveConsole)
          >>>
      
      /cc @gabriel, @jerome
      /proposed-for-review-on: nexedi/pygolang!4
      0e3da017
  16. 21 May, 2020 1 commit