¿Cómo gestionar la configuración del proyecto Python? Estas son las habilidades de Python que más necesitas
Más de un año después, todo parecía ir bien e incluso el nuevo proyecto en el que estaba trabajando en Knowledge seguía esta solución, así que decidí documentarlo.
Comencemos con el problema de gestión de configuración que estoy tratando de resolver para proyectos Python:
La capacidad de diferenciar entre varios entornos.
Hay diferentes configuraciones disponibles para entornos de desarrollo, prueba y producción, por lo que poder diferenciar entre ellas es un requisito muy básico.
Puede haber elementos de configuración comunes.
Solo es necesario modificar una pequeña cantidad de configuraciones para diferentes entornos. Por lo tanto, las secciones comunes no deben definirse repetidamente, de lo contrario se incurrirán en costos de mantenimiento.
Se puede dividir en varias partes/módulos.
Dado que hay muchos proyectos de gestión de configuración en un proyecto Python, encontrar la configuración puede llevar mucho tiempo, por lo que dividirlos ayuda a mantener la configuración.
Puedes utilizar código Python directamente.
Analizar valores variables de archivos de texto es demasiado engorroso para generar lotes de datos (como matrices) o generar valores de configuración mediante llamadas a funciones (como obtener rutas de archivos).
Los perfiles públicos y privados se pueden gestionar por separado.
En proyectos de código abierto sólo se deben incluir elementos de configuración públicos, no configuraciones privadas. Sin embargo, este requisito no significa mucho para los proyectos privados.
En el trabajo, he utilizado varios métodos para administrar la configuración del proyecto Python, los dos principales son:
Escribir un archivo de configuración separado para cada entorno e ingresar al entorno correspondiente, y enlace suave el archivo de configuración del entorno a la ruta correcta.
¿Cómo gestionar la configuración del proyecto Python? Utilice el Servicio de configuración distribuida para obtener la configuración desde ubicaciones remotas.
El primero es realmente muy problemático de usar, especialmente cuando desea ejecutar pruebas unitarias localmente, debe reemplazar el archivo de configuración con un entorno de prueba unitaria. Así que agregué las variables de entorno nuevamente y cuando se detecte la variable de entorno especificada, se cargará la configuración de la prueba unitaria. Se pueden cumplir varios requisitos más, aunque no de forma elegante.
Este último no puede usar el código Python directamente. Cuando la red no es buena, es necesario degradarla para usar el caché local. Debe configurarse para obtener la dirección del servidor de configuración. También es necesario configurarlo y el servidor de configuración puede bloquearse (Zhihu La intranet una vez encontró una situación en la que los cinco servidores de configuración estaban inactivos), así que lo usé menos.
De hecho, si lo piensa detenidamente, encontrará que "usar código Python" significa archivos fuente de Python y "dejar que los elementos de configuración comunes se implementen en Python" significa herencia, por lo que parece haber no hay mejor opción.
¿Cómo gestionar la configuración del proyecto Python? Por lo tanto, defina una clase Config y haga que todas las demás configuraciones del entorno hereden de esta clase:
# config/default.pyclass Config(object):
DEBUG_MODE = True
PUERTO = 12345
COOKIE_ SECRET = 'predeterminado'
REDIS_CONFIG = {'host': 'localhost', 'puerto': 6379, 'db': 0} # . ..
# config/development.pyfrom .default import Configclass DevelopmentConfig(Config):
COOKIE_SECRET = 'dev'
# config/unit_testing. .default import Configclass UnitTestingConfig(Config):
REDIS_CONFIG = {'host': 'localhost', 'port': 6379, 'db': 1}
# config/producción .pyfrom .default import Configclass ProductionConfig(Config):
COOKIE_SECRET = '...'.
REDIS_CONFIG = {'unix_socket_path': '/tmp/redis.sock'}
Para que solo una configuración surta efecto en cada entorno, agregue otra política: [página ]
# config/__init__.pyimport loggingimport os
env = os.getenv('ENV') # Puede cambiar el nombre a otro y configurarlo usted mismo: if env = = 'PRODUCCIÓN ': de .production import
ProductionConfig as CONFIG
logging.info('Configuración de producción cargada.') elif env == 'PRUEBAS': de .testing import TestingConfig como CONFIG
logging.info('Configuración de prueba cargada.') elif env == 'UNIT_TESTING': desde .unit_testing importe UnitTestingConfig como
CONFIG
registro .info('Configuración de prueba unitaria cargada.') else: # Utilice la configuración del entorno de desarrollo local de forma predeterminada, no es necesario establecer variables de entorno
desde .development importe DevelopmentConfig como CONFIG
logging.info('Configuración de desarrollo cargada.')excepto ImportError:
logging.warning('Error al cargar la configuración para el entorno s, use la configuración predeterminada en su lugar.', env o 'configuración no especificada'), 'developmentConfig as CONFIG'
desde .env o 'unspecified')
desde .default import Config as CONFIG
De esta manera solo necesita configurar diferentes variables de entorno antes ejecutando su aplicación. Si utiliza un supervisor para mantener el proceso, agregue la línea entorno = ENV="PRODUCCIÓN".
También puedes agregar otras reglas, como verificar el nombre de la máquina cuando no hay variables de entorno.
¿Cómo gestionar la configuración del proyecto Python? Ahora que se cumplen los dos primeros requisitos, veamos qué hace el submódulo.
Este requisito corresponde al paquete de Python, así que simplemente cambie el archivo de administración de configuración de cada proyecto de Python a un paquete. Lo siguiente es cómo satisfacer el segundo y tercer requisito.
Por ejemplo, existe una configuración de este tipo:
# config/default.pyclass Config(object):
ROOT_PATH = '/'
LOGIN_PATH = ROOT_PATH 'iniciar sesión'
SCHEME = ''
ROOT_URL = 's://ss' (Config.SCHEME, DOMAIN, ROOT_PATH)
Entre ellos, la lógica para configurar LOGIN_PATH y LOGIN_URL es en realidad la misma, pero los valores son diferentes, y reasignar estos valores en ProductionConfig es un poco anodino.
Así que extrae estas configuraciones y configúralas después de inicializar las configuraciones básicas:
class _AfterMeta(type):
def __init__(cls, name, bases, dct ):
super(_AfterMeta. cls).__init__(nombre, bases, dct)
cls._after() clase Config(objeto):
__metaclass__ = _AfterMeta
ROOT_PATH = '/'
SCHEME = ''
¿Cómo funciona la gestión de configuración de proyectos de Python? Todas las configuraciones con dependencias simplemente se asignan en el método _after.
Sin embargo, esto causa problemas de verificación estática y sugerencias de código, y hace que todas las subclases redefinan estas propiedades, incluso si no modifican las propiedades de la clase principal ni anulan los valores establecidos manualmente. Por lo tanto se puede modificar nuevamente: [página]
clase _AfterMeta(tipo):
def __init__(cls, nombre, bases, dct):
super (_AfterMeta, cls).
__init__(nombre, bases, dct)
cls._after(dct) clase Config(objeto):
__metaclass__ = _AfterMeta
ROOT_PATH = '/'
LOGIN_ PATH = ROOT_PATH 'iniciar sesión'
SCHEME = 'http'
DOMAIN = 'localhost'
ROOT_URL = 's:/ /ss' (SCHEME, DOMAIN, ROOT_PATH) @ classmethod
def _after(cls, own_attrs):
si 'LOGIN_PATH' no está en own_attrs y 'ROOT_PATH' en own_attrs: p> p>
cls.LOGIN_PATH = cls.
si 'ROOT_URL' no está en own_attrs y ('SCHEME' en own_attrs o 'DOMAIN' en own_attrs o 'ROOT_PATH' en
own_attrs):
cls.ROOT_URL = 's://ss' (cls.SCHEME, cls.DOMAIN, cls.ROOT_PATH)
Aunque el problema ha sido solucionado, todavía hay que escribirlo. La cantidad de código parece demasiado grande. No parece haber una solución mejor, afortunadamente estas configuraciones no son muchas, por lo que no está de más reescribirlas una vez.
Solo queda separar la configuración pública y privada.
Dado que necesitamos configuraciones privadas, es fácil pensar en ponerlas en otro repositorio y luego vincularlas a la carpeta de configuración:
└─config
├ ─ __init__.py
├── default.py
├── desarrollo .py -gt; privado/desarrollo.py
├── desarrollo_sample. py
├── privado (clonar desde otro repositorio privado)
│ ├── desarrollo.py
│ └── producción.py
├─ production.py -gt; private/production.py
└──production_sample.py
Para evitar enviar archivos al repositorio público*** , se pueden agregar archivos de configuración privados a .gitignore.
Por cierto, los datos de mi blog se almacenan en Redis, por lo que solo necesito hacer una copia de seguridad del archivo rdb. Sin embargo, usar otro servidor para realizar copias de seguridad sería demasiado lujoso, así que instalé Dropbox en el servidor y vinculé la carpeta de datos en la carpeta de Dropbox a la carpeta de datos del blog, que es
doodle
<. p>└── data└── redis -gt; ~/ Dropbox/doodle/redis
De esta manera, Dropbox actualizará el archivo inmediatamente después de cambiarlo. Realiza copias de seguridad automáticas y conserva todas las versiones históricas, perfecto.
¿Cómo gestionar la configuración del proyecto Python? Esta es la habilidad de Python que más necesitas. El módulo que utilizo para crear y gestionar entornos virtuales se llama venv. Venv normalmente instalará la última versión de Python que tenga. ¿Puedes manejarlo si tienes varias versiones de Python en tu sistema? Si todavía le preocupa no haber empezado bien, los demás artículos de esta sección seguramente le ayudarán.