Skip to content

Commit

Permalink
Merge ef56016 into 61b0946
Browse files Browse the repository at this point in the history
  • Loading branch information
jamadden committed Oct 23, 2018
2 parents 61b0946 + ef56016 commit 7c747c5
Show file tree
Hide file tree
Showing 11 changed files with 226 additions and 50 deletions.
5 changes: 5 additions & 0 deletions .coveragerc
Expand Up @@ -4,6 +4,11 @@ source = zope.generations

[report]
precision = 2
exclude_lines =
pragma: no cover
if __name__ == '__main__':
raise NotImplementedError
raise AssertionError

[paths]
source =
Expand Down
20 changes: 20 additions & 0 deletions README.rst
@@ -1,3 +1,23 @@
==================
zope.generations
==================

.. image:: https://img.shields.io/pypi/v/zope.generations.svg
:target: https://pypi.org/project/zope.generations/
:alt: Latest Version

.. image:: https://img.shields.io/pypi/pyversions/zope.generations.svg
:target: https://pypi.org/project/zope.generations/
:alt: Supported Python versions

.. image:: https://travis-ci.org/zopefoundation/zope.generations.svg?branch=master
:target: https://travis-ci.org/zopefoundation/zope.generations
:alt: Build Status

.. image:: https://coveralls.io/repos/github/zopefoundation/zope.generations/badge.svg
:target: https://coveralls.io/github/zopefoundation/zope.generations
:alt: Code Coverage

Generations are a way of updating objects in the database when the application
schema changes. An application schema is essentially the structure of data,
the structure of classes in the case of ZODB or the table descriptions in the
Expand Down
21 changes: 10 additions & 11 deletions setup.py
Expand Up @@ -26,6 +26,12 @@ def read(*rnames):
with open(os.path.join(os.path.dirname(__file__), *rnames)) as f:
return f.read()

TESTS_REQUIRE = [
'ZODB',
'zope.site',
'zope.testing',
'zope.testrunner',
]

setup(name='zope.generations',
version='4.1.1.dev0',
Expand Down Expand Up @@ -68,24 +74,17 @@ def read(*rnames):
packages=find_packages('src'),
package_dir={'': 'src'},
namespace_packages=['zope'],
extras_require=dict(test=[
'ZODB',
'zope.site',
'zope.testing',
]),
extras_require={
'test': TESTS_REQUIRE,
},
install_requires=[
'setuptools',
'transaction',
'zope.component',
'zope.interface',
'zope.processlifetime',
],
tests_require=[
'ZODB',
'zope.site',
'zope.testing',
'zope.testrunner',
],
tests_require=TESTS_REQUIRE,
include_package_data=True,
zip_safe=False,
)
15 changes: 9 additions & 6 deletions src/zope/generations/README.rst
Expand Up @@ -12,11 +12,14 @@ http://wiki.zope.org/zope3/DatabaseGenerations
We will be using the component architecture, and we will need a database and a
connection:

>>> import cgi
>>> try:
... from html import escape
... except ImportError:
... from cgi import escape
>>> from pprint import pprint
>>> from zope.interface import implementer

>>> from ZODB.tests.util import DB
>>> from ZODB.MappingStorage import DB
>>> db = DB()
>>> conn = db.open()
>>> root = conn.root()
Expand Down Expand Up @@ -107,11 +110,11 @@ one):
... answers = root['answers']
... if generation == 1:
... for question, answer in list(answers.items()):
... answers[question] = cgi.escape(answer)
... answers[question] = escape(answer)
... elif generation == 2:
... for question, answer in list(answers.items()):
... del answers[question]
... answers[cgi.escape(question)] = answer
... answers[escape(question)] = answer
... else:
... raise ValueError("Bummer")
... root['answers'] = answers # ping persistence
Expand Down Expand Up @@ -329,11 +332,11 @@ Let's define a new schema manager that includes installation:
... answers = root['answers']
... if generation == 1:
... for question, answer in answers.items():
... answers[question] = cgi.escape(answer)
... answers[question] = escape(answer)
... elif generation == 2:
... for question, answer in answers.items():
... del answers[question]
... answers[cgi.escape(question)] = answer
... answers[escape(question)] = answer
... else:
... raise ValueError("Bummer")
... root['answers'] = answers # ping persistence
Expand Down
3 changes: 1 addition & 2 deletions src/zope/generations/demo/evolve1.py
Expand Up @@ -12,12 +12,11 @@
#
##############################################################################
"""Silly demo evolution module."""
import zope.generations.demo


generation = 1


def evolve(context):
"""Evolver 1"""
zope.generations.demo.evolve(context, generation)
raise AssertionError("We are never actually called")
10 changes: 1 addition & 9 deletions src/zope/generations/demo3/install.py
Expand Up @@ -12,12 +12,4 @@
#
##############################################################################
"""Silly demo evolution module."""
import zope.generations.demo
import zope.nonexistingmodule # noqa


generation = 3


def evolve(context):
pass
raise ImportError("No module named nonexistingmodule")
4 changes: 2 additions & 2 deletions src/zope/generations/generations.py
Expand Up @@ -47,7 +47,7 @@ class SchemaManager(object):
and we'll create a test database and context:
>>> from ZODB.tests.util import DB
>>> from ZODB.MappingStorage import DB
>>> db = DB()
>>> context = Context()
>>> context.connection = db.open()
Expand Down Expand Up @@ -230,7 +230,7 @@ def evolve(db, how=EVOLVE):
If we create a new database, and evolve it, we'll simply update
the generation data:
>>> from ZODB.tests.util import DB
>>> from ZODB.MappingStorage import DB
>>> db = DB(database_name='testdb')
>>> conn = db.open()
>>> root = conn.root()
Expand Down
4 changes: 2 additions & 2 deletions src/zope/generations/tests/test_backwardcompat.py
Expand Up @@ -19,11 +19,11 @@ class BackwardCompatibilityTests(unittest.TestCase):

