software guide python svn project-management repository modularity

guide - python software structure



¿Cómo protejo mi base de código de Python para que los invitados no puedan ver ciertos módulos, pero todavía funciona? (3)

Estamos empezando un nuevo proyecto en Python con unos pocos algoritmos patentados y bits de lógica delicados que nos gustaría mantener en privado. También tendremos algunos forasteros (miembros selectos del público) trabajando en el código. No podemos otorgar acceso a los extraños a pequeños fragmentos de código privados, pero nos gustaría que una versión pública funcione lo suficientemente bien para ellos.

Digamos que nuestro proyecto, Foo, tiene un módulo, bar , con una función, get_sauce() . Lo que realmente ocurre en get_sauce() es secreto, pero queremos que una versión pública de get_sauce() un resultado aceptable, aunque incorrecto.

También administramos nuestro propio servidor de Subversion, por lo que tenemos control total sobre quién puede acceder a qué.

Enlaces simbólicos

Lo primero que pensé fue en el enlace simbólico: en lugar de bar.py , proporcione bar_public.py a todo el mundo y bar_private.py a desarrolladores internos. Desafortunadamente, la creación de enlaces simbólicos es un trabajo tedioso y manual, especialmente cuando realmente habrá cerca de dos docenas de estos módulos privados.

Más importante aún, hace que la gestión del archivo Authz de Subversion sea difícil, ya que para cada módulo que queremos proteger debe agregarse una excepción en el servidor. Alguien puede olvidarse de hacer esto y verificar accidentalmente los secretos ... Entonces el módulo está en el repositorio y tenemos que reconstruir el repositorio sin él y esperar que un extraño no lo descargue mientras tanto.

Múltiples repositorios

El siguiente pensamiento fue tener dos repositorios:

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

La idea es que solo los desarrolladores internos podrán realizar compras private/ public/ . Los desarrolladores internos establecerán su PYTHONPATH=private/trunk:public/trunk , pero todos los demás simplemente establecerán PYTHONPATH=public/trunk . Entonces, tanto los de adentro como los de fuera pueden from foo import bar y obtener el módulo correcto, ¿verdad?

Intentemos esto:

% 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

No soy un experto en Python, pero parece que Python ya se ha decidido por el módulo foo y las búsquedas relativas a eso:

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

Ni siquiera borrar foo ayuda:

>>> 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

¿Me puede dar una mejor solución o sugerencia?


Utilice algún tipo de sistema de complemento y mantenga sus complementos para usted, pero también tenga complementos disponibles públicamente que se envíen con el código abierto.

Los sistemas de complementos abundan. Usted puede hacer fácilmente simples muertos. Si quieres algo más avanzado, prefiero Zope Component Architecture, pero también hay opciones como setuptools entry_points, etc.

Cuál usar en su caso sería una buena segunda pregunta.


En el método __init__ del paquete foo , puede cambiar __path__ para que busque sus módulos en otros directorios.

Así que crea un directorio llamado secret y ponlo en tu repositorio privado de Subversion. En secret ponga su bar.py propiedad. En __init__.py del paquete foo público pon algo así como:

__path__.insert(0,''secret'')

Esto significará para los usuarios que tienen el repositorio privado y por lo tanto el directorio secret que obtendrán bar.py como foo.bar como secret es el primer directorio en la ruta de búsqueda. Para otros usuarios, Python no encontrará el secret y se verá como el siguiente directorio en __path__ y así cargará el bar.py normal de foo .

Por lo tanto, se verá algo como esto:

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


Aquí hay una solución alternativa que noté al leer los documentos para Flask :

flaskext/__init__.py

El único propósito de este archivo es marcar el paquete como paquete de espacio de nombres. Esto es necesario para que múltiples módulos de diferentes paquetes PyPI puedan residir en el mismo paquete de Python:

__import__(''pkg_resources'').declare_namespace(__name__)

Si desea saber exactamente qué está sucediendo allí, revise los documentos de distribución o configuración que explican cómo funciona esto.