zope.generations

Software screenshot:
zope.generations
Dettagli del software:
Versione: 4.0.0 Alpha 1
Data di caricamento: 15 Apr 15
Licenza: Libero
Popolarità: 2

Rating: nan/5 (Total Votes: 0)

zope.generations fornisce un modo di aggiornamento degli oggetti nel database quando le modifiche dello schema di applicazione e nbsp;. Uno schema di applicazione è essenzialmente la struttura di dati, la struttura di classi nel caso di ZODB o le descrizioni tabella nel caso di un database relazionale.
Documentazione dettagliata
Generazioni sono un modo di aggiornare gli oggetti nel database quando le modifiche dello schema di applicazione. Uno schema di applicazione è essenzialmente la struttura di dati, la struttura di classi nel caso di ZODB o le descrizioni tabella nel caso di un database relazionale.
Quando si modificano le strutture di dati della vostra applicazione, per esempio, si modifica il significato semantico di un campo esistente in una classe, si avrà un problema con le banche dati che sono stati creati prima della modifica. Per una discussione più approfondita e le possibili soluzioni, vedi http://wiki.zope.org/zope3/DatabaseGenerations
Useremo l'architettura a componenti, e avremo bisogno di un database e di una connessione:
& Nbsp; >>> cgi import
& Nbsp; >>> da pprint import pprint
& Nbsp; >>> da zope.interface strumenti di importazione
& Nbsp; >>> da DB import ZODB.tests.util
& Nbsp; >>> db = DB ()
& Nbsp; >>> conn = db.open ()
& Nbsp; >>> root = conn.root ()
Immaginate che la nostra applicazione è un oracolo: si può insegnare a reagire a frasi. Cerchiamo di fare cose semplici e memorizzare i dati in un dict:
& Nbsp; >>> radice ['risposte'] = {'Ciao': '? Ciao e come si fa',
& Nbsp; ... '? Senso della vita': '42',
& Nbsp; ... 'quattro & Nbsp; >>> operazione d'importazione
& Nbsp; >>> transaction.commit ()
Impostazione iniziale
Ecco un po 'di codice specifici generazioni-. Noi creare e registrare un SchemaManager. SchemaManagers sono responsabili per gli aggiornamenti reali del database. Questo sarà solo un manichino. Il punto è quello di rendere le generazioni modulo consapevoli che la nostra applicazione supporta generazioni.
L'implementazione predefinita di SchemaManager non è adatto per questa prova perché utilizza moduli Python per gestire generazioni. Per ora, sarà bene, dal momento che non vogliamo fare nulla per il momento.
& Nbsp; >>> da zope.generations.interfaces import ISchemaManager
& Nbsp; >>> da zope.generations.generations import SchemaManager
& Nbsp; >>> zope.component import
& Nbsp; >>> dummy_manager = SchemaManager (minimum_generation = 0, generazione = 0)
& Nbsp; >>> zope.component.provideUtility (
& Nbsp; ... dummy_manager, ISchemaManager, name = 'some.app')
'Some.app' è un identificatore univoco. È necessario utilizzare un URI o il nome tratteggiata del pacchetto.
Quando si avvia Zope e un database è aperto, un IDatabaseOpenedWithRoot evento viene inviato. Zope registra evolveMinimumSubscriber di default come un gestore per questo evento. Facciamo simulare questo:
& Nbsp; >>> DatabaseOpenedEventStub classe (oggetto):
& Nbsp; ... def __init __ (self, database):
& Nbsp; ... self.database = Database
& Nbsp; >>> evento = DatabaseOpenedEventStub (db)
& Nbsp; >>> da zope.generations.generations import evolveMinimumSubscriber
& Nbsp; >>> evolveMinimumSubscriber (evento)
La conseguenza di questa azione è che ora il database contiene il fatto che il nostro numero di schema attuale è 0. Quando si aggiorna lo schema, Zope3 avrà un'idea di ciò che il punto di partenza era. Qui, vedi?
& Nbsp; >>> da zope.generations.generations import generations_key
& Nbsp; >>> radice [generations_key] ['some.app']
& Nbsp; 0
Nella vita reale non si dovrebbe mai avere a preoccuparsi di questa chiave direttamente, ma si deve essere consapevoli che esiste.
Aggiornamento scenario
Torna alla storia. Qualche tempo passa e uno dei nostri clienti viene violato, perché abbiamo dimenticato di sfuggire HTML caratteri speciali! L'orrore! Dobbiamo risolvere il problema al più presto, senza perdere i dati. Decidiamo di utilizzare generazioni per impressionare i nostri coetanei.
Aggiorniamo il manager schema (cadere il vecchio e installare un nuovo personalizzato uno):
& Nbsp; >>> da zope.component globalregistry import
& Nbsp; >>> gsm = globalregistry.getGlobalSiteManager ()
& Nbsp; >>> gsm.unregisterUtility (fornito = ISchemaManager, name = 'some.app')
& Nbsp; La vera
& Nbsp; >>> MySchemaManager classe (oggetto):
& Nbsp; ... attrezzi (ISchemaManager)
& Nbsp; ...
& Nbsp; ... minimum_generation = 1
& Nbsp; ... generazione = 2
& Nbsp; ...
& Nbsp; ... def evolvere (self, context, generazione):
& Nbsp; ... root = context.connection.root ()
& nbsp; ... Risposte = radice ['risposte']
& Nbsp; ... se generazione == 1:
& Nbsp; ... per la domanda, la risposta a answers.items ():
& Nbsp; ... risposte [domanda] = cgi.escape (risposta)
& Nbsp; ... generazione Elif == 2:
& Nbsp; ... per la domanda, la risposta a answers.items ():
& Nbsp; ... Del risposte [domanda]
& Nbsp; ... risposte [cgi.escape (domanda)] = risposta
& Nbsp; ... else:
& Nbsp; ... sollevare ValueError ("Bummer")
& Nbsp; ... radice ['risposte'] = risposte # ping persistenza
& Nbsp; ... transaction.commit ()
& Nbsp; >>> direttore = MySchemaManager ()
& Nbsp; >>> zope.component.provideUtility (manager, ISchemaManager, name = 'some.app')
Abbiamo fissato minimum_generation a 1. Ciò significa che la nostra applicazione si rifiuterà di eseguire con un database più grande di generazione 1. L'attributo generazione è impostato su 2, il che significa che l'ultima generazione che questo SchemaManager conosce è 2.
evolvere () è il cavallo di battaglia qui. Il suo compito è quello di ottenere il database di generazione-1 in generazione. Si ottiene un contesto che ha il 'collegamento' attributo, che è una connessione al ZODB. È possibile utilizzare che per modificare gli oggetti come in questo esempio.
In questa particolare generazione di attuazione 1 sfugge le risposte (diciamo, critiche, perché possono essere inseriti da nessuno!), Generazione 2 sfugge alle questioni (diciamo, meno importanti, perché questi possono essere inseriti autorizzato personell solo).
In realtà, non si ha realmente bisogno di una implementazione personalizzata di ISchemaManager. Uno è disponibile, abbiamo usato per un manichino in precedenza. Esso utilizza moduli Python per l'organizzazione delle funzioni Evolver. Vedere la sua docstring per maggiori informazioni.
Nella vita reale si avrà strutture molto più complesse di oggetti rispetto a quello qui. Per rendere la vita più facile, ci sono due funzioni molto utili disponibili in zope.generations.utility: findObjectsMatching () e findObjectsProviding (). Essi scavare attraverso i contenitori in modo ricorsivo per aiutarvi a cercare vecchi oggetti che si desidera aggiornare, tramite interfaccia o da altri criteri. Sono facili da capire, controllare le docstring.
Generazioni in azione
Quindi, il nostro cliente furioso scarica il nostro ultimo codice e riavvia Zope. L'evento viene inviato automaticamente di nuovo:
& Nbsp; >>> evento = DatabaseOpenedEventStub (db)
& Nbsp; >>> evolveMinimumSubscriber (evento)
Shazam! Il client è di nuovo felice!
& Nbsp; >>> pprint (root ['risposta'])
& Nbsp; {'Ciao': 'Ciao e come si fa?',
& Nbsp; 'senso della vita?': '42',
& Nbsp; 'quattro Perché evolveMinimumSubscriber è molto pigro, aggiorna solo il database appena sufficiente in modo che l'applicazione può utilizzare (per il minimum_generation, che è). Infatti, il marcatore indica che la generazione database è stato urtato da 1:
& Nbsp; >>> radice [generations_key] ['some.app']
& Nbsp; 1
Vediamo che le generazioni stanno lavorando, così decidiamo di fare il passo successivo e si evolvono in generazione 2. Vediamo come questo può essere fatto manualmente:
& Nbsp; >>> da zope.generations.generations import evolvere
& Nbsp; >>> evolvere (db)
& Nbsp; >>> pprint (root ['risposta'])
& Nbsp; {'Ciao': 'Ciao e come si fa?',
& Nbsp; 'senso della vita?': '42',
& Nbsp; 'quattro & Nbsp; >>> radice [generations_key] ['some.app']
& Nbsp; 2
Comportamento predefinito di aggiornamenti evolvono per l'ultima generazione fornita dal SchemaManager. È possibile utilizzare l'argomento come evolvere () quando si desidera solo per verificare se è necessario aggiornare o se si vuole essere pigro come l'abbonato che abbiamo chiamato in precedenza.
Ordinamento dei responsabili dello schema
Spesso sottosistemi utilizzati per comporre un'applicazione contare su altri sottosistemi per funzionare correttamente. Se entrambi i sottosistemi forniscono ai gestori dello schema, è spesso utile conoscere l'ordine in cui saranno invocate le Evolvers. Questo permette un quadro ed è clienti di essere in grado di evolvere in concerto, ed i clienti possono sapere che il quadro sarà evoluto prima o dopo se stessa.
Ciò può essere eseguito controllando i nomi degli strumenti di gestione schema. I gestori dello schema vengono eseguite nell'ordine determinato di classificare i loro nomi.
& Nbsp; >>> Manager1 = SchemaManager (minimum_generation = 0, generazione = 0)
& Nbsp; >>> manager2 = SchemaManager (minimum_generation = 0, generazione = 0)
& Nbsp; >>> zope.component.provideUtility (
& Nbsp; ... Manager1, ISchemaManager, name = 'another.app')
& Nbsp; >>> zope.component.provideUtility (
& Nbsp; ... manager2, ISchemaManager, name = 'another.app-estensione')
Notate come il nome del primo pacchetto viene utilizzato per creare uno spazio dei nomi per i pacchetti dipendenti. Questo non è un requisito del quadro, ma un modello conveniente per questo utilizzo.
Facciamo evolvere il database di stabilire queste generazioni:
& Nbsp; >>> evento = DatabaseOpenedEventStub (db)
& Nbsp; >>> evolveMinimumSubscriber (evento)
& Nbsp; >>> radice [generations_key] ['another.app']
& Nbsp; 0
& Nbsp; >>> radice [generations_key] ['another.app-estensione']
& Nbsp; 0
Supponiamo che per qualche motivo ciascuno di questi sottosistemi deve aggiungere una generazione, e che la produzione di 1 'another.app-extension' dipende generazione 1 di 'another.app'. Avremo bisogno di fornire ai gestori dello schema per ciascun quel record di essere stati eseguiti in modo da poter verificare il risultato:
& Nbsp; >>> gsm.unregisterUtility (fornito = ISchemaManager, name = 'another.app')
& Nbsp; La vera
& Nbsp; >>> gsm.unregisterUtility (
& Nbsp; ... a condizione = ISchemaManager, name = 'another.app-estensione')
& Nbsp; La vera
& Nbsp; >>> classe FoundationSchemaManager (oggetto):
& Nbsp; ... attrezzi (ISchemaManager)
& Nbsp; ...
& Nbsp; ... minimum_generation = 1
& Nbsp; ... generazione = 1
& Nbsp; ...
& Nbsp; ... def evolvere (self, context, generazione):
& Nbsp; ... root = context.connection.root ()
& Nbsp; ... ordinazione = root.get ('ordinazione', [])
& Nbsp; ... se generazione == 1:
& Nbsp; ... ordering.append ('Fondazione 1')
& Nbsp; ... 'generazione fondazione 1' stampa
& Nbsp; ... else:
& Nbsp; ... sollevare ValueError ("Bummer")
& Nbsp; ... root ['ordinazione'] = ordinazione # ping persistenza
& Nbsp; ... transaction.commit ()
& Nbsp; >>> DependentSchemaManager classe (oggetto):
& Nbsp; ... attrezzi (ISchemaManager)
& Nbsp; ...
& Nbsp; ... minimum_generation = 1
& Nbsp; ... generazione = 1
& Nbsp; ...
& Nbsp; ... def evolvere (self, context, generazione):
& Nbsp; ... root = context.connection.root ()
& Nbsp; ... ordinazione = root.get ('ordinazione', [])
& Nbsp; ... se generazione == 1:
& Nbsp; ... ordering.append ('dipende 1')
& Nbsp; ... print 'generazione dipende 1'
& Nbsp; ... else:
& Nbsp; ... sollevare ValueError ("Bummer")
& Nbsp; ... root ['ordinazione'] = ordinazione # ping persistenza
& 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-estensione')
Evoluzione del database ora sarà sempre eseguire il 'another.app' Evolver prima del 'another.app-estensione' Evolver:
& Nbsp; >>> evento = DatabaseOpenedEventStub (db)
& Nbsp; >>> evolveMinimumSubscriber (evento)
& Nbsp; generazione fondazione 1
& Nbsp; generazione dipendente 1
& Nbsp; >>> radice ['ordinazione']
& Nbsp; ['fondazione 1', 'dipende 1']
Installazione
Nel precedente esempio, abbiamo inizializzato manualmente le risposte. Non dobbiamo avere a che fare manualmente. L'applicazione dovrebbe essere in grado di farlo automaticamente.
IInstallableSchemaManager estende ISchemaManager, fornendo un metodo di installazione per eseguire un'installazione intial di un'applicazione. Si tratta di un'alternativa migliore di registrazione abbonati-database aperto.
Definiamo un nuovo gestore schema che include l'installazione:
& Nbsp; >>> gsm.unregisterUtility (fornito = ISchemaManager, name = 'some.app')
& Nbsp; La vera
& Nbsp; >>> da zope.generations.interfaces import IInstallableSchemaManager
& Nbsp; >>> MySchemaManager classe (oggetto):
& Nbsp; ... attrezzi (IInstallableSchemaManager)
& Nbsp; ...
& Nbsp; ... minimum_generation = 1
& Nbsp; ... generazione = 2
& Nbsp; ...
& Nbsp; ... def installare (self, context):
& Nbsp; ... root = context.connection.root ()
& Nbsp; ... root ['risposte'] = {'Ciao': '? Ciao e come si fa',
& Nbsp; ... '? Senso della vita': '42',
& Nbsp; ... 'quattro & Nbsp; ... transaction.commit ()
& Nbsp; ...
& Nbsp; ... def evolvere (self, context, generazione):
& Nbsp; ... root = context.connection.root ()
& nbsp; ... Risposte = radice ['risposte']
& Nbsp; ... se generazione == 1:
& Nbsp; ... per la domanda, la risposta a answers.items ():
& Nbsp; ... risposte [domanda] = cgi.escape (risposta)
& Nbsp; ... generazione Elif == 2:
& Nbsp; ... per la domanda, la risposta a answers.items ():
& Nbsp; ... Del risposte [domanda]
& Nbsp; ... risposte [cgi.escape (domanda)] = risposta
& Nbsp; ... else:
& Nbsp; ... sollevare ValueError ("Bummer")
& Nbsp; ... radice ['risposte'] = risposte # ping persistenza
& Nbsp; ... transaction.commit ()
& Nbsp; >>> direttore = MySchemaManager ()
& Nbsp; >>> zope.component.provideUtility (manager, ISchemaManager, name = 'some.app')
Ora, consente di aprire un nuovo database:
& Nbsp; >>> db.close ()
& Nbsp; >>> db = DB ()
& Nbsp; >>> conn = db.open ()
& Nbsp; 'risposte' >>> a conn.root ()
& Nbsp; False
& Nbsp; >>> evento = DatabaseOpenedEventStub (db)
& Nbsp; >>> evolveMinimumSubscriber (evento)
& Nbsp; >>> conn.sync ()
& Nbsp; >>> root = conn.root ()
& Nbsp; >>> pprint (root ['risposta'])
& Nbsp; {'Ciao': 'Ciao e come si fa?',
& Nbsp; 'senso della vita?': '42',
& Nbsp; 'quattro & Nbsp; >>> radice [generations_key] ['some.app']
& Nbsp; 2
Il log delle transazioni ZODB osserva che il nostro script di installazione è stato eseguito
& Nbsp; >>> [. It.description per essa in conn.db () storage.iterator ()] [- 2]
& Nbsp; u'some.app: esecuzione install generazione '
(Nota minore: non è l'ultimo record, perché ci sono due commit: MySchemaManager esegue una, e evolveMinimumSubscriber esegue la seconda MySchemaManager non ha veramente bisogno di commettere..)

Cosa c'è di nuovo in questa versione:.

  • Aggiunto il supporto per Python 3.3
  • Sostituito utilizzo zope.interface.implements deprecato con decoratore zope.interface.implementer equivalente.
  • cessato il supporto per Python 2.4 e 2.5.

Cosa c'è di nuovo nella versione 3.7.1:

  • Rimosso parte buildout che è stato utilizzato durante lo sviluppo, ma lo fa Non compilare su Windows.
  • script Generation aggiungono una nota di transazione.

Requisiti :

  • Python

Altri software di sviluppo Zope Corporation and Contributors

Commenti a zope.generations

I commenti non trovato
Aggiungi commento
Accendere le immagini!