{"id":16849622,"url":"https://github.com/navytux/pygolang","last_synced_at":"2025-04-13T09:43:18.663Z","repository":{"id":44450682,"uuid":"139483800","full_name":"navytux/pygolang","owner":"navytux","description":"Go-like features for Python and Cython. (mirror of https://lab.nexedi.com/kirr/pygolang)","archived":false,"fork":false,"pushed_at":"2025-04-04T07:44:12.000Z","size":1908,"stargazers_count":60,"open_issues_count":0,"forks_count":7,"subscribers_count":4,"default_branch":"master","last_synced_at":"2025-04-04T08:30:39.258Z","etag":null,"topics":["channels","concurrency","cython","gevent","gil","go","golang","goroutines","gpython","nogil","python"],"latest_commit_sha":null,"homepage":"https://pypi.org/project/pygolang","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/navytux.png","metadata":{"files":{"readme":"README.rst","changelog":"CHANGELOG.rst","contributing":null,"funding":null,"license":"COPYING","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2018-07-02T19:11:49.000Z","updated_at":"2025-04-04T07:44:16.000Z","dependencies_parsed_at":"2024-04-19T20:28:17.234Z","dependency_job_id":"ddd8dba4-d943-43ba-b085-c245180a9a19","html_url":"https://github.com/navytux/pygolang","commit_stats":{"total_commits":426,"total_committers":3,"mean_commits":142.0,"dds":0.009389671361502372,"last_synced_commit":"91a434d511f5a27bc68ab3fd1fe81829ad6a0bf1"},"previous_names":[],"tags_count":22,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/navytux%2Fpygolang","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/navytux%2Fpygolang/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/navytux%2Fpygolang/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/navytux%2Fpygolang/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/navytux","download_url":"https://codeload.github.com/navytux/pygolang/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248693906,"owners_count":21146885,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["channels","concurrency","cython","gevent","gil","go","golang","goroutines","gpython","nogil","python"],"created_at":"2024-10-13T13:16:39.546Z","updated_at":"2025-04-13T09:43:18.639Z","avatar_url":"https://github.com/navytux.png","language":"Python","funding_links":[],"categories":["Python"],"sub_categories":[],"readme":"===================================================\n Pygolang - Go-like features for Python and Cython\n===================================================\n\nPackage `golang` provides Go-like features for Python:\n\n- `gpython` is Python interpreter with support for lightweight threads.\n- `go` spawns lightweight thread.\n- `chan` and `select` provide channels with Go semantic.\n- `func` allows to define methods separate from class.\n- `defer` allows to schedule a cleanup from the main control flow.\n- `error` and package `errors` provide error chaining.\n- `b`, `u` and `bstr`/`ustr` provide uniform UTF8-based approach to strings.\n- `gimport` allows to import python modules by full path in a Go workspace.\n\nPackage `golang.pyx` provides__ similar features for Cython/nogil.\n\n__ `Cython/nogil API`_\n\nAdditional packages and utilities are also provided__ to close other gaps\nbetween Python/Cython and Go environments.\n\n__ `Additional packages and utilities`_\n\n\n\n.. contents::\n   :depth: 1\n\n\nGPython\n-------\n\nCommand `gpython` provides Python interpreter that supports lightweight threads\nvia tight integration with gevent__. The standard library of GPython is API\ncompatible with Python standard library, but inplace of OS threads lightweight\ncoroutines are provided, and IO is internally organized via\nlibuv__/libev__-based IO scheduler. Consequently programs can spawn lots of\ncoroutines cheaply, and modules like `time`, `socket`, `ssl`, `subprocess` etc -\nall could be used from all coroutines simultaneously, and in the same blocking way\nas if every coroutine was a full OS thread. This gives ability to scale programs\nwithout changing concurrency model and existing code.\n\n__ http://www.gevent.org/\n__ http://libuv.org/\n__ http://software.schmorp.de/pkg/libev.html\n\n\nAdditionally GPython sets UTF-8 to be default encoding always, and puts `go`,\n`chan`, `select` etc into builtin namespace.\n\n.. note::\n\n   GPython is optional and the rest of Pygolang can be used from under standard Python too.\n   However without gevent integration `go` spawns full - not lightweight - OS thread.\n   GPython can be also used with threads - not gevent - runtime. Please see\n   `GPython options`_ for details.\n\n\nGoroutines and channels\n-----------------------\n\n`go` spawns a coroutine, or thread if gevent was not activated. It is possible to\nexchange data in between either threads or coroutines via channels. `chan`\ncreates a new channel with Go semantic - either synchronous or buffered. Use\n`chan.recv`, `chan.send` and `chan.close` for communication. `nilchan`\nstands for nil channel. `select` can be used to multiplex on several\nchannels. For example::\n\n    ch1 = chan()    # synchronous channel\n    ch2 = chan(3)   # channel with buffer of size 3\n\n    def _():\n        ch1.send('a')\n        ch2.send('b')\n    go(_)\n\n    ch1.recv()      # will give 'a'\n    ch2.recv_()     # will give ('b', True)\n\n    ch2 = nilchan   # rebind ch2 to nil channel\n    _, _rx = select(\n        ch1.recv,           # 0\n        ch1.recv_,          # 1\n        (ch1.send, obj),    # 2\n        ch2.recv,           # 3\n        default,            # 4\n    )\n    if _ == 0:\n        # _rx is what was received from ch1\n        ...\n    if _ == 1:\n        # _rx is (rx, ok) of what was received from ch1\n        ...\n    if _ == 2:\n        # we know obj was sent to ch1\n        ...\n    if _ == 3:\n        # this case will be never selected because\n        # send/recv on nil channel block forever.\n        ...\n    if _ == 4:\n        # default case\n        ...\n\nBy default `chan` creates new channel that can carry arbitrary Python objects.\nHowever type of channel elements can be specified via `chan(dtype=X)` - for\nexample `chan(dtype='C.int')` creates new channel whose elements are C\nintegers. `chan.nil(X)` creates typed nil channel. `Cython/nogil API`_\nexplains how channels with non-Python dtypes, besides in-Python usage, can be\nadditionally used for interaction in between Python and nogil worlds.\n\n\nMethods\n-------\n\n`func` decorator allows to define methods separate from class.\n\nFor example::\n\n  @func(MyClass)\n  def my_method(self, ...):\n      ...\n\nwill define `MyClass.my_method()`.\n\n`func` can be also used on just functions, for example::\n\n  @func\n  def my_function(...):\n      ...\n\n\nDefer / recover / panic\n-----------------------\n\n`defer` allows to schedule a cleanup to be executed when current function\nreturns. It is similar to `try`/`finally` but does not force the cleanup part\nto be far away in the end. For example::\n\n   wc = wcfs.join(zurl)    │     wc = wcfs.join(zurl)\n   defer(wc.close)         │     try:\n                           │        ...\n   ...                     │        ...\n   ...                     │        ...\n   ...                     │     finally:\n                           │        wc.close()\n\nIf deferred cleanup fails, previously unhandled exception, if any, won't be\nlost - it will be chained with (`PEP 3134`__) and included into traceback dump\neven on Python2.\n\n__ https://www.python.org/dev/peps/pep-3134/\n\nFor completeness there is `recover` and `panic` that allow to program with\nGo-style error handling, for example::\n\n   def _():\n      r = recover()\n      if r is not None:\n         print(\"recovered. error was: %s\" % (r,))\n   defer(_)\n\n   ...\n\n   panic(\"aaa\")\n\nBut `recover` and `panic` are probably of less utility since they can be\npractically natively modelled with `try`/`except`.\n\nIf `defer` is used, the function that uses it must be wrapped with `@func`\ndecorator.\n\n\nErrors\n------\n\nIn concurrent systems operational stack generally differs from execution code\nflow, which makes code stack traces significantly less useful to understand an\nerror. Pygolang provides support for error chaining that gives ability to build\noperational error stack and to inspect resulting errors:\n\n`error` is error type that can be used by itself or subclassed. By\nproviding `.Unwrap()` method, an error can optionally wrap another error this\nway forming an error chain. `errors.Is` reports whether an item in error chain\nmatches target. `fmt.Errorf` provides handy way to build wrapping errors.\nFor example::\n\n   e1 = error(\"problem\")\n   e2 = fmt.Errorf(\"doing something for %s: %w\", \"joe\", e1)\n   print(e2)         # prints \"doing something for joe: problem\"\n   errors.Is(e2, e1) # gives True\n\n   # OpError is example class to represents an error of operation op(path).\n   class OpError(error):\n      def __init__(e, op, path, err):\n         e.op   = op\n         e.path = path\n         e.err  = err\n\n      # .Error() should be used to define what error's string is.\n      # it is automatically used by error to also provide both .__str__ and .__repr__.\n      def Error(e):\n         return \"%s %s: %s\" % (e.op, e.path, e.err)\n\n      # provided .Unwrap() indicates that this error is chained.\n      def Unwrap(e):\n         return e.err\n\n   mye = OpError(\"read\", \"file.txt\", io.ErrUnexpectedEOF)\n   print(mye)                          # prints \"read file.txt: unexpected EOF\"\n   errors.Is(mye, io.EOF)              # gives False\n   errors.Is(mye. io.ErrUnexpectedEOF) # gives True\n\nBoth wrapped and wrapping error can be of arbitrary Python type - not\nnecessarily of `error` or its subclass.\n\n`error` is also used to represent at Python level an error returned by\nCython/nogil call (see `Cython/nogil API`_) and preserves Cython/nogil error\nchain for inspection at Python level.\n\nPygolang error chaining integrates with Python error chaining and takes\n`.__cause__` attribute into account for exception created via `raise X from Y`\n(`PEP 3134`__).\n\n__ https://www.python.org/dev/peps/pep-3134/\n\n\nStrings\n-------\n\nPygolang, similarly to Go, provides uniform UTF8-based approach to strings with\nthe idea to make working with byte- and unicode- strings easy and transparently\ninteroperable:\n\n- `bstr` is byte-string: it is based on `bytes` and can automatically convert to/from `unicode` [*]_.\n- `ustr` is unicode-string: it is based on `unicode` and can automatically convert to/from `bytes`.\n\nThe conversion, in both encoding and decoding, never fails and never looses\ninformation: `bstr→ustr→bstr` and `ustr→bstr→ustr` are always identity\neven if bytes data is not valid UTF-8.\n\nBoth `bstr` and `ustr` represent stings. They are two different *representations* of the same entity.\n\nSemantically `bstr` is array of bytes, while `ustr` is array of\nunicode-characters. Accessing their elements by `[index]` and iterating them yield byte and\nunicode character correspondingly [*]_. However it is possible to yield unicode\ncharacter when iterating `bstr` via `uiter`, and to yield byte character when\niterating `ustr` via `biter`. In practice `bstr` + `uiter` is enough 99% of\nthe time, and `ustr` only needs to be used for random access to string\ncharacters.  See `Strings, bytes, runes and characters in Go`__ for overview of\nthis approach.\n\n__ https://blog.golang.org/strings\n\nOperations in between `bstr` and `ustr`/`unicode` / `bytes`/`bytearray` coerce to `bstr`, while\noperations in between `ustr` and `bstr`/`bytes`/`bytearray` / `unicode` coerce\nto `ustr`.  When the coercion happens, `bytes` and `bytearray`, similarly to\n`bstr`, are also treated as UTF8-encoded strings.\n\n`bstr` and `ustr` are meant to be drop-in replacements for standard\n`str`/`unicode` classes. They support all methods of `str`/`unicode` and in\nparticular their constructors accept arbitrary objects and either convert or stringify them. For\ncases when no stringification is desired, and one only wants to convert\n`bstr`/`ustr` / `unicode`/`bytes`/`bytearray`, or an object with `buffer`\ninterface [*]_, to Pygolang string, `b` and `u` provide way to make sure an\nobject is either `bstr` or `ustr` correspondingly.\n\nUsage example::\n\n   s  = b('привет')     # s is bstr corresponding to UTF-8 encoding of 'привет'.\n   s += ' мир'          # s is b('привет мир')\n   for c in uiter(s):   # c will iterate through\n        ...             #     [u(_) for _ in ('п','р','и','в','е','т',' ','м','и','р')]\n\n   # the following gives b('привет мир труд май')\n   b('привет %s %s %s') % (u'мир',                  # raw unicode\n                           u'труд'.encode('utf-8'), # raw bytes\n                           u('май'))                # ustr\n\n   def f(s):\n      s = u(s)          # make sure s is ustr, decoding as UTF-8(*) if it was bstr, bytes, bytearray or buffer.\n      ...               # (*) the decoding never fails nor looses information.\n\n.. [*] `unicode` on Python2, `str` on Python3.\n.. [*] | ordinal of such byte and unicode character can be obtained via regular `ord`.\n       | For completeness `bbyte` and `uchr` are also provided for constructing 1-byte `bstr` and 1-character `ustr` from ordinal.\n.. [*] | data in buffer, similarly to `bytes` and `bytearray`, is treated as UTF8-encoded string.\n       | Notice that only explicit conversion through `b` and `u` accept objects with buffer interface. Automatic coercion does not.\n\n\nImport\n------\n\n`gimport` provides way to import python modules by full path in a Go workspace.\n\nFor example\n\n::\n\n    lonet = gimport('lab.nexedi.com/kirr/go123/xnet/lonet')\n\nwill import either\n\n- `lab.nexedi.com/kirr/go123/xnet/lonet.py`, or\n- `lab.nexedi.com/kirr/go123/xnet/lonet/__init__.py`\n\nlocated in `src/` under `$GOPATH`.\n\n\nCython/nogil API\n----------------\n\nCython package `golang` provides *nogil* API with goroutines, channels and\nother features that mirror corresponding Python package. Cython API is not only\nfaster compared to Python version, but also, due to *nogil* property, allows to\nbuild concurrent systems without limitations imposed by Python's GIL. All that\nwhile still programming in Python-like language. Brief description of\nCython/nogil API follows:\n\n`go` spawns new task - a coroutine, or thread, depending on activated runtime.\n`chan[T]` represents a channel with Go semantic and elements of type `T`.\nUse `makechan[T]` to create new channel, and `chan[T].recv`, `chan[T].send`,\n`chan[T].close` for communication. `nil` stands for nil channel. `select`\ncan be used to multiplex on several channels. For example::\n\n   cdef nogil:\n      struct Point:\n         int x\n         int y\n\n      void worker(chan[int] chi, chan[Point] chp):\n         chi.send(1)\n\n         cdef Point p\n         p.x = 3\n         p.y = 4\n         chp.send(p)\n\n      void myfunc():\n         cdef chan[int]   chi = makechan[int]()       # synchronous channel of integers\n         cdef chan[Point] chp = makechan[Point](3)    # channel with buffer of size 3 and Point elements\n\n         go(worker, chi, chp)\n\n         i = chi.recv()    # will give 1\n         p = chp.recv()    # will give Point(3,4)\n\n         chp = nil         # rebind chp to nil channel\n         cdef cbool ok\n         cdef int j = 33\n         _ = select([\n             chi.recvs(\u0026i),         # 0\n             chi.recvs(\u0026i, \u0026ok),    # 1\n             chi.sends(\u0026j),         # 2\n             chp.recvs(\u0026p),         # 3\n             default,               # 4\n         ])\n         if _ == 0:\n             # i is what was received from chi\n             ...\n         if _ == 1:\n             # (i, ok) is what was received from chi\n             ...\n         if _ == 2:\n             # we know j was sent to chi\n             ...\n         if _ == 3:\n             # this case will be never selected because\n             # send/recv on nil channel block forever.\n             ...\n         if _ == 4:\n             # default case\n             ...\n\nPython channels are represented by `pychan` cdef class. Python\nchannels that carry non-Python elements (`pychan.dtype != DTYPE_PYOBJECT`) can\nbe converted to Cython/nogil `chan[T]` via `pychan.chan_*()`.\nSimilarly Cython/nogil `chan[T]` can be wrapped into `pychan` via\n`pychan.from_chan_*()`. This provides interaction mechanism\nin between *nogil* and Python worlds. For example::\n\n   def myfunc(pychan pych):\n      if pych.dtype != DTYPE_INT:\n         raise TypeError(\"expected chan[int]\")\n\n      cdef chan[int] ch = pych.chan_int()  # pychan -\u003e chan[int]\n      with nogil:\n         # use ch in nogil code. Both Python and nogil parts can\n         # send/receive on the channel simultaneously.\n         ...\n\n   def mytick(): # -\u003e pychan\n      cdef chan[int] ch\n      with nogil:\n         # create a channel that is connected to some nogil task of the program\n         ch = ...\n\n      # wrap the channel into pychan. Both Python and nogil parts can\n      # send/receive on the channel simultaneously.\n      cdef pychan pych = pychan.from_chan_int(ch)  # pychan \u003c- chan[int]\n      return pych\n\n\n`error` is the interface that represents errors. `errors.New` and `fmt.errorf`\nprovide way to build errors from text. An error can optionally wrap another\nerror by implementing `errorWrapper` interface and providing `.Unwrap()` method.\n`errors.Is` reports whether an item in error chain matches target. `fmt.errorf`\nwith `%w` specifier provide handy way to build wrapping errors. For example::\n\n   e1 = errors.New(\"problem\")\n   e2 = fmt.errorf(\"doing something for %s: %w\", \"joe\", e1)\n   e2.Error()        # gives \"doing something for joe: problem\"\n   errors.Is(e2, e1) # gives True\n\nAn `error` can be exposed to Python via `pyerror` cdef class wrapper\ninstantiated by `pyerror.from_error()`. `pyerror` preserves Cython/nogil error\nchain for inspection by Python-level `error.Is`.\n\n\n`panic` stops normal execution of current goroutine by throwing a C-level\nexception. On Python/C boundaries C-level exceptions have to be converted to\nPython-level exceptions with `topyexc`. For example::\n\n   cdef void _do_something() nogil:\n      ...\n      panic(\"bug\")   # hit a bug\n\n   # do_something is called by Python code - it is thus on Python/C boundary\n   cdef void do_something() nogil except +topyexc:\n      _do_something()\n\n   def pydo_something():\n      with nogil:\n         do_something()\n\n\nSee |libgolang.h|_ and |golang.pxd|_ for details of the API.\nSee also |testprog/golang_pyx_user/|_ for demo project that uses Pygolang in\nCython/nogil mode.\n\n.. |libgolang.h| replace:: `libgolang.h`\n.. _libgolang.h: https://lab.nexedi.com/nexedi/pygolang/tree/master/golang/libgolang.h\n\n.. |golang.pxd| replace:: `golang.pxd`\n.. _golang.pxd: https://lab.nexedi.com/nexedi/pygolang/tree/master/golang/_golang.pxd\n\n.. |testprog/golang_pyx_user/| replace:: `testprog/golang_pyx_user/`\n.. _testprog/golang_pyx_user/: https://lab.nexedi.com/nexedi/pygolang/tree/master/golang/pyx/testprog/golang_pyx_user\n\n--------\n\nAdditional packages and utilities\n---------------------------------\n\nThe following additional packages and utilities are also provided to close gaps\nbetween Python/Cython and Go environments:\n\n.. contents::\n   :local:\n\nConcurrency\n~~~~~~~~~~~\n\nIn addition to `go` and channels, the following packages are provided to help\nhandle concurrency in structured ways:\n\n- |golang.context|_ (py__, pyx__) provides contexts to propagate deadlines, cancellation and\n  task-scoped values among spawned goroutines [*]_.\n\n  .. |golang.context| replace:: `golang.context`\n  .. _golang.context: https://lab.nexedi.com/nexedi/pygolang/tree/master/golang/context.h\n  __ https://lab.nexedi.com/nexedi/pygolang/tree/master/golang/context.py\n  __ https://lab.nexedi.com/nexedi/pygolang/tree/master/golang/_context.pxd\n\n- |golang.sync|_ (py__, pyx__) provides `sync.WorkGroup` to spawn group of goroutines working\n  on a common task. It also provides low-level primitives - for example\n  `sync.Once`, `sync.WaitGroup`, `sync.Mutex` and `sync.RWMutex` - that are\n  sometimes useful too.\n\n  .. |golang.sync| replace:: `golang.sync`\n  .. _golang.sync: https://lab.nexedi.com/nexedi/pygolang/tree/master/golang/sync.h\n  __ https://lab.nexedi.com/nexedi/pygolang/tree/master/golang/sync.py\n  __ https://lab.nexedi.com/nexedi/pygolang/tree/master/golang/_sync.pxd\n\n- |golang.time|_ (py__, pyx__) provides timers integrated with channels.\n\n  .. |golang.time| replace:: `golang.time`\n  .. _golang.time: https://lab.nexedi.com/nexedi/pygolang/tree/master/golang/time.h\n  __ https://lab.nexedi.com/nexedi/pygolang/tree/master/golang/time.py\n  __ https://lab.nexedi.com/nexedi/pygolang/tree/master/golang/_time.pxd\n\n- |golang.os.signal|_ (py__, pyx__) provides signal handling via channels.\n\n  .. |golang.os.signal| replace:: `golang.os.signal`\n  .. _golang.os.signal: https://lab.nexedi.com/nexedi/pygolang/tree/master/golang/os/signal.h\n  __ https://lab.nexedi.com/nexedi/pygolang/tree/master/golang/os/signal.py\n  __ https://lab.nexedi.com/nexedi/pygolang/tree/master/golang/os/_signal.pxd\n\n\n.. [*] See `Go Concurrency Patterns: Context`__ for overview.\n\n__ https://blog.golang.org/context\n\n\nString conversion\n~~~~~~~~~~~~~~~~~\n\n`qq` (import from `golang.gcompat`) provides `%q` functionality that quotes as\nGo would do. For example the following code will print name quoted in `\"`\nwithout escaping printable UTF-8 characters::\n\n   print('hello %s' % qq(name))\n\n`qq` accepts both `str` and `bytes` (`unicode` and `str` on Python2)\nand also any other type that can be converted to `str`.\n\nPackage |golang.strconv|_ provides direct access to conversion routines, for\nexample `strconv.quote` and `strconv.unquote`.\n\n.. |golang.strconv| replace:: `golang.strconv`\n.. _golang.strconv: https://lab.nexedi.com/nexedi/pygolang/tree/master/golang/strconv.py\n\n\nBenchmarking and testing\n~~~~~~~~~~~~~~~~~~~~~~~~\n\n`py.bench` allows to benchmark python code similarly to `go test -bench` and `py.test`.\nFor example, running `py.bench` on the following code::\n\n    def bench_add(b):\n        x, y = 1, 2\n        for i in xrange(b.N):\n            x + y\n\ngives something like::\n\n    $ py.bench --count=3 x.py\n    ...\n    pymod: bench_add.py\n    Benchmarkadd    50000000        0.020 µs/op\n    Benchmarkadd    50000000        0.020 µs/op\n    Benchmarkadd    50000000        0.020 µs/op\n\nPackage |golang.testing|_ provides corresponding runtime bits, e.g. `testing.B`.\n\n`py.bench` produces output in `Go benchmark format`__, and so benchmark results\ncan be analyzed and compared with standard Go tools, for example with\n`benchstat`__.\nAdditionally package |golang.x.perf.benchlib|_ can be used to load and process\nsuch benchmarking data in Python.\n\n.. |golang.testing| replace:: `golang.testing`\n.. _golang.testing: https://lab.nexedi.com/nexedi/pygolang/tree/master/golang/testing.py\n.. |golang.x.perf.benchlib| replace:: `golang.x.perf.benchlib`\n.. _golang.x.perf.benchlib: https://lab.nexedi.com/nexedi/pygolang/tree/master/golang/x/perf/benchlib.py\n__ https://github.com/golang/proposal/blob/master/design/14313-benchmark-format.md\n__ https://godoc.org/golang.org/x/perf/cmd/benchstat\n\n\n--------\n\nGPython options\n---------------\n\nGPython mimics and supports most of Python command-line options, like `gpython\n-c \u003ccommands\u003e` to run Python statements from command line, or `gpython -m\n\u003cmodule\u003e` to execute a module. Such options have the same meaning as in\nstandard Python and are not documented here.\n\nGPython-specific options and environment variables are listed below:\n\n`-X gpython.runtime=(gevent|threads)`\n    Specify which runtime GPython should use. `gevent` provides lightweight\n    coroutines, while with `threads` `go` spawns full OS thread. `gevent` is\n    default. The runtime to use can be also specified via `$GPYTHON_RUNTIME`\n    environment variable.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnavytux%2Fpygolang","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnavytux%2Fpygolang","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnavytux%2Fpygolang/lists"}