Commits

Mike Bayer  committed da3505e

looking good

  • Participants
  • Parent commits 110be5a

Comments (0)

Files changed (10)

         elif line.startswith("date:"):
             date, year = re.match(r'date:\s+(\w+ \w+ \d+) \d+:\d+:\d+ (\d+)', line).group(1, 2)
 
-            version = ".".join(re.findall(r"(\d+)", tag))
-            tags[version] = "%s %s" % (date, year)
+            digits = re.findall(r"(?:^|_)(\d+)", tag)
+            extra = re.match(".*?(beta\d|rc\d|[a-z]\d)$", tag)
+            if extra:
+                extra = extra.group(1)
+            else:
+                extra = ""
+
+            if len(digits) == 2 and extra:
+                versions = ".".join(digits) + extra, \
+                            ".".join(digits + ["0"]) + extra
+            else:
+                versions = (".".join(digits) + extra,)
+
+            for version in versions:
+                tags[version] = "%s %s" % (date, year)
     return tags
 
 def raw_blocks(fname):
                         (
                             ^\d+\.\d+ (?: \.\d+ )?
 
-                            (?:beta\d|rc\d|\w\d?)?
+                            (?:beta\d|rc\d|[a-z]\d?)?
                         )
 
                         (\(.*\))?$''', re.X)
 
     while lines:
         line = lines.pop(0)
-
         if state == normal:
             m = version_re.match(line)
             if m:
         elif state == in_bullet:
             another_bullet = bullet_re.match(line)
             version_number = version_re.match(line)
-            #import pdb
-            #pdb.set_trace()
+
             if \
                 line == "\n" or \
                 (
                 if current_output_file:
                     current_output_file.close()
                 current_major_version = major_version
-                current_output_file = open("source/changelog_%s.rst" % major_version.replace(".", ""), 'w')
+                cfile = "source/changelog_%s.rst" % major_version.replace(".", "")
+                print "writing %s" % cfile
+                current_output_file = open(cfile, 'w')
                 current_output_file.write("""
 ==============
 %s Changelog

File source/builder/changelog.py

 from docutils import nodes
 import textwrap
 import itertools
+import collections
 
 def _comma_list(text):
     return re.split(r"\s*,\s*", text.strip())
 
     sections = _comma_list("general, orm, orm declarative, orm querying, \
                 orm configuration, engine, sql, \
-                postgresql, mysql, sqlite, mssql, oracle, firebird")
+                schema, \
+                postgresql, mysql, sqlite, mssql, oracle, firebird, misc")
 
-    subsections = ["feature", "bug", "removed"]
+    subsections = ["feature", "bug", "moved", "changed", "removed", ""]
 
 
-    def run(self):
-        self.env.temp_data['ChangeLogDirective_changes'] = changes = []
-        content = _parse_content(self.content)
-        version = content.get('version', '')
+    def _organize_by_section(self, changes):
+        compound_sections = [(s, s.split(" ")) for s in
+                                self.sections if " " in s]
+
+        bysection = collections.defaultdict(list)
+        for rec in changes:
+            subsection = rec['tags'].intersection(self.subsections)
+            if subsection:
+                subsection = subsection.pop()
+            else:
+                subsection = ""
+
+            for compound, comp_words in compound_sections:
+                if rec['tags'].issuperset(comp_words):
+                    bysection[(compound, subsection)].append(rec)
+                    break
+
+            intersect = rec['tags'].intersection(self.sections)
+            if intersect:
+                bysection[(intersect.pop(), subsection)].append(rec)
+                continue
+
+            bysection[('misc', subsection)].append(rec)
+        return bysection
+
+    @classmethod
+    def changes(cls, env):
+        return env.temp_data['ChangeLogDirective_%s_changes' % cls.type_]
+
+    def _setup_run(self):
+        self.env.temp_data['ChangeLogDirective_%s_changes' % self.type_] = []
+        self._parsed_content = _parse_content(self.content)
 
         p = nodes.paragraph('', '',)
         self.state.nested_parse(self.content[1:], 0, p)
 
+    def run(self):
+        self._setup_run()
+        changes = self.changes(self.env)
         output = []
 
+        version = self._parsed_content.get('version', '')
         id_prefix = "%s-%s" % (self.type_, version)
+        topsection = self._run_top(id_prefix)
+        output.append(topsection)
+
+        bysection = self._organize_by_section(changes)
+
+        counter = itertools.count()
+
+        for section in self.sections:
+            sec, append_sec = self._section(section, id_prefix)
+
+            for cat in self.subsections:
+                for rec in bysection[(section, cat)]:
+                    rec["id"] = "%s-%s" % (id_prefix, next(counter))
+
+                    self._render_rec(rec, section, cat, append_sec)
+
+            if append_sec.children:
+                topsection.append(sec)
+
+        return output
+
+    def _section(self, section, id_prefix):
+        bullets = nodes.bullet_list()
+        sec = nodes.section('',
+                nodes.title(section, section),
+                bullets,
+                ids=["%s-%s" % (id_prefix, section.replace(" ", "-"))]
+        )
+        return sec, bullets
+
+    def _run_top(self, id_prefix):
+        version = self._parsed_content.get('version', '')
         topsection = nodes.section('',
                 nodes.title(version, version),
                 ids=[id_prefix]
             )
-        if "released" in content:
-            topsection.append(nodes.Text("Released: %s" % content['released']))
+
+        if "released" in self._parsed_content:
+            topsection.append(nodes.Text("Released: %s" % self._parsed_content['released']))
         else:
             topsection.append(nodes.Text("no release date"))
-        output.append(topsection)
+        return topsection
 
-        all_section_tags = set()
-        for rec in changes:
-            all_section_tags.update(rec['tags'])
+    def _render_rec(self, rec, section, cat, append_sec):
+        para = rec['node'].deepcopy()
+        insert_ticket = nodes.paragraph('')
+        para.append(insert_ticket)
 
-        counter = itertools.count()
-
-        for section in list(self.sections) + list(all_section_tags.difference(self.sections)):
-            sec_tags = set(section.split(" "))
-            bullets = nodes.bullet_list()
-            sec = nodes.section('',
-                    nodes.title(section, section),
-                    bullets,
-                    ids=["%s-%s" % (id_prefix, section.replace(" ", "-"))]
+        for i, ticket in enumerate(rec['tickets']):
+            if i > 0:
+                insert_ticket.append(nodes.Text(", ", ", "))
+            else:
+                insert_ticket.append(nodes.Text(" ", " "))
+            insert_ticket.append(
+                nodes.reference('', '',
+                    nodes.Text("#%s" % ticket, "#%s" % ticket),
+                    refuri=_ticketurl(ticket)
+                )
             )
 
-            for cat in self.subsections + [""]:
-                for rec in changes:
-                    if not rec.get("emitted") and rec['type'] == self.type_ and \
-                        (
-                            rec['tags'].intersection(all_section_tags) == sec_tags
-                        ) and \
-                        (
-                            cat in rec['tags'] or
-                            not cat and not rec['tags'].intersection(self.subsections)
-                        ):
+        if cat or rec['tags']:
+            #tag_node = nodes.strong('',
+            #            "[" + cat + "] "
+            #        )
+            tag_node = nodes.strong('',
+                        " ".join("[%s]" % t for t
+                            in
+                                [cat] +
+                                list(rec['tags'].difference([cat]))
+                            if t
+                        ) + " "
+                    )
+            para.children[0].insert(0, tag_node)
 
-                        rec["emitted"] = True
-                        rec["id"] = "%s-%s" % (id_prefix, next(counter))
-                        para = rec['node'].deepcopy()
-
-                        insert_ticket = nodes.paragraph('')
-                        para.append(insert_ticket)
-
-                        for i, ticket in enumerate(rec['tickets']):
-                            if i > 0:
-                                insert_ticket.append(nodes.Text(", ", ", "))
-                            else:
-                                insert_ticket.append(nodes.Text(" ", " "))
-                            insert_ticket.append(
-                                nodes.reference('', '',
-                                    nodes.Text("#%s" % ticket, "#%s" % ticket),
-                                    refuri=_ticketurl(ticket)
-                                )
-                            )
-
-                        if cat or rec['tags']:
-                            #tag_node = nodes.strong('',
-                            #            "[" + cat + "] "
-                            #        )
-                            tag_node = nodes.strong('',
-                                        "[" + ", ".join(rec['tags']) + "] "
-                                    )
-                            para.children[0].insert(0, tag_node)
-
-                        bullets.append(
-                            nodes.list_item('',
-                                nodes.target('', '', ids=[rec['id']]),
-                                para
-                            )
-                        )
-            if bullets.children:
-                topsection.append(sec)
-
-        return output
+        append_sec.append(
+            nodes.list_item('',
+                nodes.target('', '', ids=[rec['id']]),
+                para
+            )
+        )
 
 
 class MigrationLogDirective(ChangeLogDirective):
                 orm configuration, engine, sql, \
                 postgresql, mysql, sqlite")
 
-    def run(self):
-        self.env.temp_data['ChangeLogDirective_changes'] = changes = []
-
-        content = _parse_content(self.content)
-        version = content.get('version', '')
-
-        p = nodes.paragraph('', '',)
-        self.state.nested_parse(self.content[1:], 0, p)
-
-        output = []
-
-        id_prefix = "%s-%s" % (self.type_, version)
-
+    def _run_top(self, id_prefix):
+        version = self._parsed_content.get('version', '')
         title = "What's new in %s?" % version
         topsection = nodes.section('',
                 nodes.title(title, title),
                 ids=[id_prefix]
             )
-        if "released" in content:
-            topsection.append(nodes.Text("Released: %s" % content['released']))
+        if "released" in self._parsed_content:
+            topsection.append(nodes.Text("Released: %s" % self._parsed_content['released']))
+        return topsection
 
-        output.append(topsection)
+    def _section(self, section, id_prefix):
+        sec = nodes.section('',
+                nodes.title(section, section),
+                ids=["%s-%s" % (id_prefix, section.replace(" ", "-"))]
+        )
+        return sec, sec
 
-        counter = itertools.count()
+    def _render_rec(self, rec, section, cat, append_sec):
+        para = rec['node'].deepcopy()
 
-        for section in self.sections:
-            sec = nodes.section('',
-                    nodes.title(section, section),
-                    ids=["%s-%s" % (id_prefix, section.replace(" ", "-"))]
+        insert_ticket = nodes.paragraph('')
+        para.append(insert_ticket)
+
+        for i, ticket in enumerate(rec['tickets']):
+            if i > 0:
+                insert_ticket.append(nodes.Text(", ", ", "))
+            else:
+                insert_ticket.append(nodes.Text(" ", " "))
+            insert_ticket.append(
+                nodes.reference('', '',
+                    nodes.Text("#%s" % ticket, "#%s" % ticket),
+                    refuri=_ticketurl(ticket)
+                )
             )
 
-            for cat in self.subsections + [""]:
-                for rec in changes:
-                    if not rec.get("emitted") and rec['type'] == self.type_ and \
-                        (
-                            section in rec['tags']
-                        ) and \
-                        (
-                            cat in rec['tags'] or
-                            not cat and not rec['tags'].intersection(self.subsections)
-                        ):
+        append_sec.append(
+            nodes.section('',
+                nodes.title(rec['title'], rec['title']),
+                para,
+                ids=[rec['id']]
+            )
+        )
 
-                        para = rec['node'].deepcopy()
-                        rec["emitted"] = True
-                        rec["id"] = "%s-%s" % (id_prefix, next(counter))
 
-                        insert_ticket = nodes.paragraph('')
-                        para.append(insert_ticket)
-
-                        for i, ticket in enumerate(rec['tickets']):
-                            if i > 0:
-                                insert_ticket.append(nodes.Text(", ", ", "))
-                            else:
-                                insert_ticket.append(nodes.Text(" ", " "))
-                            insert_ticket.append(
-                                nodes.reference('', '',
-                                    nodes.Text("#%s" % ticket, "#%s" % ticket),
-                                    refuri=_ticketurl(ticket)
-                                )
-                            )
-
-
-                        sec.append(
-                            nodes.section('',
-                                nodes.title(rec['title'], rec['title']),
-                                para,
-                                ids=[rec['id']]
-                            )
-                        )
-            if sec.children:
-                topsection.append(sec)
-
-        return output
 
 class ChangeDirective(EnvDirective, Directive):
     has_content = True
             rec['tags'].add("orm")
 
         self.state.nested_parse(content['text'], 0, p)
-        self.env.temp_data['ChangeLogDirective_changes'].append(rec)
+        self.parent_cls.changes(self.env).append(rec)
 
         return []
 

File source/changelog_01.rst

     :released: Fri May 05 2006
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 
 
       some fixes to topological sort algorithm
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 
 
       added DISTINCT ON support to Postgres (just supply distinct=[col1,col2..])
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 
 
       added __mod__ (% operator) to sql expressions
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 
 
       "order_by" mapper property inherited from inheriting mapper
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 
 
       fix to column type used when mapper UPDATES/DELETEs
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 
 
       with convert_unicode=True, reflection was failing, has been fixed
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 
 
       types types types!  still werent working....have to use TypeDecorator again :(
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 
 
       mysql binary type converts array output to buffer, fixes PickleType
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 
 
       fixed the attributes.py memory leak once and for all
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 
 
       unittests are qualified based on the databases that support each one
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 
 
       fixed bug where column defaults would clobber VALUES clause of insert objects
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 
 
       fixed bug where table def w/ schema name would force engine connection
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 
 
       fix for parenthesis to work correctly with subqueries in INSERT/UPDATE
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 
 
       HistoryArraySet gets extend() method
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 
 
       fixed lazyload support for other comparison operators besides =
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 
 
       lazyload fix where two comparisons in the join condition point to the
       samem column
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 
 
       added "construct_new" flag to mapper, will use __new__ to create instances
       instead of __init__ (standard in 0.2)
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 
 
       added selectresults.py to SVN, missed it last time
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 
 
       tweak to allow a many-to-many relationship from a table to itself via
       an association table
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 
 
       small fix to "translate_row" function used by polymorphic example
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 
 
       create_engine uses cgi.parse_qsl to read query string (out the window in 0.2)
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 
 
       tweaks to CAST operator
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 
 
       fixed function names LOCAL_TIME/LOCAL_TIMESTAMP -> LOCALTIME/LOCALTIMESTAMP
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 
 
       fixed order of ORDER BY/HAVING in compile
     :released: Wed Apr 12 2006
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 
 
       support for MS-SQL added courtesy Rick Morrison, Runar Petursson
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 
 
       the latest SQLSoup from J. Ellis
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 
 
       ActiveMapper has preliminary support for inheritance (Jeff Watkins)
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 
 
       added a "mods" system which allows pluggable modules that modify/augment
       core functionality, using the function "install_mods(*modnames)".
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 
 
       added the first "mod", SelectResults, which modifies mapper selects to
       (Jonas Borgstr?
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 
 
       factored out querying capabilities of Mapper into a separate Query object
       and makes other things possible.
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 
 
       objectstore/Session refactored, the official way to save objects is now
       the 0.2 series.
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 
 
       types system is bound to an engine at query compile time, not schema
       construction time.  this simplifies the types system as well as the ProxyEngine.
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 
 
       added 'version_id' keyword argument to mapper. this keyword should reference a
       value received is not the expected count.
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 
 
       added 'entity_name' keyword argument to mapper. a mapper is now associated
       map for an otherwise equilvalent object.
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 
 
       overhaul to the attributes system. code has been clarified, and also fixed to
       support proper polymorphic behavior on object attributes.
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 
 
       added "for_update" flag to Select objects
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 
 
       some fixes for backrefs
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 
 
       fix for postgres1 DateTime type
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 
 
       documentation pages mostly switched over to Markdown syntax
     :released: Mon Mar 27 2006
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 
 
       added SQLSession concept to SQLEngine. this object keeps track of retrieving a
       come later regarding SQLSession.
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 
 
       added nest_on argument to objectstore.Session. This is a single SQLEngine or
       engine.
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 
 
       factored apart objectstore/unitofwork to separate "Session scoping" from
       "uow commit heavy lifting"
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 
 
       added populate_instance() method to MapperExtension. allows an extension to
       with this.
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 
 
       fixed Oracle8-compatibility "use_ansi" flag which converts JOINs to
       comparisons with the = and (+) operators, passes basic unittests
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 
 
       tweaks to Oracle LIMIT/OFFSET support
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 
 
       Oracle reflection uses ALL_** views instead of USER_** to get larger
       list of stuff to reflect from
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 105
 
       fixes to Oracle foreign key reflection
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 
 
       objectstore.commit(obj1, obj2,...) adds an extra step to seek out private
       commit
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 
 
       lots and lots of fixes to mappers which use inheritance, strengthened the
       to work with lazy/eager loading.
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 
 
       added support for mappers to inherit from others based on the same table,
       just specify the same table as that of both parent/child mapper.
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 
 
       some minor speed improvements to the attributes system with regards to
       instantiating and populating new objects.
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 
 
       fixed MySQL binary unit test
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 
 
       INSERTs can receive clause elements as VALUES arguments, not just literal
       values
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 
 
       support for calling multi-tokened functions, i.e. schema.mypkg.func()
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 
 
       added J. Ellis' SQLSoup module to extensions package
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 
 
       added "polymorphic" examples illustrating methods to load multiple object types
       small improvements to mapper, UNION construct to help the examples along
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 
 
       improvements/fixes to session.refresh()/session.expire() (which may have
       been called "invalidate" earlier..)
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 
 
       added session.expunge() which totally removes an object from the current
       session
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 
 
       added *args, **kwargs pass-thru to engine.transaction(func) allowing easier
       creation of transactionalizing decorator functions
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 
 
       added iterator interface to ResultProxy:  "for row in result:..."
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 
 
       added assertion to tx = session.begin(); tx.rollback(); tx.begin(), i.e. cant
       use it after a rollback()
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 
 
       added date conversion on bind parameter fix to SQLite enabling dates to
       work with pysqlite1
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 116
 
       improvements to subqueries to more intelligently construct their FROM
       clauses
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 
 
       added PickleType to types.
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 
 
       fixed two bugs with column labels with regards to bind parameters: bind param
       against a column named the same as "tablename_colname" added
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 
 
       major overhaul to unit of work documentation, other documentation sections.
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 
 
       fixed attributes bug where if an object is committed, its lazy-loaded list got
       blown away if it hadnt been loaded
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 
 
       added unique_connection() method to engine, connection pool to return a
       transaction
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 
 
       added invalidate() function to pooled connection.  will remove the connection
       though.
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 
 
       added distinct() function to column elements so you can do
       func.count(mycol.distinct())
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 
 
       added "always_refresh" flag to Mapper, creates a mapper that will always
     :released: Mon Mar 13 2006
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 
 
       create_engine() now uses genericized parameters; host/hostname,
        engine URIs much more "universal"
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 
 
       added support for SELECT statements embedded into a column clause, using the
       flag "scalar=True"
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 
 
       another overhaul to EagerLoading when used in conjunction with mappers that
       this can be overridden by using custom primary/secondary joins.
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 
 
       added J.Ellis patch to mapper.py so that selectone() throws an exception
       exception. also adds selectfirst_by (synonymous with get_by) and selectone_by
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 
 
       added onupdate parameter to Column, will exec SQL/python upon an update
       statement.Also adds "for_update=True" to all DefaultGenerator subclasses
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 
 
       added support for Oracle table reflection contributed by Andrija Zaric;
       still some bugs to work out regarding composite primary keys/dictionary selection
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 
 
       checked in an initial Firebird module, awaiting testing.
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 
 
       added sql.ClauseParameters dictionary object as the result for
       that the original values are easier to access
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 
 
       more docs for indexes, column defaults, connection pooling, engine construction
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 
 
       overhaul to the construction of the types system. uses a simpler inheritance
       for TypeDecorator.
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 
 
       added "convert_unicode=False" parameter to SQLEngine, will cause all String
       types to perform unicode encoding/decoding (makes Strings act like Unicodes)
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 
 
       added 'encoding="utf8"' parameter to engine.  the given encoding will be
       when convert_unicode=True.
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 
 
       improved support for mapping against UNIONs, added polymorph.py example
       to illustrate multi-class mapping against a UNION
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 
 
       fix to SQLite LIMIT/OFFSET syntax
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 
 
       fix to Oracle LIMIT syntax
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 
 
       added backref() function, allows backreferences to have keyword arguments
       that will be passed to the backref.
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 
 
       Sequences and ColumnDefault objects can do execute()/scalar() standalone
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 
 
       SQL functions (i.e. func.foo()) can do execute()/scalar() standalone
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 
 
       fix to SQL functions so that the ANSI-standard functions, i.e. current_timestamp
       etc., do not specify parenthesis.  all other functions do.
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 
 
       added settattr_clean and append_clean to SmartProperty, which set
       myclass.prop1.setattr_clean(myobject, 'hi')
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 
 
       improved support to column defaults when used by mappers; mappers will pull
       populate the object.
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 
 
       added 'get_session().invalidate(*obj)' method to objectstore, instances will
       refresh() themselves upon the next attribute access.
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 
 
       improvements to SQL func calls including an "engine" keyword argument so
       SQLEngine
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 
 
       fix to MySQL4 custom table engines, i.e. TYPE instead of ENGINE
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 
 
       slightly enhanced logging, includes timestamps and a somewhat configurable
       formatting system, in lieu of a full-blown logging system
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 
 
       improvements to the ActiveMapper class from the TG gang, including
       many-to-many relationships
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 
 
       added Double and TinyInt support to mysql
     :released: Thu Mar 02 2006
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 
 
       completed "post_update" feature, will add a second update statement before
       on each other
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 
 
       completed mapper.using(session) function, localized per-object Session
       user-defined Session
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 
 
       fix to Oracle "row_number over" clause with multiple tables
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 
 
       mapper.get() was not selecting multiple-keyed objects if the mapper's table was a join,
       such as in an inheritance relationship, this is fixed.
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 
 
       overhaul to sql/schema packages so that the sql package can run all on its own,
       removes the entire getattr() behavior that plagued 0.1.1.
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 
 
       refactoring of how the mapper "synchronizes" data between two objects into a
       synchronize between inherited and inheriting mappers.
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 
 
       made objectstore "check for out-of-identitymap" more aggressive, will perform the
       check when object attributes are modified or the object is deleted
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 
 
       Index object fully implemented, can be constructed standalone, or via
       "index" and "unique" arguments on Columns.
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 
 
       added "convert_unicode" flag to SQLEngine, will treat all String/CHAR types
       result set side.
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 
 
       postgres maintains a list of ANSI functions that must have no parenthesis so
       function calls with no arguments work consistently
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 
 
       tables can be created with no engine specified.  this will default their engine
       be connected via the function "global_connect".
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 
 
       added "refresh(*obj)" method to objectstore / Session to reload the attributes of
     :released: Fri Feb 24 2006
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 
 
       fixed a recursive call in schema that was somehow running 994 times then returning
     :released: Thu Feb 23 2006
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 
 
       small fix to Function class so that expressions with a func.foo() use the type of the
       other side which is more of a moving target (changeset 1020).
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 
 
       creating self-referring mappers with backrefs slightly easier (but still not that easy -
       changeset 1019)
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 
 
       fixes to one-to-one mappings (changeset 1015)
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 
 
       psycopg1 date/time issue with None fixed (changeset 1005)
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 
 
       two issues related to postgres, which doesnt want to give you the "lastrowid"
       also will not happen unless someone (usually the ORM) explicitly asks for it.
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 
 
       fixed a glitch with engine.execute_compiled where it was making a second
       ResultProxy that just got thrown away.
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 
 
       began to implement newer logic in object properities.  you can now say
       attribute, i.e. myclass.mapper.props['attr']
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 
 
       eager loading has been internally overhauled to use aliases at all times.  more
       "use aliases"-type instructions.  EagerLoader code is also much simpler now.
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 
 
       a new somewhat experimental flag "use_update" added to relations, indicates that
       primary INSERT or before a primary DELETE.  handles circular row dependencies.
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 
 
       added exceptions module, all raised exceptions (except for some
       KeyError/AttributeError exceptions) descend from these classes.
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 
 
       fix to date types with MySQL, returned timedelta converted to datetime.time
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 
 
       two-phase objectstore.commit operations (i.e. begin/commit) now return a
       transactional object (SessionTrans), to more clearly indicate transaction boundaries.
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 
 
       Index object with create/drop support added to schema
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 
 
       fix to postgres, where it will explicitly pre-execute a PassiveDefault on a table
       back from postgres" issue
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 
 
       change to information_schema query that gets back postgres table defs, now
       uses explicit JOIN keyword, since one user had faster performance with 8.1
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 
 
       fix to engine.process_defaults so it works correctly with a table that has
       different column name/column keys (changset 982)
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 
 
       a column can only be attached to one table - this is now asserted
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 
 
       postgres time types descend from Time type
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 
 
       fix to alltests so that it runs types test (now named testtypes)
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 
 
       fix to Join object so that it correctly exports its foreign keys (cs 973)
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 
 
       creating relationships against mappers that use inheritance fixed (cs 973)

File source/changelog_02.rst

     :released: Tue Sep 05 2006
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 
 
       cleanup on connection methods + documentation.  custom DBAPI
       function to 'create_engine'.
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 274
 
       added "recycle" argument to Pool, is "pool_recycle" on create_engine,
       stale connections
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 121
 
       changed "invalidate" semantics with pooled connection; will
       the connecting application
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 
 
       eesh !  the tutorial doctest was broken for quite some time.
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 
 
       add_property() method on mapper does a "compile all mappers"
       (as it did in the case of the tutorial !)
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 277
 
       check for pg sequence already existing before create
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 
 
       if a contextual session is established via MapperExtension.get_session
       persistent with a session already.
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 
 
       lazy loads will not fire off for an object that does not have a
       see http://www.sqlalchemy.org/trac/wiki/WhyDontForeignKeysLoadData)
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 
 
       unit-of-work does a better check for "orphaned" objects that are
       parent isnt available to cascade from.
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 
 
       mappers can tell if one of their objects is an "orphan" based
       when objects are attached and detached from each other.
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 
 
       it is now invalid to declare a self-referential relationship with
       to save)
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 
 
       improved the check for objects being part of a session when the
       unit of work seeks to flush() them as part of a relationship..
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 280
 
       statement execution supports using the same BindParam
       parameters.  nice job by Bill Noon figuring out the basic idea.
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 60, 71
 
       postgres reflection moved to use pg_schema tables, can be overridden
       with use_information_schema=True argument to create_engine.
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 155
 
       added case_sensitive argument to MetaData, Table, Column, determines
       work with
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 
 
       unit tests updated to run without any pysqlite installed; pool
       test uses a mock DBAPI
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 281
 
       urls support escaped characters in passwords
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 
 
       added limit/offset to UNION queries (though not yet in oracle)
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 
 
       added "timezone=True" flag to DateTime and Time types.  postgres
       against datetimes that dont).
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 287
 
       fix to using query.count() with distinct, **kwargs with SelectResults
       count()
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 289
 
       deregister Table from MetaData when autoload fails;
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 293
 
       import of py2.5s sqlite3
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 296
 
       unicode fix for startswith()/endswith()
     :released: Sat Aug 12 2006
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 
 
       quoting facilities set up so that database-specific quoting can be
       Aaron Spike for his excellent efforts.
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 
 
       assignmapper was setting is_primary=True, causing all sorts of mayhem
       by not raising an error when redundant mappers were set up, fixed
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 
 
       added allow_null_pks option to Mapper, allows rows where some
       primary key columns are null (i.e. when mapping to outer joins etc)
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 
 
       modifcation to unitofwork to not maintain ordering within the
       sort) dont have to worry about maintaining order (which they werent anyway)
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 
 
       fixed reflection of foreign keys to autoload the referenced table
       if it was not loaded already
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 256
 
       - pass URL query string arguments to connect() function
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 257
 
       - oracle boolean type
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 
 
       custom primary/secondary join conditions in a relation *will* be propagated
       to backrefs by default.  specifying a backref() will override this behavior.
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 
 
       better check for ambiguous join conditions in sql.Join; propagates to a
       the join condition can't be reasonably determined.
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 
 
       sqlite creates ForeignKeyConstraint objects properly upon table
       reflection.
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 224
 
       adjustments to pool stemming from changes made for.
       succeeded.  added a test script to attempt testing this.
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 
 
       fixed mysql reflection of default values to be PassiveDefault
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 263, 264
 
       added reflected 'tinyint', 'mediumint' type to MS-SQL.
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 
 
       SingletonThreadPool has a size and does a cleanup pass, so that
       for sqlite applications that dispose of threads en masse)
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 267, 265
 
       fixed small pickle bug(s) with lazy loaders
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 
 
       fixed possible error in mysql reflection where certain versions
       return an array instead of string for SHOW CREATE TABLE call
 
     .. change::
-        :tags: changeset:1770, ORM:
+        :tags: ORM, changeset:1770
         :tickets: 
 
       fix to lazy loads when mapping to joins
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 
 
       all create()/drop() calls have a keyword argument of "connectable".
       "engine" is deprecated.
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 
 
       fixed ms-sql connect() to work with adodbapi
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 
 
       added "nowait" flag to Select()
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 271
 
       inheritance check uses issubclass() instead of direct __mro__ check
       flexibly correspond to class inheritance
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 252
 
       SelectResults will use a subselect, when calling an aggregate (i.e.
       max, min, etc.) on a SelectResults that has an ORDER BY clause
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 269
 
       fixes to types so that database-specific types more easily used;
       fixes to mysql text types to work with this methodology
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 
 
       some fixes to sqlite date type organization
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 263
 
       added MSTinyInteger to MS-SQL
     :released: Thu Jul 20 2006
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 76
 
       big overhaul to schema to allow truly composite primary and foreign
       and reflection is now more table oriented rather than column oriented.
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 
 
       overhaul to MapperExtension calling scheme, wasnt working very well
       previously
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 
 
       tweaks to ActiveMapper, supports self-referential relationships
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 
 
       slight rearrangement to objectstore (in activemapper/threadlocal)
       of subclassed directly.
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 
 
       activemapper will use threadlocal's objectstore if the mod is
       activated when activemapper is imported
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 
 
       small fix to URL regexp to allow filenames with '@' in them
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 
 
       fixes to Session expunge/update/etc...needs more cleanup.
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 
 
       select_table mappers *still* werent always compiling
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 
 
       fixed up Boolean datatype
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 
 
       added count()/count_by() to list of methods proxied by assignmapper;
       this also adds them to activemapper
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 
 
       connection exceptions wrapped in DBAPIError
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 
 
       ActiveMapper now supports autoloading column definitions from the
       any relationships.
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 
 
       deferred column load could screw up the connection status in
       a flush() under some circumstances, this was fixed
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 
 
       expunge() was not working with cascade, fixed.
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 
 
       potential endless loop in cascading operations fixed.
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 
 
       added "synonym()" function, applied to properties to have a
       and allowing the original propname to be accessible in select_by().
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 
 
       fix to typing in clause construction which specifically helps
       its type to proxy columns)
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 
 
       mapper compilation work ongoing, someday it'll work....moved
       aware of their "inherited" status if so.
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 
 
       eager loads explicitly disallowed on self-referential relationships, or
       relationships to an inheriting mapper (which is also self-referential)
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 244
 
       reduced bind param size in query._get to appease the picky oracle
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 234
 
       added 'checkfirst' argument to table.create()/table.drop(), as
       well as table.exists()
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 245
 
       some other ongoing fixes to inheritance
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 
 
       attribute/backref/orphan/history-tracking tweaks as usual...
     :released: Sat Jul 08 2006
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 
 
       fixed endless loop bug in select_by(), if the traversal hit
       two mappers that referenced each other
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 
 
       upgraded all unittests to insert './lib/' into sys.path,
       working around new setuptools PYTHONPATH-killing behavior
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 
 
       further fixes with attributes/dependencies/etc....
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 
 
       improved error handling for when DynamicMetaData is not connected
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 
 
       MS-SQL support largely working (tested with pymssql)
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 
 
       ordering of UPDATE and DELETE statements within groups is now
       in order of primary key values, for more deterministic ordering
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 
 
       after_insert/delete/update mapper extensions now called per object,
       not per-object-per-table
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 
 
       further fixes/refactorings to mapper compilation
     :released: Tue Jun 27 2006
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 
 
       try/except when the mapper sets init.__name__ on a mapped class,
       supports python 2.3
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 
 
       fixed bug where threadlocal engine would still autocommit
       despite a transaction in progress
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 
 
       lazy load and deferred load operations require the parent object
       would just return a blank list or None, it now raises an exception.
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 
 
       Session.update() is slightly more lenient if the session to which
       the previous Session.
 
     .. change::
-        :tags: ORM:
+        :tags: ORM
         :tickets: 
 
       fixes to mapper compilation, checking for more error conditions