3

我们正在 Python 中启动一个新项目,其中包含一些我们希望保密的专有算法和敏感逻辑。我们还将有一些局外人(选定的公众成员)来编写代码。我们不能授予外部人员访问小型私有代码的权限,但我们希望公共版本能够为他们提供足够好的工作。

假设我们的项目 Foo 有一个模块 ,bar具有一个功能,get_sauce()。真正发生的事情get_sauce()是秘密的,但我们想要一个公共版本的get_sauce()返回一个可接受的,尽管不正确的结果。

我们还运行我们自己的 Subversion 服务器,因此我们可以完全控制谁可以访问什么。

符号链接

我的第一个想法是符号链接——而不是bar.py,只提供bar_public.py给所有人和bar_private.py内部开发人员。不幸的是,创建符号链接是一项繁琐的手动工作——尤其是当这些私有模块确实有大约两打时。

更重要的是,它使 Subversion authz 文件的管理变得困难,因为对于我们想要保护的每个模块,都必须在服务器上添加一个异常。有人可能会忘记这样做并且不小心签入了秘密......然后模块在 repo 中,我们必须在没有它的情况下重建存储库,并希望外人在此期间没有下载它。

多个存储库

下一个想法是拥有两个存储库:

private
└── trunk/
    ├── __init__.py
    └── foo/
        ├── __init__.py
        └── bar.py
public
└── trunk/
    ├── __init__.py
    └── foo/
        ├── __init__.py
        ├── bar.py
        ├── baz.py
        └── quux.py

这个想法是只有内部开发人员才能同时签出private/public/. 内部开发人员会设置他们的PYTHONPATH=private/trunk:public/trunk,但其他人只会设置PYTHONPATH=public/trunk。那么,内部人员和外部人员都from foo import bar可以获得正确的模块,对吗?

让我们试试这个:

% PYTHONPATH=private/trunk:public/trunk python
Python 2.5.1
Type "help", "copyright", "credits" or "license" for more information.
>>> import foo.bar
>>> foo.bar.sauce()
'a private bar'
>>> import foo.quux
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ImportError: No module named quux

我不是 Python 专家,但似乎 Python 已经决定了模块foo和与之相关的搜索:

>>> foo
<module 'foo' from '/path/to/private/trunk/foo/__init__.py'>

甚至删除都没有foo帮助:

>>> import sys
>>> del foo
>>> del sys.modules['foo']
>>> import foo.quux
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ImportError: No module named quux

你能给我一个更好的解决方案或建议吗?

4

3 回答 3

3

在包的__init__方法中,foo您可以更改__path__以使其在其他目录中查找其模块。

因此,创建一个名为的目录secret并将其放在您的私有 Subversion 存储库中。放入您的secret专有. bar.py__init__.py公共foo包中放入如下内容:

__path__.insert(0,'secret')

这意味着对于拥有私有存储库的用户,secret他们将获得专有目录,bar.py就像搜索路径中的第一个目录foo.bar一样。secret对于其他用户,Python 不会找到secret并且将作为下一个目录查找,__path__因此将正常bar.pyfoo.

所以它看起来像这样:

   private
    └── trunk/
        └── secret/
            └── bar.py
    public
    └── trunk/
        ├── __init__.py
        └── foo/
            ├── __init__.py
            ├── bar.py
            ├── baz.py
            └── quux.py
于 2009-09-18T08:36:49.753 回答
2

使用某种插件系统,将插件留给自己,但也有随开放代码一起提供的公开可用的插件。

插件系统比比皆是。你可以很容易地自己制作简单的东西。如果您想要更高级的东西,我更喜欢 Zope 组件架构,但也有诸如 setuptools entry_points 等选项。

在您的情况下使用哪一个将是一个很好的第二个问题。

于 2009-09-18T08:44:21.637 回答
0

这是我在阅读Flask文档时注意到的另一种解决方案:

flaskext/__init__.py

此文件的唯一目的是将包标记为命名空间包。这是必需的,以便来自不同 PyPI 包的多个模块可以驻留在同一个 Python 包中:

__import__('pkg_resources').declare_namespace(__name__)

如果您想确切地知道那里发生了什么,请查看解释其工作原理的分发或 setuptools 文档。

于 2010-07-07T07:19:03.420 回答