如何保护我的 Python 代码库,以便访客看不到某些模块,但它仍然可以工作?
我们正在用 Python 启动一个新项目,其中包含一些我们希望保密的专有算法和敏感逻辑。我们还将有一些外部人员(精选的公众成员)参与代码工作。我们不能授予外部人员访问小型私有代码的权限,但我们希望公共版本能够为他们提供足够好的工作空间。
假设我们的项目 Foo 有一个模块 bar
,其中包含一个函数 get_sauce()
。 get_sauce()
中实际发生的情况是秘密的,但我们希望 get_sauce()
的公共版本返回可接受的(尽管不正确)结果。
我们还运行自己的 Subversion 服务器,因此我们可以完全控制谁可以访问什么。
符号链接
我的第一个想法是符号链接 - 向所有人提供 bar_public.py
和 bar_private.py<,而不是
bar.py
/code> 仅限内部开发人员。不幸的是,创建符号链接是一项乏味的手动工作——尤其是当确实有大约两打这样的私有模块时。
更重要的是,它使 Subversion authz 文件的管理变得困难,因为对于我们想要保护的每个模块,必须在服务器上添加例外。有人可能会忘记执行此操作并意外地检查机密...然后该模块位于存储库中,我们必须在没有它的情况下重建存储库,并希望外部人员在此期间没有下载它。
多个存储库
接下来的想法是拥有两个存储库:
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
您能给我提供更好的解决方案或建议吗?
We're starting a new project in Python with a few proprietary algorithms and sensitive bits of logic that we'd like to keep private. We also will have a few outsiders (select members of the public) working on the code. We cannot grant the outsiders access to the small, private bits of code, but we'd like a public version to work well enough for them.
Say that our project, Foo, has a module, bar
, with one function, get_sauce()
. What really happens in get_sauce()
is secret, but we want a public version of get_sauce()
to return an acceptable, albeit incorrect, result.
We also run our own Subversion server so we have total control over who can access what.
Symlinks
My first thought was symlinking — Instead of bar.py
, provide bar_public.py
to everybody and bar_private.py
to internal developers only. Unfortunately, creating symlinks is tedious, manual work — especially when there are really going to be about two dozen of these private modules.
More importantly, it makes management of the Subversion authz file difficult, since for each module we want to protect an exception must be added on the server. Someone might forget to do this and accidentally check in secrets... Then the module is in the repo and we have to rebuild the repository without it and hope that an outsider didn't download it in the meantime.
Multiple repositories
The next thought was to have two repositories:
private
└── trunk/
├── __init__.py
└── foo/
├── __init__.py
└── bar.py
public
└── trunk/
├── __init__.py
└── foo/
├── __init__.py
├── bar.py
├── baz.py
└── quux.py
The idea is that only internal developers will be able to checkout both private/
and public/
. Internal developers will set their PYTHONPATH=private/trunk:public/trunk
, but everyone else will just set PYTHONPATH=public/trunk
. Then, both insiders and outsiders can from foo import bar
and get the right module, right?
Let's try this:
% 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
I'm not a Python expert, but it seems that Python has already made up its mind about module foo
and searches relative to that:
>>> foo
<module 'foo' from '/path/to/private/trunk/foo/__init__.py'>
Not even deleting foo
helps:
>>> 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
Can you provide me with a better solution or suggestion?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
在
__init__
方法中code>foo 包中,您可以更改 __path__ 以使其在其他目录中查找其模块。因此,创建一个名为
secret
的目录并将其放入在您的私人 Subversion 存储库中。在secret
中放入您专有的bar.py
。在公共foo
包的__init__.py
中,输入如下内容:这对于拥有私有存储库的用户来说意味着,因此
secret
他们将获得专有的bar.py
作为foo.bar
,因为secret
是搜索路径中的第一个目录。对于其他用户,Python 将找不到secret
并将其视为__path__
中的下一个目录,因此将从以下位置加载正常的bar.py
foo
。所以它看起来像这样:
In the
__init__
method of thefoo
package you can change__path__
to make it look for its modules in other directories.So create a directory called
secret
and put it in your private Subversion repository. Insecret
put your proprietarybar.py
. In the__init__.py
of the publicfoo
package put in something like:This will mean for users who have the private repository and so the
secret
directory they will get the proprietarybar.py
asfoo.bar
assecret
is the first directory in the search path. For other users, Python won't findsecret
and will look as the next directory in__path__
and so will load the normalbar.py
fromfoo
.So it will look something like this:
使用某种插件系统,并保留您的插件,但也可以使用开放代码附带的公开可用的插件。
插件系统比比皆是。您可以轻松地自己制作非常简单的东西。如果您想要更高级的东西,我更喜欢 Zope 组件架构,但也有像 setuptools entry_points 等选项。
在您的情况下使用哪一个将是一个很好的第二个问题。
Use some sort of plugin system, and keep your plugins to your self, but also have publically available plugins that gets shipped with the open code.
Plugin systems abound. You can easily make dead simple ones yourself. If you want something more advanced I prefer the Zope Component Architecture, but there are also options like setuptools entry_points, etc.
Which one to use in your case would be a good second question.
这是我在阅读 Flask 的文档时注意到的替代解决方案:
Here's an alternate solution I noticed when reading the docs for Flask: