Commit 9c61f254 authored by Kirill Smelkov's avatar Kirill Smelkov

pygopath: Initial draft

Module gopath provides way to import python modules by full path in a Go workspace.

For example

    lonet = gopath.gimport('lab.nexedi.com/kirr/go123/xnet/lonet')

will import either

    lab.nexedi.com/kirr/go123/xnet/lonet.py, or
    lab.nexedi.com/kirr/go123/xnet/lonet/__init__.py

located somewhere under $GOPATH.
parent 6d47012e
*.py[co]
__pycache__
build/
.tox/
.cache/
*.o
*.so
/dist/
*.egg-info
perf.data*
core
This diff is collapsed.
recursive-include testdata *.py
=================================================================
Pygopath - Import python modules by full path in a Go workspace
=================================================================
Module `gopath` provides way to import python modules by full path in a Go workspace.
For example
::
lonet = gopath.gimport('lab.nexedi.com/kirr/go123/xnet/lonet')
will import either
- `lab.nexedi.com/kirr/go123/xnet/lonet.py`, or
- `lab.nexedi.com/kirr/go123/xnet/lonet/__init__.py`
located in `src/` under `$GOPATH`.
# Copyright (C) 2018 Nexedi SA and Contributors.
# Kirill Smelkov <kirr@nexedi.com>
#
# This program is free software: you can Use, Study, Modify and Redistribute
# it under the terms of the GNU General Public License version 3, or (at your
# option) any later version, as published by the Free Software Foundation.
#
# You can also Link and Combine this program with other software covered by
# the terms of any of the Free Software licenses or any of the Open Source
# Initiative approved licenses and Convey the resulting work. Corresponding
# source of such a combination shall include the source code for all other
# software used.
#
# This program is distributed WITHOUT ANY WARRANTY; without even the implied
# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
#
# See COPYING file for full licensing terms.
# See https://www.nexedi.com/licensing for rationale and options.
"""Module gopath provides way to import python modules by full path in a Go workspace.
For example
lonet = gopath.gimport('lab.nexedi.com/kirr/go123/xnet/lonet')
will import either
lab.nexedi.com/kirr/go123/xnet/lonet.py, or
lab.nexedi.com/kirr/go123/xnet/lonet/__init__.py
located in src/ under $GOPATH.
"""
import os, os.path
import sys
import imp
# _gopathv returns $GOPATH vector.
def _gopathv():
gopath = os.environ.get('GOPATH')
if gopath is None:
# since Go1.8 default GOPATH is ~/go
gopath = os.path.expanduser(os.path.join('~', 'go'))
return gopath.split(os.path.pathsep)
# gimport imports python module or package from fully-qualified module name under $GOPATH.
def gimport(name):
imp.acquire_lock()
try:
return _gimport(name)
finally:
imp.release_lock()
def _gimport(name):
# we will register imported module into sys.modules with adjusted path.
# reason: if we leave dots in place, python emits warning:
# RuntimeWarning: Parent module 'lab.nexedi' not found while handling absolute import
#
# we put every imported module under `gopath.` namespace with '.' changed to '_'
modname = 'gopath.' + name.replace('.', '_')
try:
return sys.modules[modname]
except KeyError:
# not yet imported
pass
# search for module in every GOPATH entry
modpath = None
gopathv = _gopathv()
for g in gopathv:
# module: .../name.py
modpath = os.path.join(g, 'src', name + '.py')
if os.path.exists(modpath):
break
# package: .../name/__init__.py
modpath = os.path.join(g, 'src', name, '__init__.py')
if os.path.exists(modpath):
break
else:
modpath = None
if modpath is None:
raise ImportError('gopath: no module named %s' % name)
# https://stackoverflow.com/a/67692
# TODO py3 support
return imp.load_source(modname, modpath)
# Copyright (C) 2018 Nexedi SA and Contributors.
# Kirill Smelkov <kirr@nexedi.com>
#
# This program is free software: you can Use, Study, Modify and Redistribute
# it under the terms of the GNU General Public License version 3, or (at your
# option) any later version, as published by the Free Software Foundation.
#
# You can also Link and Combine this program with other software covered by
# the terms of any of the Free Software licenses or any of the Open Source
# Initiative approved licenses and Convey the resulting work. Corresponding
# source of such a combination shall include the source code for all other
# software used.
#
# This program is distributed WITHOUT ANY WARRANTY; without even the implied
# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
#
# See COPYING file for full licensing terms.
# See https://www.nexedi.com/licensing for rationale and options.
import os, os.path
from gopath import gimport
GOPATH_orig = None
def setup_module():
# set GOPATH to testdata/src
global GOPATH_orig
GOPATH_orig = os.environ.get('GOPATH')
os.environ['GOPATH'] = '%s/testdata' % (os.path.dirname(__file__),)
def teardown_module():
if GOPATH_orig is None:
del os.environ['GOPATH']
else:
os.environ['GOPATH'] = GOPATH_orig
def test_import_module():
hello = gimport('lab.nexedi.com/kirr/hello')
assert hello.TAG == 'gopath: test: hello.py'
hello.TAG = 'loaded'
# verify second gimport does not reload
hello2 = gimport('lab.nexedi.com/kirr/hello')
assert hello2 is hello
# even though hello2 is hello - the module could be reloaded.
# check it is not the case via .TAG .
assert hello.TAG == 'loaded', 'module was reloaded'
def test_import_package():
world = gimport('lab.nexedi.com/kirr/world')
assert world.TAG == 'gopath: test: world/__init__.py'
world.TAG = 'loaded'
# verify second gimport does not reload
world2 = gimport('lab.nexedi.com/kirr/world')
assert world2 is world
# even though world2 is world - the module could be reloaded.
# check it is not the case via .TAG .
assert world.TAG =='loaded', 'module was reloaded'
# pygopath | pythonic package setup
from setuptools import setup, find_packages
# read file content
def readfile(path):
with open(path, 'r') as f:
return f.read()
setup(
name = 'pygopath',
version = '0.0.0.dev1',
description = 'Import python modules by full-path in Go workspace',
long_description = readfile('README.rst'),
url = 'https://lab.nexedi.com/kirr/pygopath',
license = 'GPLv3+ with wide exception for Open-Source',
author = 'Kirill Smelkov',
author_email= 'kirr@nexedi.com',
keywords = 'go GOPATH python import',
# XXX find_packages does not find top-level *.py
#packages = find_packages(),
packages = [''],
extras_require = {
'test': ['pytest'],
},
classifiers = [_.strip() for _ in """\
Development Status :: 3 - Alpha
Intended Audience :: Developers\
""".splitlines()]
)
TAG = 'gopath: test: hello.py'
TAG = 'gopath: test: world/__init__.py'
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment