]> git.decadent.org.uk Git - dak.git/commitdiff
daklib/ls.py: manage our own database session
authorAnsgar Burchardt <ansgar@debian.org>
Mon, 15 Jun 2015 18:53:02 +0000 (20:53 +0200)
committerAnsgar Burchardt <ansgar@debian.org>
Mon, 15 Jun 2015 18:53:02 +0000 (20:53 +0200)
session_wrapper gets confused by generators: let "f" be a generator
making use of a database session:

    def wrapped_f():
      session = DBConn().session()
      try:
        return f(session)
      finally:
        session.close()

    for item in wrapped_f():
      do_something(item)

will leak database sessions as the implementation of "f" will only be
invoked from the for-loop. However at this time the "finally" block
closing the session has already run. SQLAlchemy will helpfully reopen
the session, but it will not be closed in the end.

daklib/ls.py

index 0a1548f85a5ec133ce70d8b7b3361af2f4134289..1910963609cc3d9293c808945e4d90009f2c728f 100644 (file)
 import sqlalchemy.sql as sql
 import daklib.daksql as daksql
 
-from daklib.dbconn import DBConn, session_wrapper
+from daklib.dbconn import DBConn
 from collections import defaultdict
 
-
-@session_wrapper
 def list_packages(packages, suites=None, components=None, architectures=None, binary_types=None,
                   source_and_binary=False, regex=False,
-                  format=None, highest=None,
-                  session=None):
-    t = DBConn().view_package_list
-
-    comparison_operator = "~" if regex else "="
-
-    where = sql.false()
-    for package in packages:
-        where = where | t.c.package.op(comparison_operator)(package)
-        if source_and_binary:
-            where = where | t.c.source.op(comparison_operator)(package)
-
-    if suites is not None:
-        where = where & (t.c.suite.in_(suites) | t.c.codename.in_(suites))
-    if components is not None:
-        where = where & t.c.component.in_(components)
-    if architectures is not None:
-        where = where & t.c.architecture.in_(architectures)
-    if binary_types is not None:
-        where = where & t.c.type.in_(binary_types)
-
-    if format is None:
-        c_architectures = daksql.string_agg(t.c.architecture, ', ', order_by=[t.c.architecture_is_source.desc(), t.c.architecture])
-        query = sql.select([t.c.package, t.c.version, t.c.display_suite, c_architectures]) \
-                   .where(where) \
-                   .group_by(t.c.package, t.c.version, t.c.display_suite) \
-                   .order_by(t.c.package, t.c.version, t.c.display_suite)
-        result = session.execute(query).fetchall()
-
-        if len(result) == 0:
-            raise StopIteration
-
-        lengths = {
-            'package': max(10, max(len(row[t.c.package]) for row in result)),
-            'version': max(13, max(len(row[t.c.version]) for row in result)),
-            'suite':   max(10, max(len(row[t.c.display_suite]) for row in result))
-        }
-        format = "{0:{lengths[package]}} | {1:{lengths[version]}} | {2:{lengths[suite]}} | {3}"
-
-        for row in result:
-            yield format.format(row[t.c.package], row[t.c.version], row[t.c.display_suite], row[c_architectures], lengths=lengths)
-    elif format in ('control-suite', 'heidi'):
-        query = sql.select([t.c.package, t.c.version, t.c.architecture]).where(where)
-        result = session.execute(query)
-        for row in result:
-            yield "{0} {1} {2}".format(row[t.c.package], row[t.c.version], row[t.c.architecture])
-    elif format == "python":
-        c_architectures = daksql.string_agg(t.c.architecture, ',', order_by=[t.c.architecture_is_source.desc(), t.c.architecture])
-        query = sql.select([t.c.package,
-                            t.c.version,
-                            t.c.display_suite,
-                            c_architectures,
-                            t.c.source,
-                            t.c.source_version,
-                            t.c.component]) \
-            .where(where) \
-            .group_by(t.c.package,
-                      t.c.version,
-                      t.c.display_suite,
-                      t.c.source,
-                      t.c.component,
-                      t.c.source_version)
-        result = session.execute(query).fetchall()
-
-        if len(result) == 0:
-            raise StopIteration
-
-        val = lambda: defaultdict(val)
-        ret = val()
-        for row in result:
-            ret[row[t.c.package]] \
-               [row[t.c.display_suite]] \
-               [row[t.c.version]]={'component':      row[t.c.component],
-                                   'architectures':  row[c_architectures].split(','),
-                                   'source':         row[t.c.source],
-                                   'source_version': row[t.c.source_version]
-                               }
-
-        yield ret
-        return
-    else:
-        raise ValueError("Unknown output format requested.")
-
-    if highest is not None:
-        query = sql.select([t.c.package, sql.func.max(t.c.version)]).where(where) \
-                   .group_by(t.c.package).order_by(t.c.package)
-        result = session.execute(query)
-        yield ""
-        for row in result:
-            yield "{0} ({1} {2})".format(row[0], highest, row[1])
+                  format=None, highest=None):
+    session = DBConn().session()
+    try:
+        t = DBConn().view_package_list
+
+        comparison_operator = "~" if regex else "="
+
+        where = sql.false()
+        for package in packages:
+            where = where | t.c.package.op(comparison_operator)(package)
+            if source_and_binary:
+                where = where | t.c.source.op(comparison_operator)(package)
+
+        if suites is not None:
+            where = where & (t.c.suite.in_(suites) | t.c.codename.in_(suites))
+        if components is not None:
+            where = where & t.c.component.in_(components)
+        if architectures is not None:
+            where = where & t.c.architecture.in_(architectures)
+        if binary_types is not None:
+            where = where & t.c.type.in_(binary_types)
+
+        if format is None:
+            c_architectures = daksql.string_agg(t.c.architecture, ', ', order_by=[t.c.architecture_is_source.desc(), t.c.architecture])
+            query = sql.select([t.c.package, t.c.version, t.c.display_suite, c_architectures]) \
+                       .where(where) \
+                       .group_by(t.c.package, t.c.version, t.c.display_suite) \
+                       .order_by(t.c.package, t.c.version, t.c.display_suite)
+            result = session.execute(query).fetchall()
+
+            if len(result) == 0:
+                raise StopIteration
+
+            lengths = {
+                'package': max(10, max(len(row[t.c.package]) for row in result)),
+                'version': max(13, max(len(row[t.c.version]) for row in result)),
+                'suite':   max(10, max(len(row[t.c.display_suite]) for row in result))
+            }
+            format = "{0:{lengths[package]}} | {1:{lengths[version]}} | {2:{lengths[suite]}} | {3}"
+
+            for row in result:
+                yield format.format(row[t.c.package], row[t.c.version], row[t.c.display_suite], row[c_architectures], lengths=lengths)
+        elif format in ('control-suite', 'heidi'):
+            query = sql.select([t.c.package, t.c.version, t.c.architecture]).where(where)
+            result = session.execute(query)
+            for row in result:
+                yield "{0} {1} {2}".format(row[t.c.package], row[t.c.version], row[t.c.architecture])
+        elif format == "python":
+            c_architectures = daksql.string_agg(t.c.architecture, ',', order_by=[t.c.architecture_is_source.desc(), t.c.architecture])
+            query = sql.select([t.c.package,
+                                t.c.version,
+                                t.c.display_suite,
+                                c_architectures,
+                                t.c.source,
+                                t.c.source_version,
+                                t.c.component]) \
+                .where(where) \
+                .group_by(t.c.package,
+                          t.c.version,
+                          t.c.display_suite,
+                          t.c.source,
+                          t.c.component,
+                          t.c.source_version)
+            result = session.execute(query).fetchall()
+
+            if len(result) == 0:
+                raise StopIteration
+
+            val = lambda: defaultdict(val)
+            ret = val()
+            for row in result:
+                ret[row[t.c.package]] \
+                   [row[t.c.display_suite]] \
+                   [row[t.c.version]]={'component':      row[t.c.component],
+                                       'architectures':  row[c_architectures].split(','),
+                                       'source':         row[t.c.source],
+                                       'source_version': row[t.c.source_version]
+                                   }
+
+            yield ret
+            return
+        else:
+            raise ValueError("Unknown output format requested.")
+
+        if highest is not None:
+            query = sql.select([t.c.package, sql.func.max(t.c.version)]).where(where) \
+                       .group_by(t.c.package).order_by(t.c.package)
+            result = session.execute(query)
+            yield ""
+            for row in result:
+                yield "{0} ({1} {2})".format(row[0], highest, row[1])
+    finally:
+        session.close()