def setUp(self):
from zope.generations.generations import old_generations_key
import ZODB.tests.util
from ZODB.MappingStorage import DB
import persistent.mapping
import transaction

self.db = ZODB.tests.util.DB(database_name='testdb')
self.db = DB(database_name='testdb')
self.conn = self.db.open()
self.root = self.conn.root()
generation_data = persistent.mapping.PersistentMapping()
Expand Down
154 changes: 152 additions & 2 deletions src/zope/generations/tests/test_generations.py
Expand Up @@ -13,12 +13,159 @@
##############################################################################
"""Schema-generation tests."""

import zope.component.testing
import doctest
import re
import unittest

import zope.component.testing
from zope.testing import renormalizing


class TestSchemaManager(unittest.TestCase):

assertRaisesRegex = getattr(unittest.TestCase, 'assertRaisesRegex',
unittest.TestCase.assertRaisesRegexp)

def _getTargetClass(self):
from zope.generations.generations import SchemaManager
return SchemaManager

def _makeOne(self, *args, **kwargs):
return self._getTargetClass()(*args, **kwargs)

def test_ctor_invalid_generation(self):
with self.assertRaisesRegex(
ValueError,
'generation is less than minimum_generation'
):
self._makeOne(generation=0, minimum_generation=1)

def test_ctor_invalid_min_generation(self):
with self.assertRaisesRegex(
ValueError,
'generations must be non-negative'
):
self._makeOne(generation=-1, minimum_generation=-1)

def test_ctor_invalid_generation_wo_package(self):
with self.assertRaisesRegex(
ValueError,
'A package name must be supplied'
):
self._makeOne(generation=1)


class TestEvolve(zope.component.testing.PlacelessSetup,
unittest.TestCase):

def test_error_on_install_propagates(self):
from zope import interface
from zope import component
from ZODB.MappingStorage import DB

from zope.generations.interfaces import IInstallableSchemaManager
from zope.generations.generations import evolve

class MyException(Exception):
pass

@interface.implementer(IInstallableSchemaManager)
class Manager(object):
generation = 0
def install(self, context):
raise MyException

component.provideUtility(Manager(), IInstallableSchemaManager)

db = DB()
self.addCleanup(db.close)

with self.assertRaises(MyException):
evolve(db)

def test_evolve_min_twice(self):
from zope import interface
from zope import component
from ZODB.MappingStorage import DB

from zope.generations.interfaces import ISchemaManager
from zope.generations.generations import evolve
from zope.generations.generations import EVOLVEMINIMUM


@interface.implementer(ISchemaManager)
class Manager(object):
generation = 1
minimum_generation = None
evolved = ()
def evolve(self, context, generation):
self.evolved += (generation,)

manager = Manager()
component.provideUtility(manager, ISchemaManager)

db = DB()
self.addCleanup(db.close)
evolve(db, EVOLVEMINIMUM)
# First time through we install
self.assertEqual(manager.evolved, ())

# Now bump the generation
manager.generation = 2
# And provide a minimum that's the same. We'll be called.
manager.minimum_generation = 2

evolve(db, EVOLVEMINIMUM)
self.assertEqual(manager.evolved, (2,))

# Now bump, but leave the min the same. We won't be called.
manager.generation = 3
evolve(db, EVOLVEMINIMUM)
self.assertEqual(manager.evolved, (2,))


class TestSubscribers(unittest.TestCase):

def setUp(self):
from ZODB.MappingStorage import DB
from zope.generations import generations
self.evolve = generations.evolve
generations.evolve = self.mock_evolve
self.db = DB()
self.expected_kind = None

def tearDown(self):
from zope.generations import generations
generations.evolve = self.evolve
self.db.close()

def mock_evolve(self, db, kind):
self.assertIs(db, self.db)
self.assertEqual(kind, self.expected_kind)

def test_evolveSubscriber(self):
from zope.generations.generations import EVOLVE
from zope.generations.generations import evolveSubscriber
self.expected_kind = EVOLVE

class Event(object):
def __init__(self, db):
self.database = db

evolveSubscriber(Event(self.db))

def test_evolveNotSubscriber(self):
from zope.generations.generations import EVOLVENOT
from zope.generations.generations import evolveNotSubscriber
self.expected_kind = EVOLVENOT

class Event(object):
def __init__(self, db):
self.database = db

evolveNotSubscriber(Event(self.db))


checker = renormalizing.RENormalizing([
# Python 3 unicode removed the "u".
(re.compile("u('.*?')"),
Expand All @@ -43,11 +190,12 @@ def tearDownREADME(test):


def test_suite():
suite = unittest.defaultTestLoader.loadTestsFromName(__name__)
flags = \
doctest.NORMALIZE_WHITESPACE | \
doctest.ELLIPSIS | \
doctest.IGNORE_EXCEPTION_DETAIL
return unittest.TestSuite((
docs = unittest.TestSuite((
doctest.DocFileSuite(
'README.rst',
setUp=zope.component.testing.setUp,
Expand All @@ -61,3 +209,5 @@ def test_suite():
doctest.DocTestSuite(
'zope.generations.utility'),
))
suite.addTest(docs)
return suite

0 comments on commit 7c747c5

Please sign in to comment.