zope.generations

Tela Software:
zope.generations
Detalhes de Software:
Versão: 4.0.0 Alpha 1
Data de upload: 15 Apr 15
Licença: Livre
Popularidade: 37

Rating: nan/5 (Total Votes: 0)

zope.generations fornece uma maneira de atualizar os objetos no banco de dados quando as alterações de esquema de aplicação. & Nbsp; Um esquema de aplicação é essencialmente a estrutura de dados, a estrutura de classes no caso de ZODB ou as descrições da tabela em caso de um banco de dados relacional.
A documentação detalhada
Gerações são uma forma de atualizar os objetos no banco de dados quando as alterações de esquema de aplicação. Um esquema de aplicação é, essencialmente, a estrutura de dados, a estrutura de classes no caso de ZODB ou as descrições das tabelas no caso de uma base de dados relacional.
Quando você altera as estruturas de dados do seu aplicativo, por exemplo, você muda o significado semântico de um campo existente em uma classe, você vai ter um problema com os bancos de dados que foram criados antes de sua mudança. Para uma discussão mais aprofundada e possíveis soluções, consulte http://wiki.zope.org/zope3/DatabaseGenerations
Nós estaremos usando a arquitetura de componentes, e vamos precisar de um banco de dados e uma conexão:
& Nbsp; >>> cgi importação
& Nbsp; >>> from pprint importação pprint
& Nbsp; >>> from implementos importação zope.interface
& Nbsp; >>> from ZODB.tests.util importação DB
& Nbsp; >>> db = DB ()
& Nbsp; >>> conn = db.open ()
& Nbsp; >>> root = conn.root ()
Imagine que a nossa aplicação é um oráculo: você pode ensiná-lo a reagir a frases. Vamos mantê-lo simples e armazenar os dados em um dicionário:
& Nbsp; >>> raiz ['respostas'] = {'Olá': 'Hi & como você faz ",
& Nbsp; ... '? Significado da vida': '42',
& Nbsp; ... 'quatro & Nbsp; >>> transação de importação
& Nbsp; >>> transaction.commit ()
A configuração inicial
Aqui está um código de gerações específicas. Vamos criar e registrar um SchemaManager. SchemaManagers são responsáveis ​​pelas atualizações reais do banco de dados. Este será apenas um manequim. O ponto aqui é fazer com que as gerações módulo conscientes de que a nossa aplicação suporta gerações.
A implementação padrão de SchemaManager não é adequado para este teste, pois ele usa módulos Python para gerenciar gerações. Por enquanto, ele vai ficar bem, já que não quer que ele faça nada ainda.
& Nbsp; >>> from zope.generations.interfaces importar ISchemaManager
& Nbsp; >>> from zope.generations.generations importar SchemaManager
& Nbsp; >>> zope.component importação
& Nbsp; >>> dummy_manager = SchemaManager (minimum_generation = 0, geração = 0)
& Nbsp; >>> zope.component.provideUtility (
& Nbsp; ... dummy_manager, ISchemaManager, name = 'some.app')
'Some.app' é um identificador único. Você deve usar um URI ou o nome pontilhada de seu pacote.
Quando você inicia o Zope e um banco de dados é aberto, um IDatabaseOpenedWithRoot evento é enviado. Zope registra evolveMinimumSubscriber por padrão como uma rotina de tratamento para este evento. Vamos simular este:
& Nbsp; >>> DatabaseOpenedEventStub classe (objeto):
& Nbsp; ... def __init __ (self, banco de dados):
& Nbsp; ... self.database = banco de dados
& Nbsp; >>> event = DatabaseOpenedEventStub (db)
& Nbsp; >>> from zope.generations.generations importar evolveMinimumSubscriber
& Nbsp; >>> evolveMinimumSubscriber (evento)
A conseqüência dessa ação é que agora o banco de dados contém o fato de que nosso número de esquema atual é 0. Quando atualizar o esquema, Zope3 terá uma idéia do que o ponto de partida era. Aqui, está vendo?
& Nbsp; >>> from zope.generations.generations importar generations_key
& Nbsp; >>> root [generations_key] ['some.app']
& Nbsp; 0
Na vida real, você nunca deve ter que se preocupar com essa chave diretamente, mas você deve estar ciente de que ele existe.
Atualização cenário
Voltar para a história. Algum tempo passa e um de nossos clientes for cortada porque esqueceu de escapar caracteres especiais HTML! O horror! Temos de corrigir esse problema o mais rápido possível, sem perder nenhum dado. Nós decidir usar gerações de impressionar nossos pares.
Vamos atualizar o gerente do esquema (soltar o antigo e instalar uma nova personalizada):
& Nbsp; >>> from zope.component globalregistry importação
& Nbsp; >>> gsm = globalregistry.getGlobalSiteManager ()
& Nbsp; >>> gsm.unregisterUtility (desde = ISchemaManager, name = 'some.app')
& Nbsp; A verdadeira
& Nbsp; >>> MySchemaManager classe (objeto):
& Nbsp; ... implementos (ISchemaManager)
& Nbsp; ...
& Nbsp; ... minimum_generation = 1
& Nbsp; ... geração = 2
& Nbsp; ...
& Nbsp; ... def evoluir (self, contexto, geração):
& Nbsp; ... root = context.connection.root ()
& nbsp; ... respostas = raiz ['respostas']
& Nbsp; ... se geração == 1:
& Nbsp; ... para pergunta, resposta em answers.items ():
& Nbsp; ... respostas [pergunta] = cgi.escape (resposta)
& Nbsp; ... elif geração == 2:
& Nbsp; ... para pergunta, resposta em answers.items ():
& Nbsp; ... del respostas [pergunta]
& Nbsp; ... respostas [cgi.escape (pergunta)] = resposta
& Nbsp; ... else:
& Nbsp; ... levantar ValueError ("Bummer")
& Nbsp; ... raiz ['respostas'] = respostas # ping persistência
& Nbsp; ... transaction.commit ()
& Nbsp; >>> manager = MySchemaManager ()
& Nbsp; >>> zope.component.provideUtility (gerente, ISchemaManager, name = 'some.app')
Criámos minimum_generation para 1. Isso significa que a nossa aplicação irá se recusar a correr com um banco de dados mais velho do que a geração 1. O atributo geração é definido como 2, o que significa que a última geração que este SchemaManager conhece é 2.
evoluem () é o carro-chefe aqui. Seu trabalho é fazer com que o banco de dados de geração-1 em geração. Fica um contexto que tem a "conexão" atributo, que é uma conexão com o ZODB. Você pode usar isso para mudar objetos, como neste exemplo.
Nesta geração implementação particular 1 escapa das respostas (digamos, críticas, porque eles podem ser inseridos por qualquer pessoa!), A geração de 2 escapa das perguntas (digamos, menos importantes, porque estes podem ser inseridos por autorizado personell apenas).
Na verdade, você realmente não precisa de uma implementação personalizada do ISchemaManager. Um está disponível, nós tê-lo usado por um manequim anteriormente. Ele usa módulos Python para a organização das funções Evolver. Veja seu docstring para mais informações.
Na vida real, você terá muito mais estruturas de objetos complexos do que o daqui. Para facilitar a sua vida, há duas funções muito úteis disponíveis em zope.generations.utility: findObjectsMatching () e findObjectsProviding (). Eles vão cavar através de contentores de forma recursiva para ajudá-lo a procurar objetos antigos que você deseja atualizar, por interface ou por outros critérios. Eles são fáceis de entender, verificar os seus docstrings.
Gerações em ação
Então, o nosso cliente furioso transfere nosso código mais recente e reinicia Zope. O evento é automaticamente enviado novamente:
& Nbsp; >>> event = DatabaseOpenedEventStub (db)
& Nbsp; >>> evolveMinimumSubscriber (evento)
Shazam! O cliente está feliz de novo!
& Nbsp; >>> pprint (raiz ['respostas'])
& Nbsp; {'Olá': 'Hi & como você faz?',
& Nbsp; "sentido da vida? ':' 42 ',
& Nbsp; "quatro Porque evolveMinimumSubscriber é muito preguiçoso, ele só atualiza o banco de dados apenas o suficiente para que a sua aplicação pode usá-lo (ao minimum_generation, que é). De facto, o marcador indica que a geração do banco de dados tenha sido batido até 1:
& Nbsp; >>> root [generations_key] ['some.app']
& Nbsp; 1
Vemos que as gerações estão trabalhando, por isso, decidimos dar o próximo passo e evoluir para geração 2. Vamos ver como isso pode ser feito manualmente:
& Nbsp; >>> from zope.generations.generations importar evoluir
& Nbsp; >>> evoluir (db)
& Nbsp; >>> pprint (raiz ['respostas'])
& Nbsp; {'Olá': 'Hi & como você faz?',
& Nbsp; "sentido da vida? ':' 42 ',
& Nbsp; "quatro & Nbsp; >>> root [generations_key] ['some.app']
& Nbsp; 2
Comportamento padrão de upgrades evoluir para a mais recente geração fornecido pela SchemaManager. Você pode usar o argumento como evoluir () quando você quer apenas para verificar se você precisa atualizar ou se você quer ser preguiçoso como o assinante que chamamos anteriormente.
Ordenação dos gestores de esquema
Frequentemente subsistemas utilizados para compor uma aplicação dependem de outros subsistemas para operar corretamente. Se ambos os subsistemas de fornecer aos gestores de esquema, que muitas vezes é útil para saber a ordem em que os Evolvers será invocado. Isso permite que um quadro e é clientes para ser capaz de evoluir em concerto, e os clientes podem saber que o quadro será evoluído antes ou depois de si mesmo.
Isto pode ser conseguido controlando os nomes dos utilitários do gerenciador de esquema. Os gestores de esquema são executados na ordem determinada pela triagem seus nomes.
& Nbsp; >>> manager1 = SchemaManager (minimum_generation = 0, geração = 0)
& Nbsp; >>> manager2 = SchemaManager (minimum_generation = 0, geração = 0)
& Nbsp; >>> zope.component.provideUtility (
& Nbsp; ... manager1, ISchemaManager, name = 'another.app')
& Nbsp; >>> zope.component.provideUtility (
& Nbsp; ... manager2, ISchemaManager, name = 'another.app-extensão')
Observe como o nome do primeiro pacote é usado para criar um espaço de nomes para pacotes dependentes. Isto não é um requisito do quadro, mas um padrão conveniente para esta utilização.
Vamos evoluir o banco de dados para estabelecer essas gerações:
& Nbsp; >>> event = DatabaseOpenedEventStub (db)
& Nbsp; >>> evolveMinimumSubscriber (evento)
& Nbsp; >>> root [generations_key] ['another.app']
& Nbsp; 0
& Nbsp; >>> root [generations_key] ['another.app-extensão']
& Nbsp; 0
Vamos supor que, por algum motivo a cada subsistema precisa adicionar uma geração, e que a geração de 1 de 'another.app-extensão' depende de geração de 1 de 'another.app'. Vamos precisar de fornecer aos gestores de esquema para cada registro que que eles foram executados para que possamos verificar o resultado:
& Nbsp; >>> gsm.unregisterUtility (desde = ISchemaManager, name = 'another.app')
& Nbsp; A verdadeira
& Nbsp; >>> gsm.unregisterUtility (
& Nbsp; ... desde = ISchemaManager, name = 'another.app-extensão')
& Nbsp; A verdadeira
& Nbsp; >>> class FoundationSchemaManager (objeto):
& Nbsp; ... implementos (ISchemaManager)
& Nbsp; ...
& Nbsp; ... minimum_generation = 1
& Nbsp; ... geração = 1
& Nbsp; ...
& Nbsp; ... def evoluir (self, contexto, geração):
& Nbsp; ... root = context.connection.root ()
& Nbsp; ... encomenda = root.get ('encomenda', [])
& Nbsp; ... se geração == 1:
& Nbsp; ... ordering.append ("fundação 1 ')
& Nbsp; ... 'geração fundação um' print
& Nbsp; ... else:
& Nbsp; ... levantar ValueError ("Bummer")
& Nbsp; ... root ['encomenda'] = ordenação # ping persistência
& Nbsp; ... transaction.commit ()
& Nbsp; >>> DependentSchemaManager classe (objeto):
& Nbsp; ... implementos (ISchemaManager)
& Nbsp; ...
& Nbsp; ... minimum_generation = 1
& Nbsp; ... geração = 1
& Nbsp; ...
& Nbsp; ... def evoluir (self, contexto, geração):
& Nbsp; ... root = context.connection.root ()
& Nbsp; ... encomenda = root.get ('encomenda', [])
& Nbsp; ... se geração == 1:
& Nbsp; ... ordering.append ('dependente 1')
& Nbsp; ... print 'geração dependente 1'
& Nbsp; ... else:
& Nbsp; ... levantar ValueError ("Bummer")
& Nbsp; ... root ['encomenda'] = ordenação # ping persistência
& Nbsp; ... transaction.commit ()
& Nbsp; >>> manager1 = FoundationSchemaManager ()
& Nbsp; >>> manager2 = DependentSchemaManager ()
& Nbsp; >>> zope.component.provideUtility (
& Nbsp; ... manager1, ISchemaManager, name = 'another.app')
& Nbsp; >>> zope.component.provideUtility (
& Nbsp; ... manager2, ISchemaManager, name = 'another.app-extensão')
Evoluindo o banco de dados agora será sempre executar o 'another.app' evolver antes do 'another.app-extensão "evolver:
& Nbsp; >>> event = DatabaseOpenedEventStub (db)
& Nbsp; >>> evolveMinimumSubscriber (evento)
& Nbsp; geração fundação 1
& Nbsp; geração dependente 1
& Nbsp; >>> raiz ['encomenda']
& Nbsp; ['fundação 1', 'dependente 1']
Instalação
No exemplo acima, nós inicializado manualmente as respostas. Nós não devemos ter que fazer isso manualmente. A aplicação deve ser capaz de fazer isso automaticamente.
IInstallableSchemaManager estende ISchemaManager, fornecendo um método de instalação para executar uma instalação intial de um aplicativo. Esta é uma alternativa melhor do que registrar assinantes aberta de banco de dados.
Vamos definir um novo gerenciador de esquema que inclui a instalação:
& Nbsp; >>> gsm.unregisterUtility (desde = ISchemaManager, name = 'some.app')
& Nbsp; A verdadeira
& Nbsp; >>> from zope.generations.interfaces importar IInstallableSchemaManager
& Nbsp; >>> MySchemaManager classe (objeto):
& Nbsp; ... implementos (IInstallableSchemaManager)
& Nbsp; ...
& Nbsp; ... minimum_generation = 1
& Nbsp; ... geração = 2
& Nbsp; ...
& Nbsp; ... def instalar (self, contexto):
& Nbsp; ... root = context.connection.root ()
& Nbsp; ... raiz ['respostas'] = {'Olá': 'Hi & como você faz ",
& Nbsp; ... '? Significado da vida': '42',
& Nbsp; ... 'quatro & Nbsp; ... transaction.commit ()
& Nbsp; ...
& Nbsp; ... def evoluir (self, contexto, geração):
& Nbsp; ... root = context.connection.root ()
& nbsp; ... respostas = raiz ['respostas']
& Nbsp; ... se geração == 1:
& Nbsp; ... para pergunta, resposta em answers.items ():
& Nbsp; ... respostas [pergunta] = cgi.escape (resposta)
& Nbsp; ... elif geração == 2:
& Nbsp; ... para pergunta, resposta em answers.items ():
& Nbsp; ... del respostas [pergunta]
& Nbsp; ... respostas [cgi.escape (pergunta)] = resposta
& Nbsp; ... else:
& Nbsp; ... levantar ValueError ("Bummer")
& Nbsp; ... raiz ['respostas'] = respostas # ping persistência
& Nbsp; ... transaction.commit ()
& Nbsp; >>> manager = MySchemaManager ()
& Nbsp; >>> zope.component.provideUtility (gerente, ISchemaManager, name = 'some.app')
Agora, vamos abrir um novo banco de dados:
& Nbsp; >>> db.close ()
& Nbsp; >>> db = DB ()
& Nbsp; >>> conn = db.open ()
& Nbsp; >>> 'respostas' em conn.root ()
& Nbsp; False
& Nbsp; >>> event = DatabaseOpenedEventStub (db)
& Nbsp; >>> evolveMinimumSubscriber (evento)
& Nbsp; >>> conn.sync ()
& Nbsp; >>> root = conn.root ()
& Nbsp; >>> pprint (raiz ['respostas'])
& Nbsp; {'Olá': 'Hi & como você faz?',
& Nbsp; "sentido da vida? ':' 42 ',
& Nbsp; "quatro & Nbsp; >>> root [generations_key] ['some.app']
& Nbsp; 2
O log de transações ZODB observa que o nosso script de instalação foi executado
& Nbsp; >>> [. It.description para ele em conn.db () storage.iterator ()] [- 2]
& Nbsp; u'some.app: executar a instalação geração '
(Nota menor: não é o último registro porque há dois commits: MySchemaManager realiza um, e evolveMinimumSubscriber realiza a segunda MySchemaManager realmente não precisa se comprometer.).

O que é novo nesta versão:.

  • Adicionado suporte para Python 3.3
  • Substituído preterido uso zope.interface.implements com decorador zope.interface.implementer equivalente.
  • retirou o suporte para Python 2.4 e 2.5.

O que é novo na versão 3.7.1:

  • Removido parte buildout que foi utilizado durante o desenvolvimento, mas não não compilar no Windows.
  • scripts de geração de adicionar uma nota transação.

Requisitos :

  • Python

Outro software de desenvolvedor Zope Corporation and Contributors

Comentário para zope.generations

Comentários não encontrado
Adicionar comentário
Ligue imagens!