¿Cómo protejo mi base de código Python para que los invitados no puedan ver ciertos módulos pero aún así funciona?

StackOverflow https://stackoverflow.com/questions/1443146

Pregunta

Estamos comenzando un nuevo proyecto en Python con algunos algoritmos patentados y partes sensibles de lógica que nos gustaría mantener en privado. También tendremos algunos extraños (miembros selectos del público) trabajando en el código. No podemos otorgar acceso a los extraños a los pequeños y privados bits de código, 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 sucede en get_sauce () es secreto, pero queremos que una versión pública de get_sauce () devuelva un resultado aceptable, aunque incorrecto.

También ejecutamos nuestro propio servidor Subversion para tener control total sobre quién puede acceder a qué.

Symlinks

Mi primer pensamiento fue la simulación - & nbsp; En lugar de bar.py , proporcione bar_public.py a todos y bar_private.py a interno solo desarrolladores. Desafortunadamente, crear enlaces simbólicos es tedioso, trabajo manual, especialmente cuando realmente va a haber alrededor de dos docenas de estos módulos privados.

Más importante aún, hace que la administración del archivo Subversion authz sea difícil, ya que para cada módulo que queremos proteger se debe agregar una excepción en el servidor. Alguien podría olvidar hacer esto y accidentalmente registrar 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 pagar tanto private / como public / . Los desarrolladores internos establecerán su PYTHONPATH = private / trunk: public / trunk , pero todos los demás solo establecerán PYTHONPATH = public / trunk . Entonces, tanto los de adentro como los de afuera pueden desde foo import bar y obtener el módulo correcto, ¿verdad?

Probemos 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 sobre el módulo foo y busca en relación con eso:

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

Ni siquiera eliminar 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

¿Puede proporcionarme una mejor solución o sugerencia?

¿Fue útil?

Solución

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

Cree un directorio llamado secret y póngalo en su repositorio privado de Subversion. En secret ponga su propiedad bar.py . En el __init__.py del paquete público foo ponga algo como:

__path__.insert(0,'secret')

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

Entonces se verá más o menos así:

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

Otros consejos

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

Los sistemas de complementos abundan. Usted mismo puede hacer fácilmente los más simples. Si desea algo más avanzado, prefiero la arquitectura de componentes de Zope, pero también hay opciones como setuptools entry_points, etc.

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

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

__import__('pkg_resources').declare_namespace(__name__)
     

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

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top