1. 26 Jan, 2022 3 commits
  2. 08 Dec, 2021 5 commits
    • Kirill Smelkov's avatar
      pygolang v0.0.9 · e503beb0
      Kirill Smelkov authored
      e503beb0
    • Kirill Smelkov's avatar
      gpython: tests: Adjust test_pymain_syspath to current PyPy state · 57ab5f33
      Kirill Smelkov authored
      See https://foss.heptapod.net/pypy/pypy/-/issues/3610 for stdin case.
      -m started to behave as CPython.
      57ab5f33
    • Kirill Smelkov's avatar
      gpython: tests: test_pymain: Fix -i on PyPy3 · 6ca43f2d
      Kirill Smelkov authored
      On py3 'ps1' and b'ps1' are different keys and it was failing on PyPy3 as follows:
      
                  # -i after stdin (also tests interactive mode as -i forces interactive even on non-tty)
                  d = {
                      b'hellopy': b(hellopy),
                      b'ps1':     b'' # cpython emits prompt to stderr
                  }
                  if is_pypy and not is_gpython:
                      d['ps1'] = b'>>>> ' # native pypy emits prompt to stdout and >>>> instead of >>>
                  _ = pyout(['-i'], stdin=b'import hello\n', cwd=testdata)
          >       assert _ == b"%(ps1)shello\nworld\n['']\n%(ps1)s"           % d
          E       assert b">>>> hello\...\n['']\n>>>> " == b"hello\nworld\n['']\n"
          E         At index 0 diff: b'>' != b'h'
          E         Full diff:
          E         - b"hello\nworld\n['']\n"
          E         + b">>>> hello\nworld\n['']\n>>>> "
          E         ?   +++++                    +++++
      
          gpython/gpython_test.py:200: AssertionError
      
      Fix it.
      Amends e205dbf6 (gpython: Implement -i (interactive inspect after program run) + promised interactive-mode tests)
      6ca43f2d
    • Kirill Smelkov's avatar
      context: Fix deadlock when new context is created from already-canceled parent · 58d4cbfe
      Kirill Smelkov authored
      When _BaseCtx is setting up cancel propagation it locks a parent,
      checks for parent.err != nil, and, if it is, calls
      ctx._cancel(parent.err) _with_ _holding_ parent.mu. Since _cancel
      internally also goes through parents and locks them, this was deadlocking
      on the second call to parent.mu.lock().
      
      -> Fix it by calling ctx._cancel(err) in the constructor outside of
      parent lock.
      
      The bug was there from the beginning - from e9567c7b (context: New
      package that mirrors Go's context).
      
      /trusted-by @jerome
      /reviewed-on nexedi/pygolang!16
      58d4cbfe
    • Kirill Smelkov's avatar
      context: Reorganize the code to make internal logic more clear · d0688e21
      Kirill Smelkov authored
      - _propagateCancel is used only in _BaseCtx constructor -> inline it
        there. Being run in the constructor makes it clear that this code
        works on new _BaseCtx object with empty set of children.
      
      - since _cancelFrom interacts with the code moved from _propagateCancel,
        also move it to be close to cancel propagation setup.
      
      No functional changes, just plain code movement.
      
      /trusted-by @jerome
      /reviewed-on nexedi/pygolang!16
      d0688e21
  3. 16 Aug, 2021 1 commit
  4. 07 Apr, 2021 5 commits
    • Kirill Smelkov's avatar
    • Kirill Smelkov's avatar
      gpython: Run code in carefully prepared __main__ module · 2351dd27
      Kirill Smelkov authored
      Because else sys.modules['__main__'] points to the module of gpython
      itself, not user program. This difference can be important when e.g.
      user defines classes in main module and tries to pickle them. Such
      pickling will fail if gpython is not careful to run user's code in its
      own main.
      
      Without this patch added test fails as
      
            File "check_main.py", line 51, in <module>
              main()
            File "check_main.py", line 39, in main
              assert hasattr(mainmod, 'MyUniqueClassXYZ'),        dir(mainmod)
          AssertionError: ['__builtins__', '__doc__', '__file__', '__name__', '__package__', 'main']
      
      The problem was discovered while trying to run test program from
      https://github.com/zopefoundation/ZEO/issues/166 :
      
          $ gpython zopenrace-zeo.py
          Traceback (most recent call last):
            File "/home/kirr/tmp/trashme/Z/py2.venv/bin/gpython", line 8, in <module>
              sys.exit(main())
            File "/home/kirr/tmp/trashme/Z/py2.venv/lib/python2.7/site-packages/gpython/__init__.py", line 395, in main
              pymain(argv, init)
            File "/home/kirr/tmp/trashme/Z/py2.venv/lib/python2.7/site-packages/gpython/__init__.py", line 266, in pymain
              run()
            File "/home/kirr/tmp/trashme/Z/py2.venv/lib/python2.7/site-packages/gpython/__init__.py", line 172, in run
              _execfile(filepath, g)
            File "/home/kirr/tmp/trashme/Z/py2.venv/lib/python2.7/site-packages/gpython/__init__.py", line 275, in _execfile
              six.exec_(code, globals, locals)
            File "/home/kirr/tmp/trashme/Z/py2.venv/lib/python2.7/site-packages/six.py", line 719, in exec_
              exec("""exec _code_ in _globs_, _locs_""")
            File "<string>", line 1, in <module>
            File "zopenrace-zeo.py", line 205, in <module>
              main()
            File "zopenrace-zeo.py", line 190, in main
              init()
            File "zopenrace-zeo.py", line 126, in init
              transaction.commit()
            File "/home/kirr/tmp/trashme/Z/py2.venv/lib/python2.7/site-packages/transaction/_manager.py", line 257, in commit
              return self.manager.commit()
            File "/home/kirr/tmp/trashme/Z/py2.venv/lib/python2.7/site-packages/transaction/_manager.py", line 134, in commit
              return self.get().commit()
            File "/home/kirr/tmp/trashme/Z/py2.venv/lib/python2.7/site-packages/transaction/_transaction.py", line 282, in commit
              reraise(t, v, tb)
            File "/home/kirr/tmp/trashme/Z/py2.venv/lib/python2.7/site-packages/transaction/_transaction.py", line 273, in commit
              self._commitResources()
            File "/home/kirr/tmp/trashme/Z/py2.venv/lib/python2.7/site-packages/transaction/_transaction.py", line 456, in _commitResources
              reraise(t, v, tb)
            File "/home/kirr/tmp/trashme/Z/py2.venv/lib/python2.7/site-packages/transaction/_transaction.py", line 430, in _commitResources
              rm.commit(self)
            File "/home/kirr/tmp/trashme/Z/py2.venv/lib/python2.7/site-packages/ZODB/Connection.py", line 497, in commit
              self._commit(transaction)
            File "/home/kirr/tmp/trashme/Z/py2.venv/lib/python2.7/site-packages/ZODB/Connection.py", line 546, in _commit
              self._store_objects(ObjectWriter(obj), transaction)
            File "/home/kirr/tmp/trashme/Z/py2.venv/lib/python2.7/site-packages/ZODB/Connection.py", line 578, in _store_objects
              p = writer.serialize(obj)  # This calls __getstate__ of obj
            File "/home/kirr/tmp/trashme/Z/py2.venv/lib/python2.7/site-packages/ZODB/serialize.py", line 430, in serialize
              return self._dump(meta, obj.__getstate__())
            File "/home/kirr/tmp/trashme/Z/py2.venv/lib/python2.7/site-packages/ZODB/serialize.py", line 439, in _dump
              self._p.dump(state)
          PicklingError: Can't pickle <class '__main__.PInt'>: attribute lookup __main__.PInt failed
      
      /reviewed-by @jerome
      /reviewed-on nexedi/pygolang!15
      2351dd27
    • Kirill Smelkov's avatar
      gpython: Fix interactive mode to use stdout or stderr depending on what is a tty · 95c7cce9
      Kirill Smelkov authored
      To match python behaviour:
      
          $ python >/dev/null
          Python 2.7.18 (default, Apr 20 2020, 20:30:41)
          [GCC 9.3.0] on linux2
          Type "help", "copyright", "credits" or "license" for more information.
          >>> 1+1			# NOTE the prompt (printed to stderr)
      
          $ python 2>/dev/null
          >>> 1+1			# NOTE the prompt (printed to stdout)
      
      Tests pending.
      
      /reviewed-by @jerome
      /reviewed-on nexedi/pygolang!15
      95c7cce9
    • Kirill Smelkov's avatar
      gpython: Handle program on stdin through just read+exec · 22fb559a
      Kirill Smelkov authored
      Not through interactive console, because it was printing prompts, while
      `python <prog.py` does not emit anything:
      
          $ cat prog.py
          print 'Hello World'
      
          $ python <prog.py
          Hello World
      
          $ gpython <prog.py
          Python 2.7.18 (default, Apr 20 2020, 20:30:41)
          [GCC 9.3.0] [GPython 0.0.8] [gevent 20.9.0] on linux2
          Type "help", "copyright", "credits" or "license" for more information.
          (InteractiveConsole)
          Hello World
      
      After the patch gpython output is the same as of python:
      
          $ gpython <prog.py
          Hello World
      
      Test coverage for interactive mode is pending.
      We'll add them soon in a follow-up patch after implementing -i.
      
      For _interact - by this patch logic - we should be dropping custom
      raw_input, since now _interact is called only when sys.stdin is tty.
      But we'll soon be invoking _interact when stdin is not a tty (for
      `gpython -i <prog.py`), so leave that logic in place as is.
      
      /reviewed-by @jerome
      /reviewed-on nexedi/pygolang!15
      22fb559a
    • Kirill Smelkov's avatar
      gpython: Factor-out interactive-console functionality into its own function · 6cc4bf32
      Kirill Smelkov authored
      We will soon need this to be run from several places when implementing
      support for -i.
      
      /reviewed-by @jerome
      /reviewed-on nexedi/pygolang!15
      6cc4bf32
  5. 26 Mar, 2021 1 commit
  6. 16 Mar, 2021 1 commit
  7. 14 Dec, 2020 2 commits
    • Kirill Smelkov's avatar
      *: Python3.9 switched __file__ to be always absolute · 4f28dddf
      Kirill Smelkov authored
      https://bugs.python.org/issue20443
      
      This broke test_defer_excchain_dump because
      testprog/golang_test_defer_excchain.txt is prepared with output where
      `python file` shows that file name in traceback as it was specified on
      the command line, e.g.
      
          .../pygolang/golang/testprog$ python golang_test_defer_excchain.py
          Traceback (most recent call last):
            File ".../pygolang/golang/__init__.py", line 103, in _
              return f(*argv, **kw)
            File "golang_test_defer_excchain.py", line 42, in main
              raise RuntimeError("err")
          RuntimeError: err
      
      while with py39 it became
      
          .../pygolang/golang/testprog$ python golang_test_defer_excchain.py
          Traceback (most recent call last):
            File ".../pygolang/golang/__init__.py", line 103, in _
              return f(*argv, **kw)
            File ".../pygolang/golang/testprog/golang_test_defer_excchain.py", line 42, in main
              raise RuntimeError("err")
          RuntimeError: err
      
      (notice the difference related to "line 42")
      
      -> Fix it:
      
      - amend the test to conditionally prefix golang_test_defer_excchain.py
        in expected output with PYGOLANG/golang/testprog/ if it is Python >= 3.9.
      - amend `gpython file` to match behaviour of underlying `python file`,
        so that the test passes unconditionally whether it is run by python or
        gpython.
      
      --------
      
      @jerome also says (!13 (comment 122826)):
      
      FYI, buildout (and many zope packages) essentially use doctests for
      testing and they had to deal with similar differences in output.
      `zope.testing` comes with a doctest checker named "renormalizing" which
      normalize output with regular expressions, see for example setup of some
      buildout test [here](https://github.com/buildout/buildout/blob/db3d6e2fbf5d7ff2cc4b2507253c7a221cfc3e32/src/zc/buildout/tests.py#L3615-L3651).
      We definitely don't need this here for the moment, but maybe one day it
      can be useful.
      
      /reviewed-on !13
      4f28dddf
    • Kirill Smelkov's avatar
      tox += CPython3.9 · 32167853
      Kirill Smelkov authored
      Debian testing recently switched default python3 to be python3.9.
      Let's make sure pygolang works with that python version.
      Currently some tests fail - this will be addressed in the next patch.
      
      /reviewed-on nexedi/pygolang!13
      32167853
  8. 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
  9. 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 !11
      f15459b9
  10. 06 Dec, 2020 1 commit
  11. 02 Dec, 2020 2 commits
  12. 01 Dec, 2020 1 commit
  13. 27 Nov, 2020 1 commit
  14. 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:
      
      nexedi/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
      
      nexedi/pygolang!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 !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
  15. 02 Nov, 2020 1 commit
  16. 14 Oct, 2020 5 commits
  17. 22 Sep, 2020 1 commit