From 308b32848c6ea7cf3f3de384b3ef019436d7e257 Mon Sep 17 00:00:00 2001 From: Christoph Zwerschke Date: Sat, 26 Sep 2020 14:17:11 +0200 Subject: [PATCH 01/90] Remove Webware Examples, move Tests and Docs up --- DBUtils/Examples/DBUtilsExample.py | 455 ------------------ DBUtils/Examples/Main.py | 21 - DBUtils/Examples/__init__.py | 1 - {DBUtils/Docs => Docs}/Doc.css | 0 {DBUtils/Docs => Docs}/DocUtils.css | 0 {DBUtils/Docs => Docs}/RelNotes-0.8.1.html | 0 {DBUtils/Docs => Docs}/RelNotes-0.9.1.html | 0 {DBUtils/Docs => Docs}/RelNotes-0.9.2.html | 0 {DBUtils/Docs => Docs}/RelNotes-0.9.3.html | 0 {DBUtils/Docs => Docs}/RelNotes-0.9.4.html | 0 {DBUtils/Docs => Docs}/RelNotes-1.0.html | 0 {DBUtils/Docs => Docs}/RelNotes-1.1.1.html | 0 {DBUtils/Docs => Docs}/RelNotes-1.1.html | 0 {DBUtils/Docs => Docs}/RelNotes-1.2.html | 0 {DBUtils/Docs => Docs}/RelNotes-1.3.html | 0 {DBUtils/Docs => Docs}/RelNotes-1.4.html | 0 {DBUtils/Docs => Docs}/UsersGuide.de.html | 0 {DBUtils/Docs => Docs}/UsersGuide.de.rst | 0 {DBUtils/Docs => Docs}/UsersGuide.html | 0 {DBUtils/Docs => Docs}/UsersGuide.rst | 0 {DBUtils/Docs => Docs}/dbdep.gif | Bin {DBUtils/Docs => Docs}/persist.gif | Bin {DBUtils/Docs => Docs}/pgdep.gif | Bin {DBUtils/Docs => Docs}/pool.gif | Bin {DBUtils/Tests => Tests}/TestPersistentDB.py | 0 {DBUtils/Tests => Tests}/TestPersistentPg.py | 0 {DBUtils/Tests => Tests}/TestPooledDB.py | 0 {DBUtils/Tests => Tests}/TestPooledPg.py | 0 .../Tests => Tests}/TestSimplePooledDB.py | 0 .../Tests => Tests}/TestSimplePooledPg.py | 0 {DBUtils/Tests => Tests}/TestSteadyDB.py | 0 {DBUtils/Tests => Tests}/TestSteadyPg.py | 0 .../Tests => Tests}/TestThreadingLocal.py | 0 {DBUtils/Tests => Tests}/__init__.py | 0 {DBUtils/Tests => Tests}/mock_db.py | 0 {DBUtils/Tests => Tests}/mock_pg.py | 0 36 files changed, 477 deletions(-) delete mode 100644 DBUtils/Examples/DBUtilsExample.py delete mode 100644 DBUtils/Examples/Main.py delete mode 100644 DBUtils/Examples/__init__.py rename {DBUtils/Docs => Docs}/Doc.css (100%) rename {DBUtils/Docs => Docs}/DocUtils.css (100%) rename {DBUtils/Docs => Docs}/RelNotes-0.8.1.html (100%) rename {DBUtils/Docs => Docs}/RelNotes-0.9.1.html (100%) rename {DBUtils/Docs => Docs}/RelNotes-0.9.2.html (100%) rename {DBUtils/Docs => Docs}/RelNotes-0.9.3.html (100%) rename {DBUtils/Docs => Docs}/RelNotes-0.9.4.html (100%) rename {DBUtils/Docs => Docs}/RelNotes-1.0.html (100%) rename {DBUtils/Docs => Docs}/RelNotes-1.1.1.html (100%) rename {DBUtils/Docs => Docs}/RelNotes-1.1.html (100%) rename {DBUtils/Docs => Docs}/RelNotes-1.2.html (100%) rename {DBUtils/Docs => Docs}/RelNotes-1.3.html (100%) rename {DBUtils/Docs => Docs}/RelNotes-1.4.html (100%) rename {DBUtils/Docs => Docs}/UsersGuide.de.html (100%) rename {DBUtils/Docs => Docs}/UsersGuide.de.rst (100%) rename {DBUtils/Docs => Docs}/UsersGuide.html (100%) rename {DBUtils/Docs => Docs}/UsersGuide.rst (100%) rename {DBUtils/Docs => Docs}/dbdep.gif (100%) rename {DBUtils/Docs => Docs}/persist.gif (100%) rename {DBUtils/Docs => Docs}/pgdep.gif (100%) rename {DBUtils/Docs => Docs}/pool.gif (100%) rename {DBUtils/Tests => Tests}/TestPersistentDB.py (100%) rename {DBUtils/Tests => Tests}/TestPersistentPg.py (100%) rename {DBUtils/Tests => Tests}/TestPooledDB.py (100%) rename {DBUtils/Tests => Tests}/TestPooledPg.py (100%) rename {DBUtils/Tests => Tests}/TestSimplePooledDB.py (100%) rename {DBUtils/Tests => Tests}/TestSimplePooledPg.py (100%) rename {DBUtils/Tests => Tests}/TestSteadyDB.py (100%) rename {DBUtils/Tests => Tests}/TestSteadyPg.py (100%) rename {DBUtils/Tests => Tests}/TestThreadingLocal.py (100%) rename {DBUtils/Tests => Tests}/__init__.py (100%) rename {DBUtils/Tests => Tests}/mock_db.py (100%) rename {DBUtils/Tests => Tests}/mock_pg.py (100%) diff --git a/DBUtils/Examples/DBUtilsExample.py b/DBUtils/Examples/DBUtilsExample.py deleted file mode 100644 index 8e40172..0000000 --- a/DBUtils/Examples/DBUtilsExample.py +++ /dev/null @@ -1,455 +0,0 @@ - -from MiscUtils.Configurable import Configurable -from WebKit.Examples.ExamplePage import ExamplePage - - -class DBConfig(Configurable): - """Database configuration.""" - - def defaultConfig(self): - return { - 'dbapi': 'pg', - 'database': 'demo', - 'user': 'demo', - 'password': 'demo', - 'mincached': 5, - 'maxcached': 25 - } - - def configFilename(self): - return 'Configs/Database.config' - - -# the database tables used in this example: -tables = ( - '''seminars ( - id varchar(4) primary key, - title varchar(64) unique not null, - cost money, - places_left smallint)''', - '''attendees ( - name varchar(64) not null, - seminar varchar(4), - paid boolean, - primary key(name, seminar), - foreign key (seminar) references seminars(id) on delete cascade)''') - - -class DBUtilsExample(ExamplePage): - """Example page for the DBUtils package.""" - - # Initialize the database class once when this class is loaded: - config = DBConfig().config() - if config.get('maxcached', None) is None: - dbmod_name = 'Persistent' - else: - dbmod_name = 'Pooled' - dbapi_name = config.pop('dbapi', 'pg') - if dbapi_name == 'pg': # use the PyGreSQL classic DB API - dbmod_name += 'Pg' - if 'database' in config: - config['dbname'] = config['database'] - del config['database'] - if 'password' in config: - config['passwd'] = config['password'] - del config['password'] - else: # use a DB-API 2 compliant module - dbmod_name += 'DB' - dbapi = dbmod = dbclass = dbstatus = None - try: - dbapi = __import__(dbapi_name) - try: - dbmod = getattr(__import__('DBUtils.' + dbmod_name), dbmod_name) - try: - if dbapi_name != 'pg': - config['creator'] = dbapi - dbclass = getattr(dbmod, dbmod_name)(**config) - except dbapi.Error as error: - dbstatus = str(error) - except Exception: - dbstatus = 'Could not connect to the database.' - except Exception: - dbstatus = 'Could not import DBUtils.%s.' % dbmod_name - except Exception: - dbstatus = 'Could not import %s.' % dbapi_name - - # Initialize the buttons - _actions = [] - _buttons = [] - for action in ( - 'create tables', 'list seminars', 'list attendees', - 'add seminar', 'add attendee'): - value = action.capitalize() - action = action.split() - action[1] = action[1].capitalize() - action = ''.join(action) - _actions.append(action) - _buttons.append( - '' - % (action, value)) - _buttons = tuple(_buttons) - - def title(self): - return "DBUtils Example" - - def actions(self): - return ExamplePage.actions(self) + self._actions - - def awake(self, transaction): - ExamplePage.awake(self, transaction) - self._output = [] - - def postAction(self, actionName): - self.writeBody() - del self._output - ExamplePage.postAction(self, actionName) - - def output(self, s): - self._output.append(s) - - def outputMsg(self, msg, error=False): - self._output.append( - '

%s

' % ('red' if error else 'green', msg)) - - def connection(self, shareable=True): - if self.dbstatus: - error = self.dbstatus - else: - try: - if self.dbmod_name == 'PooledDB': - return self.dbclass.connection(shareable) - else: - return self.dbclass.connection() - except self.dbapi.Error as error: - error = str(error) - except Exception: - error = 'Cannot connect to the database.' - self.outputMsg(error, True) - - def dedicated_connection(self): - return self.connection(False) - - def sqlEncode(self, s): - if s is None: - return 'null' - s = s.replace('\\', '\\\\').replace('\'', '\\\'') - return "'%s'" % s - - def createTables(self): - db = self.dedicated_connection() - if not db: - return - for table in tables: - self._output.append( - '

Creating the following table:

%s
' % table) - ddl = 'create table ' + table - try: - if self.dbapi_name == 'pg': - db.query(ddl) - else: - db.cursor().execute(ddl) - db.commit() - except self.dbapi.Error as error: - if self.dbapi_name != 'pg': - db.rollback() - self.outputMsg(error, True) - else: - self.outputMsg('The table was successfully created.') - db.close() - - def listSeminars(self): - id = self.request().field('id', None) - if id: - if not isinstance(id, list): - id = [id] - cmd = ','.join(map(self.sqlEncode, id)) - cmd = 'delete from seminars where id in (%s)' % cmd - db = self.dedicated_connection() - if not db: - return - try: - if self.dbapi_name == 'pg': - db.query('begin') - db.query(cmd) - db.query('end') - else: - db.cursor().execute(cmd) - db.commit() - except self.dbapi.Error as error: - try: - if self.dbapi_name == 'pg': - db.query('end') - else: - db.rollback() - except Exception: - pass - self.outputMsg(error, True) - return - else: - self.outputMsg('Entries deleted: %d' % len(id)) - db = self.connection() - if not db: - return - query = ('select id, title, cost, places_left' - ' from seminars order by title') - try: - if self.dbapi_name == 'pg': - result = db.query(query).getresult() - else: - cursor = db.cursor() - cursor.execute(query) - result = cursor.fetchall() - cursor.close() - except self.dbapi.Error as error: - self.outputMsg(error, True) - return - if not result: - self.outputMsg('There are no seminars in the database.', True) - return - wr = self.output - button = self._buttons[1].replace('List seminars', 'Delete') - wr('

List of seminars in the database:

') - wr('
' - '' - '' % button) - for id, title, cost, places in result: - if places is None: - places = 'unlimited' - if not cost: - cost = 'free' - wr('' % (id, title, cost, places, id)) - wr('
IDSeminar titleCostPlaces left%s
%s%s%s%s' - '' - '
') - - def listAttendees(self): - id = self.request().field('id', None) - if id: - if not isinstance(id, list): - id = [id] - cmds = [ - 'delete from attendees where rpad(seminar,4)||name in (%s)' - % ','.join(map(self.sqlEncode, id))] - places = {} - for i in id: - i = i[:4].rstrip() - if i in places: - places[i] += 1 - else: - places[i] = 1 - for i, n in places.items(): - cmds.append( - 'update seminars set places_left=places_left+%d' - ' where id=%s' % (n, self.sqlEncode(i))) - db = self.dedicated_connection() - if not db: - return - try: - if self.dbapi_name == 'pg': - db.query('begin') - for cmd in cmds: - db.query(cmd) - db.query('end') - else: - for cmd in cmds: - db.cursor().execute(cmd) - db.commit() - except self.dbapi.Error as error: - if self.dbapi_name == 'pg': - db.query('end') - else: - db.rollback() - self.outputMsg(error, True) - return - else: - self.outputMsg('Entries deleted: %d' % len(id)) - db = self.connection() - if not db: - return - query = ('select a.name, s.id, s.title, a.paid' - ' from attendees a,seminars s' - ' where s.id=a.seminar order by a.name, s.title') - try: - if self.dbapi_name == 'pg': - result = db.query(query).getresult() - else: - cursor = db.cursor() - cursor.execute(query) - result = cursor.fetchall() - cursor.close() - except self.dbapi.Error as error: - self.outputMsg(error, True) - return - if not result: - self.outputMsg('There are no attendees in the database.', True) - return - wr = self.output - button = self._buttons[2].replace('List attendees', 'Delete') - wr('

List of attendees in the database:

') - wr('
' - '' - '' % button) - for name, id, title, paid in result: - paid = 'Yes' if paid else 'No' - id = id.ljust(4) + name - wr('' - '' - '' % (name, title, paid, id)) - wr('
NameSeminarPaid%s
%s%s%s
') - - def addSeminar(self): - wr = self.output - wr('

Add a seminar entry to the database:

') - wr('
' - '' - '' - '' - '' - '' - '
ID
Title
Cost
Places
%s
' % self._buttons[3]) - request = self.request() - if not request.hasField('id'): - return - values = [] - for name in ('id', 'title', 'cost', 'places'): - values.append(request.field(name, '').strip()) - if not values[0] or not values[1]: - self.outputMsg('You must enter a seminar ID and a title!') - return - if not values[2]: - values[2] = None - if not values[3]: - values[3] = None - db = self.dedicated_connection() - if not db: - return - cmd = ('insert into seminars values (%s,%s,%s,%s)' - % tuple(map(self.sqlEncode, values))) - try: - if self.dbapi_name == 'pg': - db.query('begin') - db.query(cmd) - db.query('end') - else: - db.cursor().execute(cmd) - db.commit() - except self.dbapi.Error as error: - if self.dbapi_name == 'pg': - db.query('end') - else: - db.rollback() - self.outputMsg(error, True) - else: - self.outputMsg('"%s" added to seminars.' % values[1]) - db.close() - - def addAttendee(self): - db = self.connection() - if not db: - return - query = ('select id, title from seminars' - ' where places_left is null or places_left>0 order by title') - try: - if self.dbapi_name == 'pg': - result = db.query(query).getresult() - else: - cursor = db.cursor() - cursor.execute(query) - result = cursor.fetchall() - cursor.close() - except self.dbapi.Error as error: - self.outputMsg(error, True) - return - if not result: - self.outputMsg('You have to define seminars first.') - return - sem = ['') - sem = ''.join(sem) - wr = self.output - wr('

Add an attendee entry to the database:

') - wr('
' - '' - '' - '' - '
Name
Seminar%s
Paid' - 'Yes ' - 'No' - '
%s
' % (sem, self._buttons[4])) - request = self.request() - if not request.hasField('name'): - return - values = [] - for name in ('name', 'seminar', 'paid'): - values.append(request.field(name, '').strip()) - if not values[0] or not values[1]: - self.outputMsg('You must enter a name and a seminar!') - return - db = self.dedicated_connection() - if not db: - return - try: - if self.dbapi_name == 'pg': - db.query('begin') - cmd = ('update seminars set places_left=places_left-1' - ' where id=%s' % self.sqlEncode(values[1])) - db.query(cmd) - cmd = ('select places_left from seminars' - ' where id=%s' % self.sqlEncode(values[1])) - if (db.query(cmd).getresult()[0][0] or 0) < 0: - raise self.dbapi.Error("No more places left.") - cmd = ('insert into attendees values (%s,%s,%s)' - % tuple(map(self.sqlEncode, values))) - db.query(cmd) - db.query('end') - else: - cursor = db.cursor() - cmd = ('update seminars set places_left=places_left-1' - ' where id=%s' % self.sqlEncode(values[1])) - cursor.execute(cmd) - cmd = ('select places_left from seminars' - ' where id=%s' % self.sqlEncode(values[1])) - cursor.execute(cmd) - if (cursor.fetchone()[0] or 0) < 0: - raise self.dbapi.Error("No more places left.") - cmd = ('insert into attendees values (%s,%s,%s)' - % tuple(map(self.sqlEncode, values))) - db.cursor().execute(cmd) - cursor.close() - db.commit() - except self.dbapi.Error as error: - if self.dbapi_name == 'pg': - db.query('end') - else: - db.rollback() - self.outputMsg(error, True) - else: - self.outputMsg('%s added to attendees.' % values[0]) - db.close() - - def writeContent(self): - wr = self.writeln - if self._output: - wr('\n'.join(self._output)) - wr('

Back

') - else: - wr('

Welcome to the %s!

' % self.title()) - wr('

We are using DBUtils.%s and the %s database module.

' - % (self.dbmod_name, self.dbapi_name)) - wr('

Configuration: %r

' % DBConfig().config()) - wr('

This example uses a small demo database ' - 'designed to track the attendees for a series of seminars ' - '(see "' - 'The Python DB-API" by Andrew Kuchling).

') - wr('
' - '

%s (create the needed database tables first)

' - '

%s %s (list all database entries)

' - '

%s %s (add entries)

' - '
' % self._buttons) diff --git a/DBUtils/Examples/Main.py b/DBUtils/Examples/Main.py deleted file mode 100644 index 39bf4b6..0000000 --- a/DBUtils/Examples/Main.py +++ /dev/null @@ -1,21 +0,0 @@ - -from WebKit.Examples.ExamplePage import ExamplePage - - -class Main(ExamplePage): - - def writeContent(self): - self.writeln('''

DBUtils example

-

You can set the DBUtils parameters in the following file

- -

With the default settings,

- -

Start the demo!

-''') diff --git a/DBUtils/Examples/__init__.py b/DBUtils/Examples/__init__.py deleted file mode 100644 index 71f8157..0000000 --- a/DBUtils/Examples/__init__.py +++ /dev/null @@ -1 +0,0 @@ -# DBUtils Examples diff --git a/DBUtils/Docs/Doc.css b/Docs/Doc.css similarity index 100% rename from DBUtils/Docs/Doc.css rename to Docs/Doc.css diff --git a/DBUtils/Docs/DocUtils.css b/Docs/DocUtils.css similarity index 100% rename from DBUtils/Docs/DocUtils.css rename to Docs/DocUtils.css diff --git a/DBUtils/Docs/RelNotes-0.8.1.html b/Docs/RelNotes-0.8.1.html similarity index 100% rename from DBUtils/Docs/RelNotes-0.8.1.html rename to Docs/RelNotes-0.8.1.html diff --git a/DBUtils/Docs/RelNotes-0.9.1.html b/Docs/RelNotes-0.9.1.html similarity index 100% rename from DBUtils/Docs/RelNotes-0.9.1.html rename to Docs/RelNotes-0.9.1.html diff --git a/DBUtils/Docs/RelNotes-0.9.2.html b/Docs/RelNotes-0.9.2.html similarity index 100% rename from DBUtils/Docs/RelNotes-0.9.2.html rename to Docs/RelNotes-0.9.2.html diff --git a/DBUtils/Docs/RelNotes-0.9.3.html b/Docs/RelNotes-0.9.3.html similarity index 100% rename from DBUtils/Docs/RelNotes-0.9.3.html rename to Docs/RelNotes-0.9.3.html diff --git a/DBUtils/Docs/RelNotes-0.9.4.html b/Docs/RelNotes-0.9.4.html similarity index 100% rename from DBUtils/Docs/RelNotes-0.9.4.html rename to Docs/RelNotes-0.9.4.html diff --git a/DBUtils/Docs/RelNotes-1.0.html b/Docs/RelNotes-1.0.html similarity index 100% rename from DBUtils/Docs/RelNotes-1.0.html rename to Docs/RelNotes-1.0.html diff --git a/DBUtils/Docs/RelNotes-1.1.1.html b/Docs/RelNotes-1.1.1.html similarity index 100% rename from DBUtils/Docs/RelNotes-1.1.1.html rename to Docs/RelNotes-1.1.1.html diff --git a/DBUtils/Docs/RelNotes-1.1.html b/Docs/RelNotes-1.1.html similarity index 100% rename from DBUtils/Docs/RelNotes-1.1.html rename to Docs/RelNotes-1.1.html diff --git a/DBUtils/Docs/RelNotes-1.2.html b/Docs/RelNotes-1.2.html similarity index 100% rename from DBUtils/Docs/RelNotes-1.2.html rename to Docs/RelNotes-1.2.html diff --git a/DBUtils/Docs/RelNotes-1.3.html b/Docs/RelNotes-1.3.html similarity index 100% rename from DBUtils/Docs/RelNotes-1.3.html rename to Docs/RelNotes-1.3.html diff --git a/DBUtils/Docs/RelNotes-1.4.html b/Docs/RelNotes-1.4.html similarity index 100% rename from DBUtils/Docs/RelNotes-1.4.html rename to Docs/RelNotes-1.4.html diff --git a/DBUtils/Docs/UsersGuide.de.html b/Docs/UsersGuide.de.html similarity index 100% rename from DBUtils/Docs/UsersGuide.de.html rename to Docs/UsersGuide.de.html diff --git a/DBUtils/Docs/UsersGuide.de.rst b/Docs/UsersGuide.de.rst similarity index 100% rename from DBUtils/Docs/UsersGuide.de.rst rename to Docs/UsersGuide.de.rst diff --git a/DBUtils/Docs/UsersGuide.html b/Docs/UsersGuide.html similarity index 100% rename from DBUtils/Docs/UsersGuide.html rename to Docs/UsersGuide.html diff --git a/DBUtils/Docs/UsersGuide.rst b/Docs/UsersGuide.rst similarity index 100% rename from DBUtils/Docs/UsersGuide.rst rename to Docs/UsersGuide.rst diff --git a/DBUtils/Docs/dbdep.gif b/Docs/dbdep.gif similarity index 100% rename from DBUtils/Docs/dbdep.gif rename to Docs/dbdep.gif diff --git a/DBUtils/Docs/persist.gif b/Docs/persist.gif similarity index 100% rename from DBUtils/Docs/persist.gif rename to Docs/persist.gif diff --git a/DBUtils/Docs/pgdep.gif b/Docs/pgdep.gif similarity index 100% rename from DBUtils/Docs/pgdep.gif rename to Docs/pgdep.gif diff --git a/DBUtils/Docs/pool.gif b/Docs/pool.gif similarity index 100% rename from DBUtils/Docs/pool.gif rename to Docs/pool.gif diff --git a/DBUtils/Tests/TestPersistentDB.py b/Tests/TestPersistentDB.py similarity index 100% rename from DBUtils/Tests/TestPersistentDB.py rename to Tests/TestPersistentDB.py diff --git a/DBUtils/Tests/TestPersistentPg.py b/Tests/TestPersistentPg.py similarity index 100% rename from DBUtils/Tests/TestPersistentPg.py rename to Tests/TestPersistentPg.py diff --git a/DBUtils/Tests/TestPooledDB.py b/Tests/TestPooledDB.py similarity index 100% rename from DBUtils/Tests/TestPooledDB.py rename to Tests/TestPooledDB.py diff --git a/DBUtils/Tests/TestPooledPg.py b/Tests/TestPooledPg.py similarity index 100% rename from DBUtils/Tests/TestPooledPg.py rename to Tests/TestPooledPg.py diff --git a/DBUtils/Tests/TestSimplePooledDB.py b/Tests/TestSimplePooledDB.py similarity index 100% rename from DBUtils/Tests/TestSimplePooledDB.py rename to Tests/TestSimplePooledDB.py diff --git a/DBUtils/Tests/TestSimplePooledPg.py b/Tests/TestSimplePooledPg.py similarity index 100% rename from DBUtils/Tests/TestSimplePooledPg.py rename to Tests/TestSimplePooledPg.py diff --git a/DBUtils/Tests/TestSteadyDB.py b/Tests/TestSteadyDB.py similarity index 100% rename from DBUtils/Tests/TestSteadyDB.py rename to Tests/TestSteadyDB.py diff --git a/DBUtils/Tests/TestSteadyPg.py b/Tests/TestSteadyPg.py similarity index 100% rename from DBUtils/Tests/TestSteadyPg.py rename to Tests/TestSteadyPg.py diff --git a/DBUtils/Tests/TestThreadingLocal.py b/Tests/TestThreadingLocal.py similarity index 100% rename from DBUtils/Tests/TestThreadingLocal.py rename to Tests/TestThreadingLocal.py diff --git a/DBUtils/Tests/__init__.py b/Tests/__init__.py similarity index 100% rename from DBUtils/Tests/__init__.py rename to Tests/__init__.py diff --git a/DBUtils/Tests/mock_db.py b/Tests/mock_db.py similarity index 100% rename from DBUtils/Tests/mock_db.py rename to Tests/mock_db.py diff --git a/DBUtils/Tests/mock_pg.py b/Tests/mock_pg.py similarity index 100% rename from DBUtils/Tests/mock_pg.py rename to Tests/mock_pg.py From bef64b7d77f1df2f20efe5e09c5129865bfc5041 Mon Sep 17 00:00:00 2001 From: Christoph Zwerschke Date: Sat, 26 Sep 2020 14:24:03 +0200 Subject: [PATCH 02/90] Rename top folders to lower case --- {DBUtils => dbutils}/PersistentDB.py | 0 {DBUtils => dbutils}/PersistentPg.py | 0 {DBUtils => dbutils}/PooledDB.py | 0 {DBUtils => dbutils}/PooledPg.py | 0 {DBUtils => dbutils}/Properties.py | 0 {DBUtils => dbutils}/SimplePooledDB.py | 0 {DBUtils => dbutils}/SimplePooledPg.py | 0 {DBUtils => dbutils}/SteadyDB.py | 0 {DBUtils => dbutils}/SteadyPg.py | 0 {DBUtils => dbutils}/__init__.py | 0 {Docs => docs}/Doc.css | 0 {Docs => docs}/DocUtils.css | 0 {Docs => docs}/RelNotes-0.8.1.html | 0 {Docs => docs}/RelNotes-0.9.1.html | 0 {Docs => docs}/RelNotes-0.9.2.html | 0 {Docs => docs}/RelNotes-0.9.3.html | 0 {Docs => docs}/RelNotes-0.9.4.html | 0 {Docs => docs}/RelNotes-1.0.html | 0 {Docs => docs}/RelNotes-1.1.1.html | 0 {Docs => docs}/RelNotes-1.1.html | 0 {Docs => docs}/RelNotes-1.2.html | 0 {Docs => docs}/RelNotes-1.3.html | 0 {Docs => docs}/RelNotes-1.4.html | 0 {Docs => docs}/UsersGuide.de.html | 0 {Docs => docs}/UsersGuide.de.rst | 0 {Docs => docs}/UsersGuide.html | 0 {Docs => docs}/UsersGuide.rst | 0 {Docs => docs}/dbdep.gif | Bin {Docs => docs}/persist.gif | Bin {Docs => docs}/pgdep.gif | Bin {Docs => docs}/pool.gif | Bin {Tests => tests}/TestPersistentDB.py | 0 {Tests => tests}/TestPersistentPg.py | 0 {Tests => tests}/TestPooledDB.py | 0 {Tests => tests}/TestPooledPg.py | 0 {Tests => tests}/TestSimplePooledDB.py | 0 {Tests => tests}/TestSimplePooledPg.py | 0 {Tests => tests}/TestSteadyDB.py | 0 {Tests => tests}/TestSteadyPg.py | 0 {Tests => tests}/TestThreadingLocal.py | 0 {Tests => tests}/__init__.py | 0 {Tests => tests}/mock_db.py | 0 {Tests => tests}/mock_pg.py | 0 43 files changed, 0 insertions(+), 0 deletions(-) rename {DBUtils => dbutils}/PersistentDB.py (100%) rename {DBUtils => dbutils}/PersistentPg.py (100%) rename {DBUtils => dbutils}/PooledDB.py (100%) rename {DBUtils => dbutils}/PooledPg.py (100%) rename {DBUtils => dbutils}/Properties.py (100%) rename {DBUtils => dbutils}/SimplePooledDB.py (100%) rename {DBUtils => dbutils}/SimplePooledPg.py (100%) rename {DBUtils => dbutils}/SteadyDB.py (100%) rename {DBUtils => dbutils}/SteadyPg.py (100%) rename {DBUtils => dbutils}/__init__.py (100%) rename {Docs => docs}/Doc.css (100%) rename {Docs => docs}/DocUtils.css (100%) rename {Docs => docs}/RelNotes-0.8.1.html (100%) rename {Docs => docs}/RelNotes-0.9.1.html (100%) rename {Docs => docs}/RelNotes-0.9.2.html (100%) rename {Docs => docs}/RelNotes-0.9.3.html (100%) rename {Docs => docs}/RelNotes-0.9.4.html (100%) rename {Docs => docs}/RelNotes-1.0.html (100%) rename {Docs => docs}/RelNotes-1.1.1.html (100%) rename {Docs => docs}/RelNotes-1.1.html (100%) rename {Docs => docs}/RelNotes-1.2.html (100%) rename {Docs => docs}/RelNotes-1.3.html (100%) rename {Docs => docs}/RelNotes-1.4.html (100%) rename {Docs => docs}/UsersGuide.de.html (100%) rename {Docs => docs}/UsersGuide.de.rst (100%) rename {Docs => docs}/UsersGuide.html (100%) rename {Docs => docs}/UsersGuide.rst (100%) rename {Docs => docs}/dbdep.gif (100%) rename {Docs => docs}/persist.gif (100%) rename {Docs => docs}/pgdep.gif (100%) rename {Docs => docs}/pool.gif (100%) rename {Tests => tests}/TestPersistentDB.py (100%) rename {Tests => tests}/TestPersistentPg.py (100%) rename {Tests => tests}/TestPooledDB.py (100%) rename {Tests => tests}/TestPooledPg.py (100%) rename {Tests => tests}/TestSimplePooledDB.py (100%) rename {Tests => tests}/TestSimplePooledPg.py (100%) rename {Tests => tests}/TestSteadyDB.py (100%) rename {Tests => tests}/TestSteadyPg.py (100%) rename {Tests => tests}/TestThreadingLocal.py (100%) rename {Tests => tests}/__init__.py (100%) rename {Tests => tests}/mock_db.py (100%) rename {Tests => tests}/mock_pg.py (100%) diff --git a/DBUtils/PersistentDB.py b/dbutils/PersistentDB.py similarity index 100% rename from DBUtils/PersistentDB.py rename to dbutils/PersistentDB.py diff --git a/DBUtils/PersistentPg.py b/dbutils/PersistentPg.py similarity index 100% rename from DBUtils/PersistentPg.py rename to dbutils/PersistentPg.py diff --git a/DBUtils/PooledDB.py b/dbutils/PooledDB.py similarity index 100% rename from DBUtils/PooledDB.py rename to dbutils/PooledDB.py diff --git a/DBUtils/PooledPg.py b/dbutils/PooledPg.py similarity index 100% rename from DBUtils/PooledPg.py rename to dbutils/PooledPg.py diff --git a/DBUtils/Properties.py b/dbutils/Properties.py similarity index 100% rename from DBUtils/Properties.py rename to dbutils/Properties.py diff --git a/DBUtils/SimplePooledDB.py b/dbutils/SimplePooledDB.py similarity index 100% rename from DBUtils/SimplePooledDB.py rename to dbutils/SimplePooledDB.py diff --git a/DBUtils/SimplePooledPg.py b/dbutils/SimplePooledPg.py similarity index 100% rename from DBUtils/SimplePooledPg.py rename to dbutils/SimplePooledPg.py diff --git a/DBUtils/SteadyDB.py b/dbutils/SteadyDB.py similarity index 100% rename from DBUtils/SteadyDB.py rename to dbutils/SteadyDB.py diff --git a/DBUtils/SteadyPg.py b/dbutils/SteadyPg.py similarity index 100% rename from DBUtils/SteadyPg.py rename to dbutils/SteadyPg.py diff --git a/DBUtils/__init__.py b/dbutils/__init__.py similarity index 100% rename from DBUtils/__init__.py rename to dbutils/__init__.py diff --git a/Docs/Doc.css b/docs/Doc.css similarity index 100% rename from Docs/Doc.css rename to docs/Doc.css diff --git a/Docs/DocUtils.css b/docs/DocUtils.css similarity index 100% rename from Docs/DocUtils.css rename to docs/DocUtils.css diff --git a/Docs/RelNotes-0.8.1.html b/docs/RelNotes-0.8.1.html similarity index 100% rename from Docs/RelNotes-0.8.1.html rename to docs/RelNotes-0.8.1.html diff --git a/Docs/RelNotes-0.9.1.html b/docs/RelNotes-0.9.1.html similarity index 100% rename from Docs/RelNotes-0.9.1.html rename to docs/RelNotes-0.9.1.html diff --git a/Docs/RelNotes-0.9.2.html b/docs/RelNotes-0.9.2.html similarity index 100% rename from Docs/RelNotes-0.9.2.html rename to docs/RelNotes-0.9.2.html diff --git a/Docs/RelNotes-0.9.3.html b/docs/RelNotes-0.9.3.html similarity index 100% rename from Docs/RelNotes-0.9.3.html rename to docs/RelNotes-0.9.3.html diff --git a/Docs/RelNotes-0.9.4.html b/docs/RelNotes-0.9.4.html similarity index 100% rename from Docs/RelNotes-0.9.4.html rename to docs/RelNotes-0.9.4.html diff --git a/Docs/RelNotes-1.0.html b/docs/RelNotes-1.0.html similarity index 100% rename from Docs/RelNotes-1.0.html rename to docs/RelNotes-1.0.html diff --git a/Docs/RelNotes-1.1.1.html b/docs/RelNotes-1.1.1.html similarity index 100% rename from Docs/RelNotes-1.1.1.html rename to docs/RelNotes-1.1.1.html diff --git a/Docs/RelNotes-1.1.html b/docs/RelNotes-1.1.html similarity index 100% rename from Docs/RelNotes-1.1.html rename to docs/RelNotes-1.1.html diff --git a/Docs/RelNotes-1.2.html b/docs/RelNotes-1.2.html similarity index 100% rename from Docs/RelNotes-1.2.html rename to docs/RelNotes-1.2.html diff --git a/Docs/RelNotes-1.3.html b/docs/RelNotes-1.3.html similarity index 100% rename from Docs/RelNotes-1.3.html rename to docs/RelNotes-1.3.html diff --git a/Docs/RelNotes-1.4.html b/docs/RelNotes-1.4.html similarity index 100% rename from Docs/RelNotes-1.4.html rename to docs/RelNotes-1.4.html diff --git a/Docs/UsersGuide.de.html b/docs/UsersGuide.de.html similarity index 100% rename from Docs/UsersGuide.de.html rename to docs/UsersGuide.de.html diff --git a/Docs/UsersGuide.de.rst b/docs/UsersGuide.de.rst similarity index 100% rename from Docs/UsersGuide.de.rst rename to docs/UsersGuide.de.rst diff --git a/Docs/UsersGuide.html b/docs/UsersGuide.html similarity index 100% rename from Docs/UsersGuide.html rename to docs/UsersGuide.html diff --git a/Docs/UsersGuide.rst b/docs/UsersGuide.rst similarity index 100% rename from Docs/UsersGuide.rst rename to docs/UsersGuide.rst diff --git a/Docs/dbdep.gif b/docs/dbdep.gif similarity index 100% rename from Docs/dbdep.gif rename to docs/dbdep.gif diff --git a/Docs/persist.gif b/docs/persist.gif similarity index 100% rename from Docs/persist.gif rename to docs/persist.gif diff --git a/Docs/pgdep.gif b/docs/pgdep.gif similarity index 100% rename from Docs/pgdep.gif rename to docs/pgdep.gif diff --git a/Docs/pool.gif b/docs/pool.gif similarity index 100% rename from Docs/pool.gif rename to docs/pool.gif diff --git a/Tests/TestPersistentDB.py b/tests/TestPersistentDB.py similarity index 100% rename from Tests/TestPersistentDB.py rename to tests/TestPersistentDB.py diff --git a/Tests/TestPersistentPg.py b/tests/TestPersistentPg.py similarity index 100% rename from Tests/TestPersistentPg.py rename to tests/TestPersistentPg.py diff --git a/Tests/TestPooledDB.py b/tests/TestPooledDB.py similarity index 100% rename from Tests/TestPooledDB.py rename to tests/TestPooledDB.py diff --git a/Tests/TestPooledPg.py b/tests/TestPooledPg.py similarity index 100% rename from Tests/TestPooledPg.py rename to tests/TestPooledPg.py diff --git a/Tests/TestSimplePooledDB.py b/tests/TestSimplePooledDB.py similarity index 100% rename from Tests/TestSimplePooledDB.py rename to tests/TestSimplePooledDB.py diff --git a/Tests/TestSimplePooledPg.py b/tests/TestSimplePooledPg.py similarity index 100% rename from Tests/TestSimplePooledPg.py rename to tests/TestSimplePooledPg.py diff --git a/Tests/TestSteadyDB.py b/tests/TestSteadyDB.py similarity index 100% rename from Tests/TestSteadyDB.py rename to tests/TestSteadyDB.py diff --git a/Tests/TestSteadyPg.py b/tests/TestSteadyPg.py similarity index 100% rename from Tests/TestSteadyPg.py rename to tests/TestSteadyPg.py diff --git a/Tests/TestThreadingLocal.py b/tests/TestThreadingLocal.py similarity index 100% rename from Tests/TestThreadingLocal.py rename to tests/TestThreadingLocal.py diff --git a/Tests/__init__.py b/tests/__init__.py similarity index 100% rename from Tests/__init__.py rename to tests/__init__.py diff --git a/Tests/mock_db.py b/tests/mock_db.py similarity index 100% rename from Tests/mock_db.py rename to tests/mock_db.py diff --git a/Tests/mock_pg.py b/tests/mock_pg.py similarity index 100% rename from Tests/mock_pg.py rename to tests/mock_pg.py From f22adcec9b8eab2cf236808bd33f1220cb66526d Mon Sep 17 00:00:00 2001 From: Christoph Zwerschke Date: Sat, 26 Sep 2020 16:15:28 +0200 Subject: [PATCH 03/90] Rename UsersGuide, make Changelog from ReleaseNotes --- docs/RelNotes-0.8.1.html | 19 -- docs/RelNotes-0.9.1.html | 29 --- docs/RelNotes-0.9.2.html | 26 --- docs/RelNotes-0.9.3.html | 34 --- docs/RelNotes-0.9.4.html | 26 --- docs/RelNotes-1.0.html | 49 ---- docs/RelNotes-1.1.1.html | 32 --- docs/RelNotes-1.1.html | 46 ---- docs/RelNotes-1.2.html | 26 --- docs/RelNotes-1.3.html | 26 --- docs/RelNotes-1.4.html | 26 --- docs/changelog.html | 270 ++++++++++++++++++++++ docs/changelog.rst | 211 +++++++++++++++++ docs/{Doc.css => doc.css} | 2 +- docs/{DocUtils.css => docutils.css} | 0 docs/{UsersGuide.de.html => main.de.html} | 4 +- docs/{UsersGuide.de.rst => main.de.rst} | 4 +- docs/{UsersGuide.html => main.html} | 4 +- docs/{UsersGuide.rst => main.rst} | 4 +- buildhtml.py => docs/make.py | 4 +- 20 files changed, 492 insertions(+), 350 deletions(-) delete mode 100644 docs/RelNotes-0.8.1.html delete mode 100644 docs/RelNotes-0.9.1.html delete mode 100644 docs/RelNotes-0.9.2.html delete mode 100644 docs/RelNotes-0.9.3.html delete mode 100644 docs/RelNotes-0.9.4.html delete mode 100644 docs/RelNotes-1.0.html delete mode 100644 docs/RelNotes-1.1.1.html delete mode 100644 docs/RelNotes-1.1.html delete mode 100644 docs/RelNotes-1.2.html delete mode 100644 docs/RelNotes-1.3.html delete mode 100644 docs/RelNotes-1.4.html create mode 100644 docs/changelog.html create mode 100644 docs/changelog.rst rename docs/{Doc.css => doc.css} (99%) rename docs/{DocUtils.css => docutils.css} (100%) rename docs/{UsersGuide.de.html => main.de.html} (99%) rename docs/{UsersGuide.de.rst => main.de.rst} (99%) rename docs/{UsersGuide.html => main.html} (99%) rename docs/{UsersGuide.rst => main.rst} (99%) rename buildhtml.py => docs/make.py (92%) diff --git a/docs/RelNotes-0.8.1.html b/docs/RelNotes-0.8.1.html deleted file mode 100644 index fbb16f8..0000000 --- a/docs/RelNotes-0.8.1.html +++ /dev/null @@ -1,19 +0,0 @@ - - - -DBUtils 0.8.1 Release Notes - - - -

DBUtils 0.8.1 Release Notes

- -

DBUtils 0.8.1 was released on September 13, 2005.

- -

This is the first public release of DBUtils.

- - - - diff --git a/docs/RelNotes-0.9.1.html b/docs/RelNotes-0.9.1.html deleted file mode 100644 index 55b96b4..0000000 --- a/docs/RelNotes-0.9.1.html +++ /dev/null @@ -1,29 +0,0 @@ - - - -DBUtils 0.9.1 Release Notes - - - -

DBUtils 0.9.1 Release Notes

- -

DBUtils 0.9.1 was released on May 8, 2006.

- -

This is the second public release of DBUtils.

- -

Changes:

-
    -
  • Added _closeable attribute and made persistent connections -not closeable by default. This allows PersistentDB to be used -in the same way as you would use PooledDB.
  • -
  • Allowed arguments in the DB-API 2 cursor() method. -MySQLdb is using this to specify cursor classes. (Suggested by Michael Palmer.)
  • -
  • Improved the documentation and added a User's Guide.
  • -
- - - - diff --git a/docs/RelNotes-0.9.2.html b/docs/RelNotes-0.9.2.html deleted file mode 100644 index b3e566d..0000000 --- a/docs/RelNotes-0.9.2.html +++ /dev/null @@ -1,26 +0,0 @@ - - - -DBUtils 0.9.2 Release Notes - - - -

DBUtils 0.9.2 Release Notes

- -

DBUtils 0.9.2 was released on September 22, 2006.

- -

This is the third public release of DBUtils.

- -

Changes:

-
    -
  • Renamed SolidDB to SteadyDB to avoid confusion -with the solidDB storage engine.
  • -
  • Accordingly, renamed SolidPg to SteadyPg.
  • -
- - - - diff --git a/docs/RelNotes-0.9.3.html b/docs/RelNotes-0.9.3.html deleted file mode 100644 index 72f4fb8..0000000 --- a/docs/RelNotes-0.9.3.html +++ /dev/null @@ -1,34 +0,0 @@ - - - -DBUtils 0.9.3 Release Notes - - - -

DBUtils 0.9.3 Release Notes

- -

DBUtils 0.9.3 was released on May 21, 2007.

- -

This is the fourth public release of DBUtils.

- -

Changes:

-
    -
  • Support custom creator functions for database connections. -These can now be used as the first parameter instead of an DB-API module -(suggested by Ezio Vernacotola).
  • -
  • Added destructor for steady connections.
  • -
  • Use setuptools -if available.
  • -
  • Some code cleanup.
  • -
  • Some fixes in the documentation. -Added Chinese translation -of the User's Guide, -kindly contributed by gashero.
  • -
- - - - diff --git a/docs/RelNotes-0.9.4.html b/docs/RelNotes-0.9.4.html deleted file mode 100644 index 674a6c8..0000000 --- a/docs/RelNotes-0.9.4.html +++ /dev/null @@ -1,26 +0,0 @@ - - - -DBUtils 0.9.4 Release Notes - - - -

DBUtils 0.9.4 Release Notes

- -

DBUtils 0.9.4 was released on July 7, 2007.

- -

This is the fifth public release of DBUtils.

- -

This release fixes a problem in the destructor code and has been -supplemented with a German User's Guide.

- -

Please note that the dbapi parameter has been renamed to -creator in the last release since you can now pass custom -creator functions for database connections instead of DB-API 2 modules.

- - - - diff --git a/docs/RelNotes-1.0.html b/docs/RelNotes-1.0.html deleted file mode 100644 index 2606375..0000000 --- a/docs/RelNotes-1.0.html +++ /dev/null @@ -1,49 +0,0 @@ - - - -DBUtils 1.0 Release Notes - - - -

DBUtils 1.0 Release Notes

- -

DBUtils 1.0 was released on November 29, 2008.

- -

This is the sixth public release of DBUtils.

- -

Changes:

-
    -
  • Added a failures parameter for configuring the exception classes for -which the failover mechanisms is applied (as suggested by Matthew Harriger).
  • -
  • Added a closeable parameter for configuring whether connections -can be closed (otherwise closing connections will be silently ignored).
  • -
  • It is now possible to override defaults via the creator.dbapi -and creator.threadsafety attributes.
  • -
  • Added alias method dedicated_connection for -connection(shareable=False).
  • -
  • Added a version attribute to all exported classes.
  • -
  • Where 0 has the meaning "unlimited", parameters can now be also -set to None instead.
  • -
  • It turned out that threading.local does not work properly with -mod_wsgi, so we use the Python implementation for thread-local data -even when a faster threading.local implementation is available. -A new parameter threadlocal allows you to pass an arbitrary class -such as threading.local if you know it works in your environment.
  • -
- -

Bugfixes and Improvements:

-
    -
  • In some cases, when instance initialization failed or referenced objects -were already destroyed, finalizers could throw exceptions or create infinite -recursion (problem reported by Gregory Pinero and Jehiah Czebotar).
  • -
  • DBUtils now tries harder to find the underlying DB-API 2 module if only a -connection creator function is specified. This had not worked before with the -MySQLdb module (problem reported by Gregory Pinero).
  • -
- - - - diff --git a/docs/RelNotes-1.1.1.html b/docs/RelNotes-1.1.1.html deleted file mode 100644 index b780067..0000000 --- a/docs/RelNotes-1.1.1.html +++ /dev/null @@ -1,32 +0,0 @@ - - - -DBUtils 1.1.1 Release Notes - - - -

DBUtils 1.1.1 Release Notes

- -

DBUtils 1.1.1 was released on 02/04/17.

- -

This bugfix release is the eight public release of DBUtils.

- -

It is intended to be used with Python versions 2.3 to 2.7

- -

Improvements:

-
    -
  • Reopen SteadyDB connections when commit or rollback fails -(suggested by Ben Hoyt).
  • -
- -

Bugfixes:

-
    -
  • Fixed a problem when running under Jython (reported by Vitaly Kruglikov).
  • -
- - - - diff --git a/docs/RelNotes-1.1.html b/docs/RelNotes-1.1.html deleted file mode 100644 index 6cdb156..0000000 --- a/docs/RelNotes-1.1.html +++ /dev/null @@ -1,46 +0,0 @@ - - - -DBUtils 1.1 Release Notes - - - -

DBUtils 1.1 Release Notes

- -

DBUtils 1.1 was released on August 14, 2011.

- -

This is the seventh public release of DBUtils.

- -

Improvements:

-
    -
  • The transparent reopening of connections is actually an undesired behavior -if it happens during database transactions. In these cases, the transaction -should fail and the error be reported back to the application instead of the -rest of the transaction being executed in a new connection and therefore in -a new transaction. Therefore DBUtils now allows suspending the transparent -reopening during transactions. All you need to do is indicate the beginning -of a transaction by calling the begin() method of the connection. -DBUtils makes sure that this method always exists, even if the database driver -does not support it.
  • -
  • If the database driver supports a ping() method, then DBUtils -can use it to check whether connections are alive instead of just trying -to use the connection and reestablishing it in case it was dead. Since these -checks are done at the expense of some performance, you have exact control -when these are executed via the new ping parameter.
  • -
  • PooledDB has got another new parameter reset for -controlling how connections are reset before being put back into the pool.
  • -
- -

Bugfixes:

-
    -
  • Fixed propagation of error messages when the connection was lost.
  • -
  • Fixed an issue with the setoutputsize() cursor method.
  • -
  • Fixed some minor issues with the DBUtilsExample for Webware.
  • -
- - - - diff --git a/docs/RelNotes-1.2.html b/docs/RelNotes-1.2.html deleted file mode 100644 index a90eae2..0000000 --- a/docs/RelNotes-1.2.html +++ /dev/null @@ -1,26 +0,0 @@ - - - -DBUtils 1.2 Release Notes - - - -

DBUtils 1.2 Release Notes

- -

DBUtils 1.2 was released on 02/05/17.

- -

This is the ninth public release of DBUtils.

- -

It is intended to be used with Python versions 2.6 and newer.

- -

Improvements:

-
    -
  • Python 3 is now supported.
  • -
- - - - diff --git a/docs/RelNotes-1.3.html b/docs/RelNotes-1.3.html deleted file mode 100644 index 05f8614..0000000 --- a/docs/RelNotes-1.3.html +++ /dev/null @@ -1,26 +0,0 @@ - - - -DBUtils 1.3 Release Notes - - - -

DBUtils 1.3 Release Notes

- -

DBUtils 1.3 was released on 03/08/18.

- -

This is the tenth public release of DBUtils.

- -

It is intended to be used with Python versions 2.6, 2.7 or 3.4 - 3.7.

- -

Improvements:

-
    -
  • Supports context handlers for connections and cursors.
  • -
- - - - diff --git a/docs/RelNotes-1.4.html b/docs/RelNotes-1.4.html deleted file mode 100644 index 0565fd0..0000000 --- a/docs/RelNotes-1.4.html +++ /dev/null @@ -1,26 +0,0 @@ - - - -DBUtils 1.4 Release Notes - - - -

DBUtils 1.4 Release Notes

- -

DBUtils 1.4 was released on 09/26/20.

- -

This version is intended to be used with Python versions 2.7 and 3.5 to 3.9.

- -

Improvements:

-
    -
  • The SteadyDB and SteadyPg classes only reconnect -after the maxusage limit has been reached when the connection is -not currently inside a transaction.
  • -
- - - - diff --git a/docs/changelog.html b/docs/changelog.html new file mode 100644 index 0000000..1ecb86c --- /dev/null +++ b/docs/changelog.html @@ -0,0 +1,270 @@ + + + + + +Changelog for DBUtils + + + +
+

Changelog for DBUtils

+ + +
+

2.0

+

DBUtils 2.0 was released on September 26, 2020.

+

It is intended to be used with Python versions 2.7 and 3.5 to 3.9.

+
+

Changes:

+
    +
  • DBUtils does not act as a Webware plugin anymore, it is now just an ordinary +Python package (of course it could be used as such also before).

  • +
  • The top-level packages and folders have been renamed to lower-case. +Particularly, you need to import dbutils instead of DBUtils now.

  • +
  • The Webware Examples folder has been removed.

  • +
  • This changelog file has been created from the former release notes.

  • +
+
+
+
+

1.4

+

DBUtils 1.4 was released on August 26, 2020.

+

It is intended to be used with Python versions 2.7 and 3.5 to 3.9.

+
+

Improvements:

+
    +
  • The SteadyDB and SteadyPg classes only reconnect after the +maxusage limit has been reached when the connection is not currently +inside a transaction.

  • +
+
+
+
+

1.3

+

DBUtils 1.3 was released on March 3, 2018.

+

It is intended to be used with Python versions 2.6, 2.7 and 3.4 to 3.7.

+
+

Improvements:

+
    +
  • This version now supports context handlers for connections and cursors.

  • +
+
+
+
+

1.2

+

DBUtils 1.2 was released on February 5, 2017.

+

It is intended to be used with Python versions 2.6, 2.7 and 3.0 to 3.6.

+
+
+

1.1.1

+

DBUtils 1.1.1 was released on February 4, 2017.

+

It is intended to be used with Python versions 2.3 to 2.7.

+
+

Improvements:

+
    +
  • Reopen SteadyDB connections when commit or rollback fails +(suggested by Ben Hoyt).

  • +
+
+
+

Bugfixes:

+
    +
  • Fixed a problem when running under Jython (reported by Vitaly Kruglikov).

  • +
+
+
+
+

1.1

+

DBUtils 1.1 was released on August 14, 2011.

+
+

Improvements:

+
    +
  • The transparent reopening of connections is actually an undesired behavior +if it happens during database transactions. In these cases, the transaction +should fail and the error be reported back to the application instead of the +rest of the transaction being executed in a new connection and therefore in +a new transaction. Therefore DBUtils now allows suspending the transparent +reopening during transactions. All you need to do is indicate the beginning +of a transaction by calling the begin() method of the connection. +DBUtils makes sure that this method always exists, even if the database +driver does not support it.

  • +
  • If the database driver supports a ping() method, then DBUtils can use it +to check whether connections are alive instead of just trying to use the +connection and reestablishing it in case it was dead. Since these checks are +done at the expense of some performance, you have exact control when these +are executed via the new ping parameter.

  • +
  • PooledDB has got another new parameter reset for controlling how +connections are reset before being put back into the pool.

  • +
+
+
+

Bugfixes:

+
+

System Message: WARNING/2 (changelog.rst, line 100)

+

Title underline too short.

+
Bugfixes:
+--------
+
+
    +
  • Fixed propagation of error messages when the connection was lost.

  • +
  • Fixed an issue with the setoutputsize() cursor method.

  • +
  • Fixed some minor issues with the DBUtilsExample for Webware.

  • +
+
+
+
+

1.0

+

DBUtils 1.0 was released on November 29, 2008.

+

It is intended to be used with Python versions 2.2 to 2.6.

+
+

Changes:

+
    +
  • Added a failures parameter for configuring the exception classes for +which the failover mechanisms is applied (as suggested by Matthew Harriger).

  • +
  • Added a closeable parameter for configuring whether connections can be +closed (otherwise closing connections will be silently ignored).

  • +
  • It is now possible to override defaults via the creator.dbapi and +creator.threadsafety attributes.

  • +
  • Added an alias method dedicated_connection as a shorthand for +connection(shareable=False).

  • +
  • Added a version attribute to all exported classes.

  • +
  • Where the value 0 has the meaning "unlimited", parameters can now be also +set to the value None instead.

  • +
  • It turned out that threading.local does not work properly with +mod_wsgi, so we use the Python implementation for thread-local data +even when a faster threading.local implementation is available. +A new parameter threadlocal allows you to pass an arbitrary class +such as threading.local if you know it works in your environment.

  • +
+
+
+

Bugfixes and Improvements:

+
    +
  • In some cases, when instance initialization failed or referenced objects +were already destroyed, finalizers could throw exceptions or create infinite +recursion (problem reported by Gregory Pinero and Jehiah Czebotar).

  • +
  • DBUtils now tries harder to find the underlying DB-API 2 module if only a +connection creator function is specified. This had not worked before with +the MySQLdb module (problem reported by Gregory Pinero).

  • +
+
+
+
+

0.9.4

+

DBUtils 0.9.4 was released on July 7, 2007.

+

This release fixes a problem in the destructor code and has been supplemented +with a German User's Guide.

+

Again, please note that the dbapi parameter has been renamed to creator +in the last release, since you can now pass custom creator functions +for database connections instead of DB-API 2 modules.

+
+
+

0.9.3

+

DBUtils 0.9.3 was released on May 21, 2007.

+
+

Changes:

+
    +
  • Support custom creator functions for database connections. +These can now be used as the first parameter instead of an DB-API module +(suggested by Ezio Vernacotola).

  • +
  • Added destructor for steady connections.

  • +
  • Use setuptools if available.

  • +
  • Some code cleanup.

  • +
  • Some fixes in the documentation. +Added Chinese translation of the User's Guide, kindly contributed by gashero.

  • +
+
+
+
+

0.9.2

+

DBUtils 0.9.2 was released on September 22, 2006.

+

It is intended to be used with Python versions 2.2 to 2.5.

+
+

Changes:

+
    +
  • Renamed SolidDB to SteadyDB to avoid confusion with the "solidDB" +storage engine. Accordingly, renamed SolidPg to SteadyPg.

  • +
+
+
+
+

0.9.1

+

DBUtils 0.9.1 was released on May 8, 2006.

+

It is intended to be used with Python versions 2.2 to 2.4.

+
+

Changes:

+
    +
  • Added _closeable attribute and made persistent connections not closeable +by default. This allows PersistentDB to be used in the same way as you +would use PooledDB.

  • +
  • Allowed arguments in the DB-API 2 cursor() method. MySQLdb is using this +to specify cursor classes. (Suggested by Michael Palmer.)

  • +
  • Improved the documentation and added a User's Guide.

  • +
+
+
+
+

0.8.1 - 2005-09-13

+

DBUtils 0.8.1 was released on September 13, 2005.

+

It is intended to be used with Python versions 2.0 to 2.4.

+

This is the first public release of DBUtils.

+
+
+ + diff --git a/docs/changelog.rst b/docs/changelog.rst new file mode 100644 index 0000000..fb97129 --- /dev/null +++ b/docs/changelog.rst @@ -0,0 +1,211 @@ +Changelog for DBUtils ++++++++++++++++++++++ + +.. contents:: Contents + +2.0 +=== + +DBUtils 2.0 was released on September 26, 2020. + +It is intended to be used with Python versions 2.7 and 3.5 to 3.9. + +Changes: +-------- + +* DBUtils does not act as a Webware plugin anymore, it is now just an ordinary + Python package (of course it could be used as such also before). +* The top-level packages and folders have been renamed to lower-case. + Particularly, you need to import ``dbutils`` instead of ``DBUtils`` now. +* The Webware ``Examples`` folder has been removed. +* This changelog file has been created from the former release notes. + +1.4 +=== + +DBUtils 1.4 was released on August 26, 2020. + +It is intended to be used with Python versions 2.7 and 3.5 to 3.9. + +Improvements: +------------- + +* The ``SteadyDB`` and ``SteadyPg`` classes only reconnect after the + ``maxusage`` limit has been reached when the connection is not currently + inside a transaction. + +1.3 +=== + +DBUtils 1.3 was released on March 3, 2018. + +It is intended to be used with Python versions 2.6, 2.7 and 3.4 to 3.7. + +Improvements: +------------- + +* This version now supports context handlers for connections and cursors. + +1.2 +=== + +DBUtils 1.2 was released on February 5, 2017. + +It is intended to be used with Python versions 2.6, 2.7 and 3.0 to 3.6. + +1.1.1 +===== + +DBUtils 1.1.1 was released on February 4, 2017. + +It is intended to be used with Python versions 2.3 to 2.7. + +Improvements: +------------- + +* Reopen ``SteadyDB`` connections when commit or rollback fails + (suggested by Ben Hoyt). + +Bugfixes: +--------- + +* Fixed a problem when running under Jython (reported by Vitaly Kruglikov). + +1.1 +=== + +DBUtils 1.1 was released on August 14, 2011. + +Improvements: +------------- + +* The transparent reopening of connections is actually an undesired behavior + if it happens during database transactions. In these cases, the transaction + should fail and the error be reported back to the application instead of the + rest of the transaction being executed in a new connection and therefore in + a new transaction. Therefore DBUtils now allows suspending the transparent + reopening during transactions. All you need to do is indicate the beginning + of a transaction by calling the ``begin()`` method of the connection. + DBUtils makes sure that this method always exists, even if the database + driver does not support it. +* If the database driver supports a ``ping()`` method, then DBUtils can use it + to check whether connections are alive instead of just trying to use the + connection and reestablishing it in case it was dead. Since these checks are + done at the expense of some performance, you have exact control when these + are executed via the new ``ping`` parameter. +* ``PooledDB`` has got another new parameter ``reset`` for controlling how + connections are reset before being put back into the pool. + +Bugfixes: +-------- + +* Fixed propagation of error messages when the connection was lost. +* Fixed an issue with the ``setoutputsize()`` cursor method. +* Fixed some minor issues with the ``DBUtilsExample`` for Webware. + + +1.0 +=== + +DBUtils 1.0 was released on November 29, 2008. + +It is intended to be used with Python versions 2.2 to 2.6. + +Changes: +-------- + +* Added a ``failures`` parameter for configuring the exception classes for + which the failover mechanisms is applied (as suggested by Matthew Harriger). +* Added a ``closeable`` parameter for configuring whether connections can be + closed (otherwise closing connections will be silently ignored). +* It is now possible to override defaults via the ``creator.dbapi`` and + ``creator.threadsafety`` attributes. +* Added an alias method ``dedicated_connection`` as a shorthand for + ``connection(shareable=False)``. +* Added a version attribute to all exported classes. +* Where the value ``0`` has the meaning "unlimited", parameters can now be also + set to the value ``None`` instead. +* It turned out that ``threading.local`` does not work properly with + ``mod_wsgi``, so we use the Python implementation for thread-local data + even when a faster ``threading.local`` implementation is available. + A new parameter ``threadlocal`` allows you to pass an arbitrary class + such as ``threading.local`` if you know it works in your environment. + +Bugfixes and Improvements: +-------------------------- + +* In some cases, when instance initialization failed or referenced objects + were already destroyed, finalizers could throw exceptions or create infinite + recursion (problem reported by Gregory Pinero and Jehiah Czebotar). +* DBUtils now tries harder to find the underlying DB-API 2 module if only a + connection creator function is specified. This had not worked before with + the MySQLdb module (problem reported by Gregory Pinero). + +0.9.4 +===== + +DBUtils 0.9.4 was released on July 7, 2007. + +This release fixes a problem in the destructor code and has been supplemented +with a German User's Guide. + +Again, please note that the ``dbapi`` parameter has been renamed to ``creator`` +in the last release, since you can now pass custom creator functions +for database connections instead of DB-API 2 modules. + +0.9.3 +===== + +DBUtils 0.9.3 was released on May 21, 2007. + +Changes: +-------- + +* Support custom creator functions for database connections. + These can now be used as the first parameter instead of an DB-API module + (suggested by Ezio Vernacotola). +* Added destructor for steady connections. +* Use setuptools_ if available. +* Some code cleanup. +* Some fixes in the documentation. + Added Chinese translation of the User's Guide, kindly contributed by gashero. + +.. _setuptools: https://github.com/pypa/setuptools + +0.9.2 +===== + +DBUtils 0.9.2 was released on September 22, 2006. + +It is intended to be used with Python versions 2.2 to 2.5. + +Changes: +-------- + +* Renamed ``SolidDB`` to ``SteadyDB`` to avoid confusion with the "solidDB" + storage engine. Accordingly, renamed ``SolidPg`` to ``SteadyPg``. + +0.9.1 +===== + +DBUtils 0.9.1 was released on May 8, 2006. + +It is intended to be used with Python versions 2.2 to 2.4. + +Changes: +-------- +* Added ``_closeable`` attribute and made persistent connections not closeable + by default. This allows ``PersistentDB`` to be used in the same way as you + would use ``PooledDB``. +* Allowed arguments in the DB-API 2 ``cursor()`` method. MySQLdb is using this + to specify cursor classes. (Suggested by Michael Palmer.) +* Improved the documentation and added a User's Guide. + +0.8.1 - 2005-09-13 +================== + +DBUtils 0.8.1 was released on September 13, 2005. + +It is intended to be used with Python versions 2.0 to 2.4. + +This is the first public release of DBUtils. diff --git a/docs/Doc.css b/docs/doc.css similarity index 99% rename from docs/Doc.css rename to docs/doc.css index 391e17c..c815371 100644 --- a/docs/Doc.css +++ b/docs/doc.css @@ -6,7 +6,7 @@ /* First import default style for pages created with Docutils: */ -@import url(DocUtils.css); +@import url(docutils.css); /* Customization for Webware goes here: */ diff --git a/docs/DocUtils.css b/docs/docutils.css similarity index 100% rename from docs/DocUtils.css rename to docs/docutils.css diff --git a/docs/UsersGuide.de.html b/docs/main.de.html similarity index 99% rename from docs/UsersGuide.de.html rename to docs/main.de.html index 948e12a..10a3eef 100644 --- a/docs/UsersGuide.de.html +++ b/docs/main.de.html @@ -11,12 +11,12 @@

Benutzeranleitung für DBUtils

Version
-
1.4
+
2.0
Released

09/26/20

Translations
-

English | German

+

English | German

diff --git a/docs/UsersGuide.de.rst b/docs/main.de.rst similarity index 99% rename from docs/UsersGuide.de.rst rename to docs/main.de.rst index ee59e63..00013ac 100644 --- a/docs/UsersGuide.de.rst +++ b/docs/main.de.rst @@ -1,11 +1,11 @@ Benutzeranleitung für DBUtils +++++++++++++++++++++++++++++ -:Version: 1.4 +:Version: 2.0 :Released: 09/26/20 :Translations: English_ | German -.. _English: UsersGuide.html +.. _English: main.html .. contents:: Inhalt diff --git a/docs/UsersGuide.html b/docs/main.html similarity index 99% rename from docs/UsersGuide.html rename to docs/main.html index 2ec476e..9ec6f26 100644 --- a/docs/UsersGuide.html +++ b/docs/main.html @@ -11,12 +11,12 @@

DBUtils User's Guide

Version
-
1.4
+
2.0
Released

09/26/20

Translations
-

English | German

+

English | German

diff --git a/docs/UsersGuide.rst b/docs/main.rst similarity index 99% rename from docs/UsersGuide.rst rename to docs/main.rst index 5c17298..edbfd31 100644 --- a/docs/UsersGuide.rst +++ b/docs/main.rst @@ -1,11 +1,11 @@ DBUtils User's Guide ++++++++++++++++++++ -:Version: 1.4 +:Version: 2.0 :Released: 09/26/20 :Translations: English | German_ -.. _German: UsersGuide.de.html +.. _German: main.de.html .. contents:: Contents diff --git a/buildhtml.py b/docs/make.py similarity index 92% rename from buildhtml.py rename to docs/make.py index 420a64c..fb82e88 100755 --- a/buildhtml.py +++ b/docs/make.py @@ -1,4 +1,4 @@ -#!/usr/bin/python3 +#!/usr/bin/python3.8 """Build HMTL from reST files.""" @@ -10,7 +10,7 @@ print("Creating the documentation...") -for rst_file in glob(join('DBUtils', 'Docs', '*.rst')): +for rst_file in glob('*.rst'): name = splitext(rst_file)[0] lang = splitext(name)[1] if lang.startswith('.'): From 5b9fe81108f87fdfa689332b7183c4d8dfb2b721 Mon Sep 17 00:00:00 2001 From: Christoph Zwerschke Date: Sat, 26 Sep 2020 16:29:26 +0200 Subject: [PATCH 04/90] Rename all modules to lower-case Also remove Properties.py since this is no longer a Webware plug-in. --- MANIFEST.in | 12 ++++++++++-- dbutils/Properties.py | 19 ------------------- dbutils/{PersistentDB.py => persistent_db.py} | 0 dbutils/{PersistentPg.py => persistent_pg.py} | 0 dbutils/{PooledDB.py => pooled_db.py} | 0 dbutils/{PooledPg.py => pooled_pg.py} | 0 ...{SimplePooledDB.py => simple_pooled_db.py} | 0 ...{SimplePooledPg.py => simple_pooled_pg.py} | 0 dbutils/{SteadyDB.py => steady_db.py} | 0 dbutils/{SteadyPg.py => steady_pg.py} | 0 Release.md => release.md | 0 setup.py | 4 ++-- ...tPersistentDB.py => test_persistend_db.py} | 0 ...tPersistentPg.py => test_persistend_pg.py} | 0 tests/{TestPooledDB.py => test_pooled_db.py} | 0 tests/{TestPooledPg.py => test_pooled_pg.py} | 0 ...lePooledDB.py => test_simple_pooled_db.py} | 0 ...lePooledPg.py => test_simple_pooled_pg.py} | 0 tests/{TestSteadyDB.py => test_steady_db.py} | 0 tests/{TestSteadyPg.py => test_steady_pg.py} | 0 ...eadingLocal.py => test_threading_local.py} | 0 tox.ini | 7 ++----- 22 files changed, 14 insertions(+), 28 deletions(-) delete mode 100644 dbutils/Properties.py rename dbutils/{PersistentDB.py => persistent_db.py} (100%) rename dbutils/{PersistentPg.py => persistent_pg.py} (100%) rename dbutils/{PooledDB.py => pooled_db.py} (100%) rename dbutils/{PooledPg.py => pooled_pg.py} (100%) rename dbutils/{SimplePooledDB.py => simple_pooled_db.py} (100%) rename dbutils/{SimplePooledPg.py => simple_pooled_pg.py} (100%) rename dbutils/{SteadyDB.py => steady_db.py} (100%) rename dbutils/{SteadyPg.py => steady_pg.py} (100%) rename Release.md => release.md (100%) rename tests/{TestPersistentDB.py => test_persistend_db.py} (100%) rename tests/{TestPersistentPg.py => test_persistend_pg.py} (100%) rename tests/{TestPooledDB.py => test_pooled_db.py} (100%) rename tests/{TestPooledPg.py => test_pooled_pg.py} (100%) rename tests/{TestSimplePooledDB.py => test_simple_pooled_db.py} (100%) rename tests/{TestSimplePooledPg.py => test_simple_pooled_pg.py} (100%) rename tests/{TestSteadyDB.py => test_steady_db.py} (100%) rename tests/{TestSteadyPg.py => test_steady_pg.py} (100%) rename tests/{TestThreadingLocal.py => test_threading_local.py} (100%) diff --git a/MANIFEST.in b/MANIFEST.in index 14ffe38..b4efc19 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,3 +1,11 @@ -exclude Release.md setversion.py +include MANIFEST.in + +include LICENSE include README.md -include DBUtils/Docs/* + +recursive-include docs *.rst make.py *.html *.css *.png *.gif + +prune docs/_build +exclude release.md setversion.py + +global-exclude *.py[co] __pycache__ diff --git a/dbutils/Properties.py b/dbutils/Properties.py deleted file mode 100644 index da7426e..0000000 --- a/dbutils/Properties.py +++ /dev/null @@ -1,19 +0,0 @@ -name = 'DBUtils' - -version = (1, 4, 0) - -docs = [ - {'name': "User's Guide", 'file': 'UsersGuide.html'}, -] - -status = 'beta' - -requiredPyVersion = (2, 7, 0) - -synopsis = ( - "DBUtils provides database related support classes and functions" - " to Webware. There is plenty of useful reusable code here.") - -WebKitConfig = { - 'examplePages': ['DBUtilsExample'] -} diff --git a/dbutils/PersistentDB.py b/dbutils/persistent_db.py similarity index 100% rename from dbutils/PersistentDB.py rename to dbutils/persistent_db.py diff --git a/dbutils/PersistentPg.py b/dbutils/persistent_pg.py similarity index 100% rename from dbutils/PersistentPg.py rename to dbutils/persistent_pg.py diff --git a/dbutils/PooledDB.py b/dbutils/pooled_db.py similarity index 100% rename from dbutils/PooledDB.py rename to dbutils/pooled_db.py diff --git a/dbutils/PooledPg.py b/dbutils/pooled_pg.py similarity index 100% rename from dbutils/PooledPg.py rename to dbutils/pooled_pg.py diff --git a/dbutils/SimplePooledDB.py b/dbutils/simple_pooled_db.py similarity index 100% rename from dbutils/SimplePooledDB.py rename to dbutils/simple_pooled_db.py diff --git a/dbutils/SimplePooledPg.py b/dbutils/simple_pooled_pg.py similarity index 100% rename from dbutils/SimplePooledPg.py rename to dbutils/simple_pooled_pg.py diff --git a/dbutils/SteadyDB.py b/dbutils/steady_db.py similarity index 100% rename from dbutils/SteadyDB.py rename to dbutils/steady_db.py diff --git a/dbutils/SteadyPg.py b/dbutils/steady_pg.py similarity index 100% rename from dbutils/SteadyPg.py rename to dbutils/steady_pg.py diff --git a/Release.md b/release.md similarity index 100% rename from Release.md rename to release.md diff --git a/setup.py b/setup.py index 7e97f95..478fe8e 100755 --- a/setup.py +++ b/setup.py @@ -43,6 +43,6 @@ url='https://webwareforpython.github.io/DBUtils/', platforms=['any'], license='MIT License', - packages=['DBUtils', 'DBUtils.Examples', 'DBUtils.Tests'], - package_data={'DBUtils': ['Docs/*']} + packages=['dbutils'], + zip_safe=False, ) diff --git a/tests/TestPersistentDB.py b/tests/test_persistend_db.py similarity index 100% rename from tests/TestPersistentDB.py rename to tests/test_persistend_db.py diff --git a/tests/TestPersistentPg.py b/tests/test_persistend_pg.py similarity index 100% rename from tests/TestPersistentPg.py rename to tests/test_persistend_pg.py diff --git a/tests/TestPooledDB.py b/tests/test_pooled_db.py similarity index 100% rename from tests/TestPooledDB.py rename to tests/test_pooled_db.py diff --git a/tests/TestPooledPg.py b/tests/test_pooled_pg.py similarity index 100% rename from tests/TestPooledPg.py rename to tests/test_pooled_pg.py diff --git a/tests/TestSimplePooledDB.py b/tests/test_simple_pooled_db.py similarity index 100% rename from tests/TestSimplePooledDB.py rename to tests/test_simple_pooled_db.py diff --git a/tests/TestSimplePooledPg.py b/tests/test_simple_pooled_pg.py similarity index 100% rename from tests/TestSimplePooledPg.py rename to tests/test_simple_pooled_pg.py diff --git a/tests/TestSteadyDB.py b/tests/test_steady_db.py similarity index 100% rename from tests/TestSteadyDB.py rename to tests/test_steady_db.py diff --git a/tests/TestSteadyPg.py b/tests/test_steady_pg.py similarity index 100% rename from tests/TestSteadyPg.py rename to tests/test_steady_pg.py diff --git a/tests/TestThreadingLocal.py b/tests/test_threading_local.py similarity index 100% rename from tests/TestThreadingLocal.py rename to tests/test_threading_local.py diff --git a/tox.ini b/tox.ini index cfc48a4..78dd8dc 100644 --- a/tox.ini +++ b/tox.ini @@ -1,9 +1,6 @@ [tox] envlist = py{27,35,36,37,38,39}, flake8 -[pytest] -python_files=Test*.py - [testenv] setenv = PYTHONPATH = {toxinidir} @@ -14,8 +11,8 @@ commands = [testenv:flake8] basepython = - python + python3.8 deps = flake8 commands = - flake8 DBUtils + flake8 *.py dbutils From 1513377fd16de472325bd83cdd0216007e69bcf3 Mon Sep 17 00:00:00 2001 From: Christoph Zwerschke Date: Sat, 26 Sep 2020 18:01:47 +0200 Subject: [PATCH 05/90] Use the new lower-case module names everywhere Also use the bump2version tool instead of setversion.py. --- .bumpversion.cfg | 22 ++++ README.md | 2 +- dbutils/__init__.py | 14 +- dbutils/persistent_db.py | 7 +- dbutils/persistent_pg.py | 7 +- dbutils/pooled_db.py | 7 +- dbutils/pooled_pg.py | 7 +- dbutils/simple_pooled_db.py | 4 +- dbutils/simple_pooled_pg.py | 4 +- dbutils/steady_db.py | 4 +- dbutils/steady_pg.py | 4 +- docs/changelog.html | 7 +- docs/changelog.rst | 3 +- docs/main.de.html | 3 - docs/main.de.rst | 1 - docs/main.html | 3 - docs/main.rst | 1 - docs/make.py | 16 +-- setup.py | 2 +- setversion.py | 123 ------------------ tests/__init__.py | 2 +- tests/mock_pg.py | 4 +- ...persistend_db.py => test_persistent_db.py} | 122 +++++++++-------- ...persistend_pg.py => test_persistent_pg.py} | 112 ++++++++-------- tests/test_pooled_db.py | 68 +++++----- tests/test_pooled_pg.py | 34 +++-- tests/test_simple_pooled_db.py | 69 +++++----- tests/test_simple_pooled_pg.py | 49 ++++--- tests/test_steady_db.py | 56 ++++---- tests/test_steady_pg.py | 34 +++-- tests/test_threading_local.py | 68 +++++----- tox.ini | 2 +- 32 files changed, 350 insertions(+), 511 deletions(-) create mode 100644 .bumpversion.cfg delete mode 100755 setversion.py rename tests/{test_persistend_db.py => test_persistent_db.py} (74%) rename tests/{test_persistend_pg.py => test_persistent_pg.py} (64%) diff --git a/.bumpversion.cfg b/.bumpversion.cfg new file mode 100644 index 0000000..9eab400 --- /dev/null +++ b/.bumpversion.cfg @@ -0,0 +1,22 @@ +[bumpversion] +current_version = 2.0 + +[bumpversion:file:setup.py] +search = __version__ = '{current_version}' +replace = __version__ = '{new_version}' + +[bumpversion:file:dbutils/__init__.py] +search = __version__ = '{current_version}' +replace = __version__ = '{new_version}' + +[bumpversion:file:README.md] +search = The current version {current_version} +replace = The current version {new_version} + +[bumpversion:file:docs/main.rst] +search = :Version: {current_version} +search = :Version: {new_version} + +[bumpversion:file:docs/main.de.rst] +search = :Version: {current_version} +search = :Version: {new_version} diff --git a/README.md b/README.md index 481657f..3697d59 100644 --- a/README.md +++ b/README.md @@ -6,6 +6,6 @@ to a database that can be used in all kinds of multi-threaded environments like Webware for Python or other web application servers. The suite supports DB-API 2 compliant database interfaces and the classic PyGreSQL interface. -The current version of DBUtils supports Python versions 2.7 and 3.5 - 3.8. +The current version 2.0 of DBUtils supports Python versions 2.7 and 3.5 - 3.8. The DBUtils home page can be found here: https://webwareforpython.github.io/DBUtils/ diff --git a/dbutils/__init__.py b/dbutils/__init__.py index 7fd5939..adfdbf7 100644 --- a/dbutils/__init__.py +++ b/dbutils/__init__.py @@ -1,12 +1,8 @@ -# DBUtils package +# DBUtils main package __all__ = [ - 'SimplePooledPg', 'SteadyPg', 'PooledPg', 'PersistentPg', - 'SimplePooledDB', 'SteadyDB', 'PooledDB', 'PersistentDB' -] + '__version__', + 'simple_pooled_pg', 'steady_pg', 'pooled_pg', 'persistent_pg', + 'simple_pooled_db', 'steady_db', 'pooled_db', 'persistent_db'] -__version__ = '1.4' - - -def InstallInWebKit(appServer): - pass +__version__ = '2.0' diff --git a/dbutils/persistent_db.py b/dbutils/persistent_db.py index ae383d4..ac26c11 100644 --- a/dbutils/persistent_db.py +++ b/dbutils/persistent_db.py @@ -64,7 +64,7 @@ every connection to your local database 'mydb' to be reused 1000 times: import pgdb # import used DB-API 2 module - from DBUtils.PersistentDB import PersistentDB + from dbutils.persistent_db import PersistentDB persist = PersistentDB(pgdb, 1000, database='mydb') Once you have set up the generator with these parameters, you can @@ -111,9 +111,8 @@ """ -from DBUtils.SteadyDB import connect - -__version__ = '1.4' +from . import __version__ +from .steady_db import connect try: # Prefer the pure Python version of threading.local. diff --git a/dbutils/persistent_pg.py b/dbutils/persistent_pg.py index 08ea171..b14960e 100644 --- a/dbutils/persistent_pg.py +++ b/dbutils/persistent_pg.py @@ -54,7 +54,7 @@ For instance, if you want every connection to your local database 'mydb' to be reused 1000 times: - from DBUtils.PersistentPg import PersistentPg + from dbutils.persistent_pg import PersistentPg persist = PersistentPg(5, dbname='mydb') Once you have set up the generator with these parameters, you can @@ -102,9 +102,8 @@ """ -from DBUtils.SteadyPg import SteadyPgConnection - -__version__ = '1.4' +from . import __version__ +from .steady_pg import SteadyPgConnection try: # Prefer the pure Python version of threading.local. diff --git a/dbutils/pooled_db.py b/dbutils/pooled_db.py index 3336177..0b13c96 100644 --- a/dbutils/pooled_db.py +++ b/dbutils/pooled_db.py @@ -74,7 +74,7 @@ want a pool of at least five connections to your local database 'mydb': import pgdb # import used DB-API 2 module - from DBUtils.PooledDB import PooledDB + from dbutils.pooled_db import PooledDB pool = PooledDB(pgdb, 5, database='mydb') Once you have set up the connection pool you can request @@ -141,9 +141,8 @@ from threading import Condition -from DBUtils.SteadyDB import connect - -__version__ = '1.4' +from . import __version__ +from .steady_db import connect class PooledDBError(Exception): diff --git a/dbutils/pooled_pg.py b/dbutils/pooled_pg.py index c451dec..2f8b937 100644 --- a/dbutils/pooled_pg.py +++ b/dbutils/pooled_pg.py @@ -55,7 +55,7 @@ For instance, if you want a pool of at least five connections to your local database 'mydb': - from DBUtils.PooledPg import PooledPg + from dbutils.pooled_pg import PooledPg pool = PooledPg(5, dbname='mydb') Once you have set up the connection pool you can request @@ -113,9 +113,8 @@ except ImportError: # Python 3 from queue import Queue, Empty, Full -from DBUtils.SteadyPg import SteadyPgConnection - -__version__ = '1.4' +from . import __version__ +from .steady_pg import SteadyPgConnection class PooledPgError(Exception): diff --git a/dbutils/simple_pooled_db.py b/dbutils/simple_pooled_db.py index 3318163..3e1b406 100644 --- a/dbutils/simple_pooled_db.py +++ b/dbutils/simple_pooled_db.py @@ -26,7 +26,7 @@ to be cached in the pool and the connection parameters, e.g. import pgdb # import used DB-API 2 module - from DBUtils.SimplePooledDB import PooledDB + from dbutils.simple_pooled_db import PooledDB dbpool = PooledDB(pgdb, 5, host=..., database=..., user=..., ...) you can demand database connections from that pool, @@ -73,7 +73,7 @@ """ -__version__ = '1.4' +from . import __version__ class PooledDBError(Exception): diff --git a/dbutils/simple_pooled_pg.py b/dbutils/simple_pooled_pg.py index 84cd1a2..4927a35 100644 --- a/dbutils/simple_pooled_pg.py +++ b/dbutils/simple_pooled_pg.py @@ -26,7 +26,7 @@ number of connections to be cached in the pool and the connection parameters, e.g. - from DBUtils.SimplePooledPg import PooledPg + from dbutils.simple_pooled_pg import PooledPg dbpool = PooledPg(5, host=..., database=..., user=..., ...) you can demand database connections from that pool, @@ -70,7 +70,7 @@ from pg import DB as PgConnection -__version__ = '1.4' +from . import __version__ class PooledPgConnection: diff --git a/dbutils/steady_db.py b/dbutils/steady_db.py index 6ad6423..13918d6 100644 --- a/dbutils/steady_db.py +++ b/dbutils/steady_db.py @@ -58,7 +58,7 @@ without further notice. import pgdb # import used DB-API 2 module - from DBUtils.SteadyDB import connect + from dbutils.steady_db import connect db = connect(pgdb, 10000, ["set datestyle to german"], host=..., database=..., user=..., ...) ... @@ -92,7 +92,7 @@ import sys -__version__ = '1.4' +from . import __version__ try: baseint = (int, long) diff --git a/dbutils/steady_pg.py b/dbutils/steady_pg.py index 5c10be8..a75b025 100644 --- a/dbutils/steady_pg.py +++ b/dbutils/steady_pg.py @@ -45,7 +45,7 @@ database is lost or has been used too often, it will be automatically reset, without further notice. - from DBUtils.SteadyPg import SteadyPgConnection + from dbutils.steady_pg import SteadyPgConnection db = SteadyPgConnection(10000, ["set datestyle to german"], host=..., dbname=..., user=..., ...) ... @@ -72,7 +72,7 @@ from pg import DB as PgConnection -__version__ = '1.4' +from . import __version__ try: baseint = (int, long) diff --git a/docs/changelog.html b/docs/changelog.html index 1ecb86c..7db17cd 100644 --- a/docs/changelog.html +++ b/docs/changelog.html @@ -78,6 +78,7 @@

Changes:

  • The top-level packages and folders have been renamed to lower-case. Particularly, you need to import dbutils instead of DBUtils now.

  • The Webware Examples folder has been removed.

  • +
  • The internal naming conventions have been changed to comply with PEP8.

  • This changelog file has been created from the former release notes.

  • @@ -155,12 +156,6 @@

    Improvements:

    Bugfixes:

    -
    -

    System Message: WARNING/2 (changelog.rst, line 100)

    -

    Title underline too short.

    -
    Bugfixes:
    ---------
    -
    • Fixed propagation of error messages when the connection was lost.

    • Fixed an issue with the setoutputsize() cursor method.

    • diff --git a/docs/changelog.rst b/docs/changelog.rst index fb97129..bf41adf 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -18,6 +18,7 @@ Changes: * The top-level packages and folders have been renamed to lower-case. Particularly, you need to import ``dbutils`` instead of ``DBUtils`` now. * The Webware ``Examples`` folder has been removed. +* The internal naming conventions have been changed to comply with PEP8. * This changelog file has been created from the former release notes. 1.4 @@ -97,7 +98,7 @@ Improvements: connections are reset before being put back into the pool. Bugfixes: --------- +--------- * Fixed propagation of error messages when the connection was lost. * Fixed an issue with the ``setoutputsize()`` cursor method. diff --git a/docs/main.de.html b/docs/main.de.html index 10a3eef..b26431d 100644 --- a/docs/main.de.html +++ b/docs/main.de.html @@ -12,9 +12,6 @@

      Benutzeranleitung für DBUtils

      Version
      2.0
      -
      Released
      -

      09/26/20

      -
      Translations

      English | German

      diff --git a/docs/main.de.rst b/docs/main.de.rst index 00013ac..f0fda86 100644 --- a/docs/main.de.rst +++ b/docs/main.de.rst @@ -2,7 +2,6 @@ +++++++++++++++++++++++++++++ :Version: 2.0 -:Released: 09/26/20 :Translations: English_ | German .. _English: main.html diff --git a/docs/main.html b/docs/main.html index 9ec6f26..a6625bf 100644 --- a/docs/main.html +++ b/docs/main.html @@ -12,9 +12,6 @@

      DBUtils User's Guide

      Version
      2.0
      -
      Released
      -

      09/26/20

      -
      Translations

      English | German

      diff --git a/docs/main.rst b/docs/main.rst index edbfd31..43b7905 100644 --- a/docs/main.rst +++ b/docs/main.rst @@ -2,7 +2,6 @@ ++++++++++++++++++++ :Version: 2.0 -:Released: 09/26/20 :Translations: English | German_ .. _German: main.de.html diff --git a/docs/make.py b/docs/make.py index fb82e88..f2153df 100755 --- a/docs/make.py +++ b/docs/make.py @@ -5,7 +5,7 @@ from __future__ import print_function from glob import glob -from os.path import splitext, join +from os.path import splitext from docutils.core import publish_file print("Creating the documentation...") @@ -25,13 +25,11 @@ with open(rst_file, encoding='utf-8-sig') as source: with open(html_file, 'w', encoding='utf-8') as destination: publish_file(writer_name='html5', - source=source, destination=destination, - settings_overrides = dict( - stylesheet_path='Doc.css', - embed_stylesheet=False, - toc_backlinks=False, - language_code=lang - ) - ) + source=source, destination=destination, + settings_overrides=dict( + stylesheet_path='Doc.css', + embed_stylesheet=False, + toc_backlinks=False, + language_code=lang)) print("Done.") diff --git a/setup.py b/setup.py index 478fe8e..5f54dfe 100755 --- a/setup.py +++ b/setup.py @@ -10,7 +10,7 @@ warnings.filterwarnings('ignore', 'Unknown distribution option') -__version__ = '1.4' +__version__ = '2.0' readme = open('README.md').read() diff --git a/setversion.py b/setversion.py deleted file mode 100755 index 2164a07..0000000 --- a/setversion.py +++ /dev/null @@ -1,123 +0,0 @@ -#!/usr/bin/env python - -"""Set version. - -This script sets the DBUtils version number information -consistently in all files of the distribution. - -""" - -from __future__ import print_function - -import os -import sys -import re -from glob import glob - -# Version format is (Major, Minor, Sub, Alpha/Beta/etc) -# The Sub is optional, and if 0 is not returned. -# Examples: (0, 8, 1, 'b1'), (0, 8, 2) or (0, 9, 0, 'rc1') -# releaseDate format should be 'MM/DD/YY'. - -# Update this to change the current version and release date: -# version = ('X', 'Y', 0) -version = (1, 4, 0) -# releaseDate = '@@/@@/@@' -releaseDate = '09/26/20' - -# Verbose output (output unchanged files also): -verbose = False - -path = os.path.dirname(os.path.abspath(sys.argv[0])) -sys.path.append(path) -os.chdir(path) -print("Setversion", path) - - -def versionString(version): - """Create version string. - - For a sequence containing version information such as (2, 0, 0, 'pre'), - this returns a printable string such as '2.0pre'. - The micro version number is only excluded from the string if it is zero. - - """ - ver = list(map(str, version)) - numbers, rest = ver[:2 if ver[2] == '0' else 3], ver[3:] - return '.'.join(numbers) + '-'.join(rest) - - -versionString = versionString(version) - -if versionString == 'X.Y': - print("Please set the version.") - sys.exit(1) -if releaseDate == '@@/@@/@@': - print("Please set the release date.") - sys.exit(1) - - -class Replacer: - """Class to handle substitutions in a file.""" - - def __init__(self, *args): - self._subs = list(args) - - def add(self, search, replace): - self._subs.append((re.compile(search, re.M), replace)) - - def replaceInStr(self, data): - for search, replace in self._subs: - data = re.sub(search, replace, data) - return data - - def replaceInFile(self, filename): - data = open(filename).read() - newData = self.replaceInStr(data) - if data == newData: - if verbose: - print("Unchanged", filename) - else: - print("Updating", filename) - open(filename, 'w').write(newData) - - def replaceGlob(self, pattern): - for file in glob(pattern): - if os.path.exists(file): - self.replaceInFile(file) - - -pyReplace = Replacer() -pyReplace.add(r"(__version__\s*=\s*)'.*'", r"\g<1>%s" % repr(versionString)) - -propReplace = Replacer() -propReplace.add(r"(version\s*=\s*).*", r"\g<1>%s" % repr(version)) -propReplace.add(r"(releaseDate\s*=\s*).*", r"\g<1>%s" % repr(releaseDate)) - -htmlReplace = Replacer() -htmlReplace.add( - r"[^<]*", - r" %s " % versionString) -htmlReplace.add( - r"[^<]*", - r" %s " % releaseDate) - -rstReplace = Replacer() -rstReplace.add( - r"^:(.+)?: (X|\d+)\.(Y|\d+)(\.\d+)?$", r":\1: %s" % versionString) -rstReplace.add( - r"^:(.+)?: (@|\d){2}/(@|\d){2}/(@|\d){2}$", r":\1: %s" % releaseDate) - -# Replace in Python files: -pyReplace.replaceGlob('*.py') -pyReplace.replaceGlob('DBUtils/*.py') -pyReplace.replaceGlob('DBUtils/*/*.py') - -# Replace in Properties files: -propReplace.replaceGlob('DBUtils/Properties.py') - -# Replace in existing HTML: -htmlReplace.replaceGlob('DBUtils/Docs/*.html') - -# Replace in reStructuredText files: -rstReplace.replaceGlob('DBUtils/Docs/*.rst') diff --git a/tests/__init__.py b/tests/__init__.py index 3195867..ec99602 100644 --- a/tests/__init__.py +++ b/tests/__init__.py @@ -1 +1 @@ -# DBUtils Tests +# DBUtils tests diff --git a/tests/mock_pg.py b/tests/mock_pg.py index 48fe998..7b4fcdc 100644 --- a/tests/mock_pg.py +++ b/tests/mock_pg.py @@ -22,10 +22,10 @@ class ProgrammingError(DatabaseError): def connect(*args, **kwargs): - return pgConnection(*args, **kwargs) + return PgConnection(*args, **kwargs) -class pgConnection: +class PgConnection: """The underlying pg API connection class.""" def __init__(self, dbname=None, user=None): diff --git a/tests/test_persistend_db.py b/tests/test_persistent_db.py similarity index 74% rename from tests/test_persistend_db.py rename to tests/test_persistent_db.py index 6f7ec53..bf1f8c6 100644 --- a/tests/test_persistend_db.py +++ b/tests/test_persistent_db.py @@ -13,11 +13,9 @@ import unittest -import DBUtils.Tests.mock_db as dbapi +from . import mock_db as dbapi -from DBUtils.PersistentDB import PersistentDB, local - -__version__ = '1.4' +from dbutils.persistent_db import PersistentDB, local class TestPersistentDB(unittest.TestCase): @@ -25,19 +23,17 @@ class TestPersistentDB(unittest.TestCase): def setUp(self): dbapi.threadsafety = 1 - def test0_CheckVersion(self): - from DBUtils import __version__ as DBUtilsVersion - self.assertEqual(DBUtilsVersion, __version__) - from DBUtils.PersistentDB import __version__ as PersistentDBVersion - self.assertEqual(PersistentDBVersion, __version__) + def test_version(self): + from dbutils import __version__, persistent_db + self.assertEqual(persistent_db.__version__, __version__) self.assertEqual(PersistentDB.version, __version__) - def test1_NoThreadsafety(self): - from DBUtils.PersistentDB import NotSupportedError + def test_no_threadsafety(self): + from dbutils.persistent_db import NotSupportedError for dbapi.threadsafety in (None, 0): self.assertRaises(NotSupportedError, PersistentDB, dbapi) - def test2_Close(self): + def test_close(self): for closeable in (False, True): persist = PersistentDB(dbapi, closeable=closeable) db = persist.connection() @@ -51,7 +47,7 @@ def test2_Close(self): db._close() self.assertFalse(db._con.valid) - def test3_Connection(self): + def test_connection(self): persist = PersistentDB(dbapi) db = persist.connection() db_con = db._con @@ -65,26 +61,26 @@ def test3_Connection(self): db2.close() db.close() - def test4_Threads(self): - numThreads = 3 + def test_threads(self): + num_threads = 3 persist = PersistentDB(dbapi, closeable=True) try: from queue import Queue, Empty except ImportError: # Python 2 from Queue import Queue, Empty - queryQueue, resultQueue = [], [] - for i in range(numThreads): - queryQueue.append(Queue(1)) - resultQueue.append(Queue(1)) + query_queue, result_queue = [], [] + for i in range(num_threads): + query_queue.append(Queue(1)) + result_queue.append(Queue(1)) - def runQueries(i): + def run_queries(i): this_db = persist.connection() while 1: try: try: - q = queryQueue[i].get(1, 1) + q = query_queue[i].get(1, 1) except TypeError: - q = queryQueue[i].get(1) + q = query_queue[i].get(1) except Empty: q = None if not q: @@ -105,82 +101,82 @@ def runQueries(i): cursor.close() r = '%d(%d): %s' % (i, db._usage, r) try: - resultQueue[i].put(r, 1, 1) + result_queue[i].put(r, 1, 1) except TypeError: - resultQueue[i].put(r, 1) + result_queue[i].put(r, 1) db.close() from threading import Thread threads = [] - for i in range(numThreads): - thread = Thread(target=runQueries, args=(i,)) + for i in range(num_threads): + thread = Thread(target=run_queries, args=(i,)) threads.append(thread) thread.start() - for i in range(numThreads): + for i in range(num_threads): try: - queryQueue[i].put('ping', 1, 1) + query_queue[i].put('ping', 1, 1) except TypeError: - queryQueue[i].put('ping', 1) - for i in range(numThreads): + query_queue[i].put('ping', 1) + for i in range(num_threads): try: - r = resultQueue[i].get(1, 1) + r = result_queue[i].get(1, 1) except TypeError: - r = resultQueue[i].get(1) + r = result_queue[i].get(1) self.assertEqual(r, '%d(0): ok - thread alive' % i) self.assertTrue(threads[i].is_alive()) - for i in range(numThreads): + for i in range(num_threads): for j in range(i + 1): try: - queryQueue[i].put('select test%d' % j, 1, 1) - r = resultQueue[i].get(1, 1) + query_queue[i].put('select test%d' % j, 1, 1) + r = result_queue[i].get(1, 1) except TypeError: - queryQueue[i].put('select test%d' % j, 1) - r = resultQueue[i].get(1) + query_queue[i].put('select test%d' % j, 1) + r = result_queue[i].get(1) self.assertEqual(r, '%d(%d): test%d' % (i, j + 1, j)) try: - queryQueue[1].put('select test4', 1, 1) + query_queue[1].put('select test4', 1, 1) except TypeError: - queryQueue[1].put('select test4', 1) + query_queue[1].put('select test4', 1) try: - r = resultQueue[1].get(1, 1) + r = result_queue[1].get(1, 1) except TypeError: - r = resultQueue[1].get(1) + r = result_queue[1].get(1) self.assertEqual(r, '1(3): test4') try: - queryQueue[1].put('close', 1, 1) - r = resultQueue[1].get(1, 1) + query_queue[1].put('close', 1, 1) + r = result_queue[1].get(1, 1) except TypeError: - queryQueue[1].put('close', 1) - r = resultQueue[1].get(1) + query_queue[1].put('close', 1) + r = result_queue[1].get(1) self.assertEqual(r, '1(3): ok - connection closed') for j in range(2): try: - queryQueue[1].put('select test%d' % j, 1, 1) - r = resultQueue[1].get(1, 1) + query_queue[1].put('select test%d' % j, 1, 1) + r = result_queue[1].get(1, 1) except TypeError: - queryQueue[1].put('select test%d' % j, 1) - r = resultQueue[1].get(1) + query_queue[1].put('select test%d' % j, 1) + r = result_queue[1].get(1) self.assertEqual(r, '1(%d): test%d' % (j + 1, j)) - for i in range(numThreads): + for i in range(num_threads): self.assertTrue(threads[i].is_alive()) try: - queryQueue[i].put('ping', 1, 1) + query_queue[i].put('ping', 1, 1) except TypeError: - queryQueue[i].put('ping', 1) - for i in range(numThreads): + query_queue[i].put('ping', 1) + for i in range(num_threads): try: - r = resultQueue[i].get(1, 1) + r = result_queue[i].get(1, 1) except TypeError: - r = resultQueue[i].get(1) + r = result_queue[i].get(1) self.assertEqual(r, '%d(%d): ok - thread alive' % (i, i + 1)) self.assertTrue(threads[i].is_alive()) - for i in range(numThreads): + for i in range(num_threads): try: - queryQueue[i].put(None, 1, 1) + query_queue[i].put(None, 1, 1) except TypeError: - queryQueue[i].put(None, 1) + query_queue[i].put(None, 1) - def test5_MaxUsage(self): + def test_maxusage(self): persist = PersistentDB(dbapi, 20) db = persist.connection() self.assertEqual(db._maxusage, 20) @@ -196,7 +192,7 @@ def test5_MaxUsage(self): self.assertEqual(db._con.num_uses, j) self.assertEqual(db._con.num_queries, j) - def test6_SetSession(self): + def test_setsession(self): persist = PersistentDB(dbapi, 3, ('set datestyle',)) db = persist.connection() self.assertEqual(db._maxusage, 3) @@ -214,7 +210,7 @@ def test6_SetSession(self): cursor.close() self.assertEqual(db._con.session, ['datestyle']) - def test7_ThreadLocal(self): + def test_threadlocal(self): persist = PersistentDB(dbapi) self.assertTrue(isinstance(persist.thread, local)) @@ -224,7 +220,7 @@ class threadlocal: persist = PersistentDB(dbapi, threadlocal=threadlocal) self.assertTrue(isinstance(persist.thread, threadlocal)) - def test8_PingCheck(self): + def test_ping_check(self): Connection = dbapi.Connection Connection.has_ping = True Connection.num_pings = 0 @@ -276,7 +272,7 @@ def test8_PingCheck(self): Connection.has_ping = False Connection.num_pings = 0 - def test9_FailedTransaction(self): + def test_failed_transaction(self): persist = PersistentDB(dbapi) db = persist.connection() cursor = db.cursor() diff --git a/tests/test_persistend_pg.py b/tests/test_persistent_pg.py similarity index 64% rename from tests/test_persistend_pg.py rename to tests/test_persistent_pg.py index f5ba411..bed067b 100644 --- a/tests/test_persistend_pg.py +++ b/tests/test_persistent_pg.py @@ -13,23 +13,19 @@ import unittest -import DBUtils.Tests.mock_pg as pg +from . import mock_pg as pg -from DBUtils.PersistentPg import PersistentPg - -__version__ = '1.4' +from dbutils.persistent_pg import PersistentPg class TestPersistentPg(unittest.TestCase): - def test0_CheckVersion(self): - from DBUtils import __version__ as DBUtilsVersion - self.assertEqual(DBUtilsVersion, __version__) - from DBUtils.PersistentPg import __version__ as PersistentPgVersion - self.assertEqual(PersistentPgVersion, __version__) + def test_version(self): + from dbutils import __version__, persistent_pg + self.assertEqual(persistent_pg.__version__, __version__) self.assertEqual(PersistentPg.version, __version__) - def test1_Close(self): + def test_close(self): for closeable in (False, True): persist = PersistentPg(closeable=closeable) db = persist.connection() @@ -45,26 +41,26 @@ def test1_Close(self): db._close() self.assertFalse(db._con.db and db._con.valid) - def test2_Threads(self): - numThreads = 3 + def test_threads(self): + num_threads = 3 persist = PersistentPg() try: from queue import Queue, Empty except ImportError: # Python 2 from Queue import Queue, Empty - queryQueue, resultQueue = [], [] - for i in range(numThreads): - queryQueue.append(Queue(1)) - resultQueue.append(Queue(1)) + query_queue, result_queue = [], [] + for i in range(num_threads): + query_queue.append(Queue(1)) + result_queue.append(Queue(1)) - def runQueries(i): + def run_queries(i): this_db = persist.connection().db while 1: try: try: - q = queryQueue[i].get(1, 1) + q = query_queue[i].get(1, 1) except TypeError: - q = queryQueue[i].get(1) + q = query_queue[i].get(1) except Empty: q = None if not q: @@ -82,80 +78,80 @@ def runQueries(i): r = db.query(q) r = '%d(%d): %s' % (i, db._usage, r) try: - resultQueue[i].put(r, 1, 1) + result_queue[i].put(r, 1, 1) except TypeError: - resultQueue[i].put(r, 1) + result_queue[i].put(r, 1) db.close() from threading import Thread threads = [] - for i in range(numThreads): - thread = Thread(target=runQueries, args=(i,)) + for i in range(num_threads): + thread = Thread(target=run_queries, args=(i,)) threads.append(thread) thread.start() - for i in range(numThreads): + for i in range(num_threads): try: - queryQueue[i].put('ping', 1, 1) + query_queue[i].put('ping', 1, 1) except TypeError: - queryQueue[i].put('ping', 1) - for i in range(numThreads): + query_queue[i].put('ping', 1) + for i in range(num_threads): try: - r = resultQueue[i].get(1, 1) + r = result_queue[i].get(1, 1) except TypeError: - r = resultQueue[i].get(1) + r = result_queue[i].get(1) self.assertEqual(r, '%d(0): ok - thread alive' % i) self.assertTrue(threads[i].is_alive()) - for i in range(numThreads): + for i in range(num_threads): for j in range(i + 1): try: - queryQueue[i].put('select test%d' % j, 1, 1) - r = resultQueue[i].get(1, 1) + query_queue[i].put('select test%d' % j, 1, 1) + r = result_queue[i].get(1, 1) except TypeError: - queryQueue[i].put('select test%d' % j, 1) - r = resultQueue[i].get(1) + query_queue[i].put('select test%d' % j, 1) + r = result_queue[i].get(1) self.assertEqual(r, '%d(%d): test%d' % (i, j + 1, j)) try: - queryQueue[1].put('select test4', 1, 1) - r = resultQueue[1].get(1, 1) + query_queue[1].put('select test4', 1, 1) + r = result_queue[1].get(1, 1) except TypeError: - queryQueue[1].put('select test4', 1) - r = resultQueue[1].get(1) + query_queue[1].put('select test4', 1) + r = result_queue[1].get(1) self.assertEqual(r, '1(3): test4') try: - queryQueue[1].put('close', 1, 1) - r = resultQueue[1].get(1, 1) + query_queue[1].put('close', 1, 1) + r = result_queue[1].get(1, 1) except TypeError: - queryQueue[1].put('close', 1) - r = resultQueue[1].get(1) + query_queue[1].put('close', 1) + r = result_queue[1].get(1) self.assertEqual(r, '1(3): ok - connection closed') for j in range(2): try: - queryQueue[1].put('select test%d' % j, 1, 1) - r = resultQueue[1].get(1, 1) + query_queue[1].put('select test%d' % j, 1, 1) + r = result_queue[1].get(1, 1) except TypeError: - queryQueue[1].put('select test%d' % j, 1) - r = resultQueue[1].get(1) + query_queue[1].put('select test%d' % j, 1) + r = result_queue[1].get(1) self.assertEqual(r, '1(%d): test%d' % (j + 1, j)) - for i in range(numThreads): + for i in range(num_threads): self.assertTrue(threads[i].is_alive()) try: - queryQueue[i].put('ping', 1, 1) + query_queue[i].put('ping', 1, 1) except TypeError: - queryQueue[i].put('ping', 1) - for i in range(numThreads): + query_queue[i].put('ping', 1) + for i in range(num_threads): try: - r = resultQueue[i].get(1, 1) + r = result_queue[i].get(1, 1) except TypeError: - r = resultQueue[i].get(1) + r = result_queue[i].get(1) self.assertEqual(r, '%d(%d): ok - thread alive' % (i, i + 1)) self.assertTrue(threads[i].is_alive()) - for i in range(numThreads): + for i in range(num_threads): try: - queryQueue[i].put(None, 1, 1) + query_queue[i].put(None, 1, 1) except TypeError: - queryQueue[i].put(None, 1) + query_queue[i].put(None, 1) - def test3_MaxUsage(self): + def test_maxusage(self): persist = PersistentPg(20) db = persist.connection() self.assertEqual(db._maxusage, 20) @@ -167,7 +163,7 @@ def test3_MaxUsage(self): self.assertEqual(db._usage, j) self.assertEqual(db.num_queries, j) - def test4_SetSession(self): + def test_setsession(self): persist = PersistentPg(3, ('set datestyle',)) db = persist.connection() self.assertEqual(db._maxusage, 3) @@ -179,7 +175,7 @@ def test4_SetSession(self): db.query('select test') self.assertEqual(db.db.session, ['datestyle']) - def test5_FailedTransaction(self): + def test_failed_transaction(self): persist = PersistentPg() db = persist.connection() db._con.close() diff --git a/tests/test_pooled_db.py b/tests/test_pooled_db.py index 04ee5b8..860b7f5 100644 --- a/tests/test_pooled_db.py +++ b/tests/test_pooled_db.py @@ -13,30 +13,26 @@ import unittest -import DBUtils.Tests.mock_db as dbapi +from . import mock_db as dbapi -from DBUtils.PooledDB import ( +from dbutils.pooled_db import ( PooledDB, SharedDBConnection, InvalidConnection, TooManyConnections) -__version__ = '1.4' - class TestPooledDB(unittest.TestCase): - def test00_CheckVersion(self): - from DBUtils import __version__ as DBUtilsVersion - self.assertEqual(DBUtilsVersion, __version__) - from DBUtils.PooledDB import __version__ as PooledDBVersion - self.assertEqual(PooledDBVersion, __version__) + def test_version(self): + from dbutils import __version__, pooled_db + self.assertEqual(pooled_db.__version__, __version__) self.assertEqual(PooledDB.version, __version__) - def test01_NoThreadsafety(self): - from DBUtils.PooledDB import NotSupportedError + def test_no_threadsafety(self): + from dbutils.pooled_db import NotSupportedError for threadsafety in (None, 0): dbapi.threadsafety = threadsafety self.assertRaises(NotSupportedError, PooledDB, dbapi) - def test02_Threadsafety(self): + def test_threadsafety(self): for threadsafety in (1, 2, 3): dbapi.threadsafety = threadsafety pool = PooledDB(dbapi, 0, 0, 1) @@ -48,7 +44,7 @@ def test02_Threadsafety(self): self.assertEqual(pool._maxshared, 0) self.assertFalse(hasattr(pool, '_shared_cache')) - def test03_CreateConnection(self): + def test_create_connection(self): for threadsafety in (1, 2): dbapi.threadsafety = threadsafety shareable = threadsafety > 1 @@ -67,7 +63,7 @@ def test03_CreateConnection(self): self.assertTrue(hasattr(pool, '_setsession')) self.assertIsNone(pool._setsession) con = pool._idle_cache[0] - from DBUtils.SteadyDB import SteadyDBConnection + from dbutils.steady_db import SteadyDBConnection self.assertTrue(isinstance(con, SteadyDBConnection)) self.assertTrue(hasattr(con, '_maxusage')) self.assertEqual(con._maxusage, 0) @@ -167,7 +163,7 @@ def test03_CreateConnection(self): self.assertEqual(con._maxusage, 3) self.assertEqual(con._setsession_sql, ('set datestyle',)) - def test04_CloseConnection(self): + def test_close_connection(self): for threadsafety in (1, 2): dbapi.threadsafety = threadsafety shareable = threadsafety > 1 @@ -189,7 +185,7 @@ def test04_CloseConnection(self): self.assertEqual(shared_con.shared, 1) self.assertTrue(hasattr(shared_con, 'con')) self.assertEqual(shared_con.con, con) - from DBUtils.SteadyDB import SteadyDBConnection + from dbutils.steady_db import SteadyDBConnection self.assertTrue(isinstance(con, SteadyDBConnection)) self.assertTrue(hasattr(con, '_con')) db_con = con._con @@ -247,7 +243,7 @@ def test04_CloseConnection(self): if shareable: self.assertEqual(len(pool._shared_cache), 0) - def test05_CloseAll(self): + def test_close_all(self): for threadsafety in (1, 2): dbapi.threadsafety = threadsafety shareable = threadsafety > 1 @@ -304,7 +300,7 @@ def close_shared(what=closed): del cache self.assertEqual(closed, ['idle', 'shared']) - def test06_ShareableConnection(self): + def test_shareable_connection(self): for threadsafety in (1, 2): dbapi.threadsafety = threadsafety shareable = threadsafety > 1 @@ -394,7 +390,7 @@ def test06_ShareableConnection(self): else: self.assertEqual(len(pool._idle_cache), 3) - def test08_MinMaxCached(self): + def test_min_max_cached(self): for threadsafety in (1, 2): dbapi.threadsafety = threadsafety shareable = threadsafety > 1 @@ -475,7 +471,7 @@ def test08_MinMaxCached(self): if shareable: self.assertEqual(len(pool._shared_cache), 0) - def test08_MaxShared(self): + def test_max_shared(self): for threadsafety in (1, 2): dbapi.threadsafety = threadsafety shareable = threadsafety > 1 @@ -514,7 +510,7 @@ def test08_MaxShared(self): if shareable: self.assertEqual(len(pool._shared_cache), 7) - def test09_SortShared(self): + def test_sort_shared(self): dbapi.threadsafety = 2 pool = PooledDB(dbapi, 0, 4, 4) cache = [] @@ -533,7 +529,7 @@ def test09_SortShared(self): db = pool.connection() self.assertIs(db._con, cache[3]._con) - def test10_EquallyShared(self): + def test_equally_shared(self): for threadsafety in (1, 2): dbapi.threadsafety = threadsafety shareable = threadsafety > 1 @@ -568,7 +564,7 @@ def test10_EquallyShared(self): if shareable: self.assertEqual(len(pool._shared_cache), 0) - def test11_ManyShared(self): + def test_many_shared(self): for threadsafety in (1, 2): dbapi.threadsafety = threadsafety shareable = threadsafety > 1 @@ -619,7 +615,7 @@ def test11_ManyShared(self): else: self.assertEqual(len(pool._idle_cache), 35) - def test12_Rollback(self): + def test_rollback(self): for threadsafety in (1, 2): dbapi.threadsafety = threadsafety pool = PooledDB(dbapi, 0, 1) @@ -651,7 +647,7 @@ def test12_Rollback(self): 'doit1', 'commit', 'dont1', 'rollback', 'doit2', 'commit', 'rollback']) - def test13_MaxConnections(self): + def test_maxconnections(self): for threadsafety in (1, 2): dbapi.threadsafety = threadsafety shareable = threadsafety > 1 @@ -856,7 +852,7 @@ def connection(): session, ['rollback', 'rollback', 'thread', 'rollback']) del db - def test14_MaxUsage(self): + def test_maxusage(self): for threadsafety in (1, 2): dbapi.threadsafety = threadsafety for maxusage in (0, 3, 7): @@ -891,7 +887,7 @@ def test14_MaxUsage(self): self.assertEqual(db._con._con.num_uses, j + 1) self.assertEqual(db._con._con.num_queries, j) - def test15_SetSession(self): + def test_setsession(self): for threadsafety in (1, 2): dbapi.threadsafety = threadsafety setsession = ('set time zone', 'set datestyle') @@ -920,7 +916,7 @@ def test15_SetSession(self): self.assertEqual( db._con._con.session, ['time zone', 'datestyle', 'test2']) - def test16_OneThreadTwoConnections(self): + def test_one_thread_two_connections(self): for threadsafety in (1, 2): dbapi.threadsafety = threadsafety shareable = threadsafety > 1 @@ -977,7 +973,7 @@ def test16_OneThreadTwoConnections(self): self.assertNotEqual(db1, db2) self.assertNotEqual(db1._con, db2._con) - def test17_ThreeThreadsTwoConnections(self): + def test_tnree_threads_two_connections(self): for threadsafety in (1, 2): dbapi.threadsafety = threadsafety pool = PooledDB(dbapi, 2, 2, 0, 2, True) @@ -1039,7 +1035,7 @@ def connection(): self.assertNotEqual(db1._con, db2._con) self.assertEqual(db1._con, db1_con) - def test18_PingCheck(self): + def test_ping_check(self): Connection = dbapi.Connection Connection.has_ping = True Connection.num_pings = 0 @@ -1107,7 +1103,7 @@ def test18_PingCheck(self): Connection.has_ping = False Connection.num_pings = 0 - def test19_FailedTransaction(self): + def test_failed_transaction(self): dbapi.threadsafety = 2 pool = PooledDB(dbapi, 0, 1, 1) db = pool.connection() @@ -1136,7 +1132,7 @@ def test19_FailedTransaction(self): db._con._con.close() cursor.execute('select test') - def test20_SharedInTransaction(self): + def test_shared_in_transaction(self): dbapi.threadsafety = 2 pool = PooledDB(dbapi, 0, 1, 1) db = pool.connection() @@ -1164,7 +1160,7 @@ def test20_SharedInTransaction(self): db = pool.connection() self.assertIs(db._con, db1._con) - def test21_ResetTransaction(self): + def test_reset_transaction(self): pool = PooledDB(dbapi, 1, 1, 0) db = pool.connection() db.begin() @@ -1189,13 +1185,13 @@ def test21_ResetTransaction(self): class TestSharedDBConnection(unittest.TestCase): - def test01_CreateConnection(self): + def test_create_connection(self): db_con = dbapi.connect() con = SharedDBConnection(db_con) self.assertEqual(con.con, db_con) self.assertEqual(con.shared, 1) - def test01_ShareAndUnshare(self): + def test_share_and_unshare(self): con = SharedDBConnection(dbapi.connect()) self.assertEqual(con.shared, 1) con.share() @@ -1207,7 +1203,7 @@ def test01_ShareAndUnshare(self): con.unshare() self.assertEqual(con.shared, 1) - def test02_Comparison(self): + def test_comparison(self): con1 = SharedDBConnection(dbapi.connect()) con1.con._transaction = False con2 = SharedDBConnection(dbapi.connect()) diff --git a/tests/test_pooled_pg.py b/tests/test_pooled_pg.py index cd4103b..0379693 100644 --- a/tests/test_pooled_pg.py +++ b/tests/test_pooled_pg.py @@ -13,23 +13,19 @@ import unittest -import DBUtils.Tests.mock_pg # noqa +from . import mock_pg # noqa -from DBUtils.PooledPg import PooledPg, InvalidConnection - -__version__ = '1.4' +from dbutils.pooled_pg import PooledPg, InvalidConnection class TestPooledPg(unittest.TestCase): - def test0_CheckVersion(self): - from DBUtils import __version__ as DBUtilsVersion - self.assertEqual(DBUtilsVersion, __version__) - from DBUtils.PooledPg import __version__ as PooledPgVersion - self.assertEqual(PooledPgVersion, __version__) + def test_version(self): + from dbutils import __version__, pooled_pg + self.assertEqual(pooled_pg.__version__, __version__) self.assertEqual(PooledPg.version, __version__) - def test1_CreateConnection(self): + def test_create_connection(self): pool = PooledPg( 1, 1, 0, False, None, None, False, 'PooledPgTestDB', user='PooledPgTestUser') @@ -43,7 +39,7 @@ def test1_CreateConnection(self): self.assertFalse(pool._reset) db_con = pool._cache.get(0) pool._cache.put(db_con, 0) - from DBUtils.SteadyPg import SteadyPgConnection + from dbutils.steady_pg import SteadyPgConnection self.assertTrue(isinstance(db_con, SteadyPgConnection)) db = pool.connection() self.assertEqual(pool._cache.qsize(), 0) @@ -77,14 +73,14 @@ def test1_CreateConnection(self): self.assertEqual(db._maxusage, 3) self.assertEqual(db._setsession_sql, ('set datestyle',)) - def test2_CloseConnection(self): + def test_close_connection(self): pool = PooledPg( 0, 1, 0, False, None, None, False, 'PooledPgTestDB', user='PooledPgTestUser') db = pool.connection() self.assertTrue(hasattr(db, '_con')) db_con = db._con - from DBUtils.SteadyPg import SteadyPgConnection + from dbutils.steady_pg import SteadyPgConnection self.assertTrue(isinstance(db_con, SteadyPgConnection)) self.assertTrue(hasattr(pool, '_cache')) self.assertEqual(pool._cache.qsize(), 0) @@ -105,7 +101,7 @@ def test2_CloseConnection(self): self.assertEqual(pool._cache.qsize(), 1) self.assertEqual(pool._cache.get(0), db_con) - def test3_MinMaxCached(self): + def test_min_max_cached(self): pool = PooledPg(3) self.assertTrue(hasattr(pool, '_cache')) self.assertEqual(pool._cache.qsize(), 3) @@ -151,8 +147,8 @@ def test3_MinMaxCached(self): cache.pop().close() self.assertEqual(pool._cache.qsize(), 5) - def test4_MaxConnections(self): - from DBUtils.PooledPg import TooManyConnections + def test_max_connections(self): + from dbutils.pooled_pg import TooManyConnections pool = PooledPg(1, 2, 3) self.assertEqual(pool._cache.qsize(), 1) cache = [pool.connection() for i in range(3)] @@ -205,7 +201,7 @@ def connection(): self.assertEqual(session, ['thread']) del db - def test5_OneThreadTwoConnections(self): + def test_one_thread_two_connections(self): pool = PooledPg(2) db1 = pool.connection() for i in range(5): @@ -228,7 +224,7 @@ def test5_OneThreadTwoConnections(self): db2.query('select test') self.assertEqual(db2.num_queries, 8) - def test6_ThreeThreadsTwoConnections(self): + def test_three_threads_two_connections(self): pool = PooledPg(2, 2, 2, True) try: from queue import Queue, Empty @@ -268,7 +264,7 @@ def connection(): self.assertNotEqual(db1._con, db2._con) self.assertEqual(db1._con, db1_con) - def test7_ResetTransaction(self): + def test_reset_transaction(self): pool = PooledPg(1) db = pool.connection() db.begin() diff --git a/tests/test_simple_pooled_db.py b/tests/test_simple_pooled_db.py index 28d2764..3c6ede1 100644 --- a/tests/test_simple_pooled_db.py +++ b/tests/test_simple_pooled_db.py @@ -14,49 +14,37 @@ import unittest -import DBUtils.Tests.mock_db as dbapi +from . import mock_db as dbapi -from DBUtils import SimplePooledDB - -__version__ = '1.4' - - -def versionString(version): - """Create version string.""" - ver = [str(v) for v in version] - numbers, rest = ver[:2 if ver[2] == '0' else 3], ver[3:] - return '.'.join(numbers) + '-'.join(rest) +from dbutils import simple_pooled_db class TestSimplePooledDB(unittest.TestCase): - def my_dbpool(self, mythreadsafety, maxConnections): + def my_db_pool(self, mythreadsafety, maxConnections): threadsafety = dbapi.threadsafety dbapi.threadsafety = mythreadsafety try: - return SimplePooledDB.PooledDB( + return simple_pooled_db.PooledDB( dbapi, maxConnections, 'SimplePooledDBTestDB', 'SimplePooledDBTestUser') finally: dbapi.threadsafety = threadsafety - def test0_check_version(self): - from DBUtils import __version__ as DBUtilsVersion - self.assertEqual(DBUtilsVersion, __version__) - from DBUtils.Properties import version - self.assertEqual(versionString(version), __version__) - self.assertEqual(SimplePooledDB.__version__, __version__) - self.assertEqual(SimplePooledDB.PooledDB.version, __version__) + def test_version(self): + from dbutils import __version__ + self.assertEqual(simple_pooled_db.__version__, __version__) + self.assertEqual(simple_pooled_db.PooledDB.version, __version__) - def test1_no_threadsafety(self): + def test_no_threadsafety(self): for threadsafety in (None, -1, 0, 4): self.assertRaises( - SimplePooledDB.NotSupportedError, - self.my_dbpool, threadsafety, 1) + simple_pooled_db.NotSupportedError, + self.my_db_pool, threadsafety, 1) - def test2_create_connection(self): + def test_create_connection(self): for threadsafety in (1, 2, 3): - dbpool = self.my_dbpool(threadsafety, 1) + dbpool = self.my_db_pool(threadsafety, 1) db = dbpool.connection() self.assertTrue(hasattr(db, 'cursor')) self.assertTrue(hasattr(db, 'open_cursors')) @@ -66,41 +54,44 @@ def test2_create_connection(self): self.assertTrue(hasattr(db, 'user')) self.assertEqual(db.user, 'SimplePooledDBTestUser') cursor = db.cursor() + self.assertIsNotNone(cursor) self.assertEqual(db.open_cursors, 1) del cursor - def test3_close_connection(self): + def test_close_connection(self): for threadsafety in (1, 2, 3): - dbpool = self.my_dbpool(threadsafety, 1) - db = dbpool.connection() + db_pool = self.my_db_pool(threadsafety, 1) + db = db_pool.connection() self.assertEqual(db.open_cursors, 0) cursor1 = db.cursor() + self.assertIsNotNone(cursor1) self.assertEqual(db.open_cursors, 1) db.close() self.assertFalse(hasattr(db, 'open_cursors')) - db = dbpool.connection() + db = db_pool.connection() self.assertTrue(hasattr(db, 'database')) self.assertEqual(db.database, 'SimplePooledDBTestDB') self.assertTrue(hasattr(db, 'user')) self.assertEqual(db.user, 'SimplePooledDBTestUser') self.assertEqual(db.open_cursors, 1) cursor2 = db.cursor() + self.assertIsNotNone(cursor2) self.assertEqual(db.open_cursors, 2) del cursor2 del cursor1 - def test4_two_connections(self): + def test_two_connections(self): for threadsafety in (1, 2, 3): - dbpool = self.my_dbpool(threadsafety, 2) - db1 = dbpool.connection() + db_pool = self.my_db_pool(threadsafety, 2) + db1 = db_pool.connection() cursors1 = [db1.cursor() for i in range(5)] - db2 = dbpool.connection() + db2 = db_pool.connection() self.assertNotEqual(db1, db2) cursors2 = [db2.cursor() for i in range(7)] self.assertEqual(db1.open_cursors, 5) self.assertEqual(db2.open_cursors, 7) db1.close() - db1 = dbpool.connection() + db1 = db_pool.connection() self.assertNotEqual(db1, db2) self.assertTrue(hasattr(db1, 'cursor')) for i in range(3): @@ -111,8 +102,8 @@ def test4_two_connections(self): del cursors2 del cursors1 - def test5_threadsafety_1(self): - dbpool = self.my_dbpool(1, 2) + def test_threadsafety_1(self): + db_pool = self.my_db_pool(1, 2) try: from queue import Queue, Empty except ImportError: # Python 2 @@ -120,7 +111,7 @@ def test5_threadsafety_1(self): queue = Queue(3) def connection(): - queue.put(dbpool.connection()) + queue.put(db_pool.connection()) from threading import Thread threads = [Thread(target=connection).start() for i in range(3)] @@ -145,9 +136,9 @@ def connection(): self.assertNotEqual(db1, db3) self.assertNotEqual(db1._con, db3._con) - def test6_threadsafety_2(self): + def test_threadsafety_2(self): for threadsafety in (2, 3): - dbpool = self.my_dbpool(threadsafety, 2) + dbpool = self.my_db_pool(threadsafety, 2) db1 = dbpool.connection() db2 = dbpool.connection() cursors = [dbpool.connection().cursor() for i in range(100)] diff --git a/tests/test_simple_pooled_pg.py b/tests/test_simple_pooled_pg.py index 7ff7690..251fd72 100644 --- a/tests/test_simple_pooled_pg.py +++ b/tests/test_simple_pooled_pg.py @@ -13,28 +13,25 @@ import unittest -import DBUtils.Tests.mock_pg # noqa +from . import mock_pg # noqa -from DBUtils import SimplePooledPg - -__version__ = '1.4' +from dbutils import simple_pooled_pg class TestSimplePooledPg(unittest.TestCase): - def my_dbpool(self, maxConnections): - return SimplePooledPg.PooledPg( + def my_db_pool(self, maxConnections): + return simple_pooled_pg.PooledPg( maxConnections, 'SimplePooledPgTestDB', 'SimplePooledPgTestUser') - def test0_check_version(self): - from DBUtils import __version__ as DBUtilsVersion - self.assertEqual(DBUtilsVersion, __version__) - self.assertEqual(SimplePooledPg.__version__, __version__) - self.assertEqual(SimplePooledPg.PooledPg.version, __version__) + def test_version(self): + from dbutils import __version__ + self.assertEqual(simple_pooled_pg.__version__, __version__) + self.assertEqual(simple_pooled_pg.PooledPg.version, __version__) - def test1_create_connection(self): - dbpool = self.my_dbpool(1) - db = dbpool.connection() + def test_create_connection(self): + db_pool = self.my_db_pool(1) + db = db_pool.connection() self.assertTrue(hasattr(db, 'query')) self.assertTrue(hasattr(db, 'num_queries')) self.assertEqual(db.num_queries, 0) @@ -45,15 +42,15 @@ def test1_create_connection(self): db.query('select 1') self.assertEqual(db.num_queries, 1) - def test2_close_connection(self): - dbpool = self.my_dbpool(1) - db = dbpool.connection() + def test_close_connection(self): + db_pool = self.my_db_pool(1) + db = db_pool.connection() self.assertEqual(db.num_queries, 0) db.query('select 1') self.assertEqual(db.num_queries, 1) db.close() self.assertFalse(hasattr(db, 'num_queries')) - db = dbpool.connection() + db = db_pool.connection() self.assertTrue(hasattr(db, 'dbname')) self.assertEqual(db.dbname, 'SimplePooledPgTestDB') self.assertTrue(hasattr(db, 'user')) @@ -62,12 +59,12 @@ def test2_close_connection(self): db.query('select 1') self.assertEqual(db.num_queries, 2) - def test3_two_connections(self): - dbpool = self.my_dbpool(2) - db1 = dbpool.connection() + def test_two_connections(self): + db_pool = self.my_db_pool(2) + db1 = db_pool.connection() for i in range(5): db1.query('select 1') - db2 = dbpool.connection() + db2 = db_pool.connection() self.assertNotEqual(db1, db2) self.assertNotEqual(db1._con, db2._con) for i in range(7): @@ -75,7 +72,7 @@ def test3_two_connections(self): self.assertEqual(db1.num_queries, 5) self.assertEqual(db2.num_queries, 7) db1.close() - db1 = dbpool.connection() + db1 = db_pool.connection() self.assertNotEqual(db1, db2) self.assertNotEqual(db1._con, db2._con) self.assertTrue(hasattr(db1, 'query')) @@ -85,8 +82,8 @@ def test3_two_connections(self): db2.query('select 1') self.assertEqual(db2.num_queries, 8) - def test4_threads(self): - dbpool = self.my_dbpool(2) + def test_threads(self): + db_pool = self.my_db_pool(2) try: from queue import Queue, Empty except ImportError: # Python 2 @@ -94,7 +91,7 @@ def test4_threads(self): queue = Queue(3) def connection(): - queue.put(dbpool.connection()) + queue.put(db_pool.connection()) from threading import Thread threads = [Thread(target=connection).start() for i in range(3)] diff --git a/tests/test_steady_db.py b/tests/test_steady_db.py index f9c7d15..79342a6 100644 --- a/tests/test_steady_db.py +++ b/tests/test_steady_db.py @@ -12,24 +12,20 @@ import unittest -import DBUtils.Tests.mock_db as dbapi +from . import mock_db as dbapi -from DBUtils.SteadyDB import ( +from dbutils.steady_db import ( connect as SteadyDBconnect, SteadyDBConnection, SteadyDBCursor) -__version__ = '1.4' - class TestSteadyDB(unittest.TestCase): - def test00_CheckVersion(self): - from DBUtils import __version__ as DBUtilsVersion - self.assertEqual(DBUtilsVersion, __version__) - from DBUtils.SteadyDB import __version__ as SteadyDBVersion - self.assertEqual(SteadyDBVersion, __version__) - self.assertEqual(SteadyDBConnection.version, __version__) + def test_version(self): + from dbutils import __version__, steady_db + self.assertEqual(steady_db.__version__, __version__) + self.assertEqual(steady_db.SteadyDBConnection.version, __version__) - def test01_MockedConnection(self): + def test_mocked_connection(self): db = dbapi.connect( 'SteadyDBTestDB', user='SteadyDBTestUser') db.__class__.has_ping = False @@ -101,7 +97,7 @@ def test01_MockedConnection(self): db.__class__.has_ping = False db.__class__.num_pings = 0 - def test02_BrokenConnection(self): + def test_broken_connection(self): self.assertRaises(TypeError, SteadyDBConnection, None) self.assertRaises(TypeError, SteadyDBCursor, None) db = SteadyDBconnect(dbapi, database='ok') @@ -119,7 +115,7 @@ def test02_BrokenConnection(self): cursor.close() self.assertRaises(dbapi.OperationalError, db.cursor, 'error') - def test03_Close(self): + def test_close(self): for closeable in (False, True): db = SteadyDBconnect(dbapi, closeable=closeable) self.assertTrue(db._con.valid) @@ -132,7 +128,7 @@ def test03_Close(self): db._close() self.assertFalse(db._con.valid) - def test04_Connection(self): + def test_connection(self): db = SteadyDBconnect( dbapi, 0, None, None, None, True, 'SteadyDBTestDB', user='SteadyDBTestUser') @@ -249,7 +245,7 @@ def test04_Connection(self): self.assertEqual( db._con.session, ['doit', 'commit', 'dont', 'rollback']) - def test05_ConnectionContextHandler(self): + def test_connection_context_handler(self): db = SteadyDBconnect( dbapi, 0, None, None, None, True, 'SteadyDBTestDB', user='SteadyDBTestUser') @@ -267,7 +263,7 @@ def test05_ConnectionContextHandler(self): self.assertTrue(error) self.assertEqual(db._con.session, ['commit', 'rollback']) - def test06_CursorContextHandler(self): + def test_cursor_context_handler(self): db = SteadyDBconnect( dbapi, 0, None, None, None, True, 'SteadyDBTestDB', user='SteadyDBTestUser') @@ -278,7 +274,7 @@ def test06_CursorContextHandler(self): self.assertEqual(cursor.fetchone(), 'test') self.assertEqual(db._con.open_cursors, 0) - def test07_ConnectionCreatorFunction(self): + def test_connection_creator_function(self): db1 = SteadyDBconnect( dbapi, 0, None, None, None, True, 'SteadyDBTestDB', user='SteadyDBTestUser') @@ -293,7 +289,7 @@ def test07_ConnectionCreatorFunction(self): db2.close() db1.close() - def test08_ConnectionMaxUsage(self): + def test_connection_maxusage(self): db = SteadyDBconnect(dbapi, 10) cursor = db.cursor() for i in range(100): @@ -343,7 +339,7 @@ def test08_ConnectionMaxUsage(self): self.assertEqual(db._con.num_uses, 1) self.assertEqual(db._con.num_queries, 1) - def test09_ConnectionSetSession(self): + def test_connection_setsession(self): db = SteadyDBconnect(dbapi, 3, ('set time zone', 'set datestyle')) self.assertTrue(hasattr(db, '_usage')) self.assertEqual(db._usage, 0) @@ -401,7 +397,7 @@ def test09_ConnectionSetSession(self): self.assertEqual(db._con.num_queries, 1) self.assertEqual(db._con.session, ['time zone', 'datestyle']) - def test10_ConnectionFailures(self): + def test_connection_failures(self): db = SteadyDBconnect(dbapi) db.close() db.cursor() @@ -416,7 +412,7 @@ def test10_ConnectionFailures(self): db.close() db.cursor() - def test11_ConnectionFailureError(self): + def test_connection_failure_error(self): db = SteadyDBconnect(dbapi) cursor = db.cursor() db.close() @@ -425,7 +421,7 @@ def test11_ConnectionFailureError(self): db.close() self.assertRaises(dbapi.ProgrammingError, cursor.execute, 'error') - def test12_ConnectionSetSizes(self): + def test_connection_set_sizes(self): db = SteadyDBconnect(dbapi) cursor = db.cursor() cursor.execute('get sizes') @@ -450,7 +446,7 @@ def test12_ConnectionSetSizes(self): result = cursor.fetchone() self.assertEqual(result, ([6, 42, 7], {None: 7, 3: 15, 9: 42})) - def test13_ConnectionPingCheck(self): + def test_connection_ping_check(self): Connection = dbapi.Connection Connection.has_ping = False Connection.num_pings = 0 @@ -539,7 +535,7 @@ def test13_ConnectionPingCheck(self): Connection.has_ping = False Connection.num_pings = 0 - def test14_BeginTransaction(self): + def test_begin_transaction(self): db = SteadyDBconnect(dbapi, database='ok') cursor = db.cursor() cursor.close() @@ -562,7 +558,7 @@ def test14_BeginTransaction(self): cursor.execute('select test12') self.assertEqual(cursor.fetchone(), 'test12') - def test15_WithBeginExtension(self): + def test_with_begin_extension(self): db = SteadyDBconnect(dbapi, database='ok') db._con._begin_called_with = None @@ -576,7 +572,7 @@ def begin(a, b=None, c=7): self.assertEqual(cursor.fetchone(), 'test13') self.assertEqual(db._con._begin_called_with, (42, 6, 7)) - def test16_CancelTransaction(self): + def test_cancel_transaction(self): db = SteadyDBconnect(dbapi, database='ok') cursor = db.cursor() db.begin() @@ -586,7 +582,7 @@ def test16_CancelTransaction(self): cursor.execute('select test14') self.assertEqual(cursor.fetchone(), 'test14') - def test17_WithCancelExtension(self): + def test_with_cancel_extension(self): db = SteadyDBconnect(dbapi, database='ok') db._con._cancel_called = None @@ -601,7 +597,7 @@ def cancel(): db.cancel() self.assertEqual(db._con._cancel_called, 'yes') - def test18_ResetTransaction(self): + def test_reset_transaction(self): db = SteadyDBconnect(dbapi, database='ok') db.begin() self.assertFalse(db._con.session) @@ -613,7 +609,7 @@ def test18_ResetTransaction(self): db.close() self.assertEqual(db._con.session, ['rollback']) - def test19_CommitError(self): + def test_commit_error(self): db = SteadyDBconnect(dbapi, database='ok') db.begin() self.assertFalse(db._con.session) @@ -635,7 +631,7 @@ def test19_CommitError(self): self.assertEqual(db._con.session, ['commit']) self.assertTrue(db._con.valid) - def test20_RollbackError(self): + def test_rollback_error(self): db = SteadyDBconnect(dbapi, database='ok') db.begin() self.assertFalse(db._con.session) diff --git a/tests/test_steady_pg.py b/tests/test_steady_pg.py index e566a7b..df88b77 100644 --- a/tests/test_steady_pg.py +++ b/tests/test_steady_pg.py @@ -15,23 +15,19 @@ import unittest import sys -import DBUtils.Tests.mock_pg as pg +from . import mock_pg as pg -from DBUtils.SteadyPg import SteadyPgConnection - -__version__ = '1.4' +from dbutils.steady_pg import SteadyPgConnection class TestSteadyPg(unittest.TestCase): - def test0_CheckVersion(self): - from DBUtils import __version__ as DBUtilsVersion - self.assertEqual(DBUtilsVersion, __version__) - from DBUtils.SteadyPg import __version__ as SteadyPgVersion - self.assertEqual(SteadyPgVersion, __version__) - self.assertEqual(SteadyPgConnection.version, __version__) + def test_version(self): + from dbutils import __version__, steady_pg + self.assertEqual(steady_pg.__version__, __version__) + self.assertEqual(steady_pg.SteadyPgConnection.version, __version__) - def test1_MockedConnection(self): + def test_mocked_connection(self): PgConnection = pg.DB db = PgConnection( 'SteadyPgTestDB', user='SteadyPgTestUser') @@ -80,7 +76,7 @@ def test1_MockedConnection(self): self.assertRaises(pg.InternalError, db.query, 'select test') self.assertRaises(pg.InternalError, db.get_tables) - def test2_BrokenConnection(self): + def test_broken_connection(self): self.assertRaises(TypeError, SteadyPgConnection, 'wrong') db = SteadyPgConnection(dbname='ok') InternalError = sys.modules[db._con.__module__].InternalError @@ -89,7 +85,7 @@ def test2_BrokenConnection(self): del db self.assertRaises(InternalError, SteadyPgConnection, dbname='error') - def test3_Close(self): + def test_close(self): for closeable in (False, True): db = SteadyPgConnection(closeable=closeable) self.assertTrue(db._con.db and db._con.valid) @@ -104,7 +100,7 @@ def test3_Close(self): db._close() self.assertFalse(db._con.db and db._con.valid) - def test4_Connection(self): + def test_connection(self): db = SteadyPgConnection( 0, None, 1, 'SteadyPgTestDB', user='SteadyPgTestUser') self.assertTrue(hasattr(db, 'db')) @@ -184,7 +180,7 @@ def test4_Connection(self): self.assertEqual(db._usage, 1) self.assertEqual(db.num_queries, 0) - def test5_ConnectionContextHandler(self): + def test_connection_context_handler(self): db = SteadyPgConnection( 0, None, 1, 'SteadyPgTestDB', user='SteadyPgTestUser') self.assertEqual(db.session, []) @@ -202,7 +198,7 @@ def test5_ConnectionContextHandler(self): self.assertEqual( db._con.session, ['begin', 'commit', 'begin', 'rollback']) - def test6_ConnectionMaxUsage(self): + def test_connection_maxusage(self): db = SteadyPgConnection(10) for i in range(100): r = db.query('select test%d' % i) @@ -250,7 +246,7 @@ def test6_ConnectionMaxUsage(self): self.assertEqual(db._usage, 1) self.assertEqual(db.num_queries, 1) - def test7_ConnectionSetSession(self): + def test_connection_setsession(self): db = SteadyPgConnection(3, ('set time zone', 'set datestyle')) self.assertTrue(hasattr(db, 'num_queries')) self.assertEqual(db.num_queries, 0) @@ -271,7 +267,7 @@ def test7_ConnectionSetSession(self): self.assertEqual(db.num_queries, 0) self.assertEqual(db.session, ['time zone', 'datestyle', 'test']) - def test8_Begin(self): + def test_begin(self): for closeable in (False, True): db = SteadyPgConnection(closeable=closeable) db.begin() @@ -291,7 +287,7 @@ def test8_Begin(self): self.assertEqual(db.begin('select sql:begin'), 'sql:begin') self.assertEqual(db.num_queries, 2) - def test9_End(self): + def test_end(self): for closeable in (False, True): db = SteadyPgConnection(closeable=closeable) db.begin() diff --git a/tests/test_threading_local.py b/tests/test_threading_local.py index 424ea2f..b44c613 100644 --- a/tests/test_threading_local.py +++ b/tests/test_threading_local.py @@ -3,41 +3,39 @@ import unittest from threading import Thread -from DBUtils.PersistentDB import local - -__version__ = '1.4' +from dbutils.persistent_db import local class TestThreadingLocal(unittest.TestCase): - def test0_GetAttr(self): - mydata = local() - mydata.number = 42 - self.assertEqual(mydata.number, 42) + def test_getattr(self): + my_data = local() + my_data.number = 42 + self.assertEqual(my_data.number, 42) - def test1_Dict(self): - mydata = local() - mydata.number = 42 - self.assertEqual(mydata.__dict__, {'number': 42}) - mydata.__dict__.setdefault('widgets', []) - self.assertEqual(mydata.widgets, []) + def test_dict(self): + my_data = local() + my_data.number = 42 + self.assertEqual(my_data.__dict__, {'number': 42}) + my_data.__dict__.setdefault('widgets', []) + self.assertEqual(my_data.widgets, []) - def test2_ThreadLocal(self): + def test_threadlocal(self): def f(): - items = sorted(mydata.__dict__.items()) + items = sorted(my_data.__dict__.items()) log.append(items) - mydata.number = 11 - log.append(mydata.number) - mydata = local() - mydata.number = 42 + my_data.number = 11 + log.append(my_data.number) + my_data = local() + my_data.number = 42 log = [] thread = Thread(target=f) thread.start() thread.join() self.assertEqual(log, [[], 11]) - self.assertEqual(mydata.number, 42) + self.assertEqual(my_data.number, 42) - def test3_SubClass(self): + def test_subclass(self): class MyLocal(local): number = 2 @@ -52,36 +50,36 @@ def __init__(self, **kw): def squared(self): return self.number ** 2 - mydata = MyLocal(color='red') - self.assertEqual(mydata.number, 2) - self.assertEqual(mydata.color, 'red') - del mydata.color - self.assertEqual(mydata.squared(), 4) + my_data = MyLocal(color='red') + self.assertEqual(my_data.number, 2) + self.assertEqual(my_data.color, 'red') + del my_data.color + self.assertEqual(my_data.squared(), 4) def f(): - items = sorted(mydata.__dict__.items()) + items = sorted(my_data.__dict__.items()) log.append(items) - mydata.number = 7 - log.append(mydata.number) + my_data.number = 7 + log.append(my_data.number) log = [] thread = Thread(target=f) thread.start() thread.join() self.assertEqual(log, [[('color', 'red'), ('initialized', 1)], 7]) - self.assertEqual(mydata.number, 2) - self.assertFalse(hasattr(mydata, 'color')) + self.assertEqual(my_data.number, 2) + self.assertFalse(hasattr(my_data, 'color')) class MyLocal(local): __slots__ = 'number' - mydata = MyLocal() - mydata.number = 42 - mydata.color = 'red' + my_data = MyLocal() + my_data.number = 42 + my_data.color = 'red' thread = Thread(target=f) thread.start() thread.join() - self.assertEqual(mydata.number, 7) + self.assertEqual(my_data.number, 7) if __name__ == '__main__': diff --git a/tox.ini b/tox.ini index 78dd8dc..0e56291 100644 --- a/tox.ini +++ b/tox.ini @@ -15,4 +15,4 @@ basepython = deps = flake8 commands = - flake8 *.py dbutils + flake8 dbutils tests docs setup.py From f067391bb59ebd76b7e57ba7860ec9c42fce6c7f Mon Sep 17 00:00:00 2001 From: Christoph Zwerschke Date: Sat, 26 Sep 2020 18:18:01 +0200 Subject: [PATCH 06/90] Convert images from GIF to PNG --- MANIFEST.in | 2 +- docs/dbdep.gif | Bin 2653 -> 0 bytes docs/dbdep.png | Bin 0 -> 3331 bytes docs/main.de.html | 8 ++++---- docs/main.de.rst | 8 ++++---- docs/main.html | 8 ++++---- docs/main.rst | 8 ++++---- docs/persist.gif | Bin 7378 -> 0 bytes docs/persist.png | Bin 0 -> 7063 bytes docs/pgdep.gif | Bin 2426 -> 0 bytes docs/pgdep.png | Bin 0 -> 3129 bytes docs/pool.gif | Bin 13454 -> 0 bytes docs/pool.png | Bin 0 -> 11963 bytes 13 files changed, 17 insertions(+), 17 deletions(-) delete mode 100644 docs/dbdep.gif create mode 100644 docs/dbdep.png delete mode 100644 docs/persist.gif create mode 100644 docs/persist.png delete mode 100644 docs/pgdep.gif create mode 100644 docs/pgdep.png delete mode 100644 docs/pool.gif create mode 100644 docs/pool.png diff --git a/MANIFEST.in b/MANIFEST.in index b4efc19..9896216 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -3,7 +3,7 @@ include MANIFEST.in include LICENSE include README.md -recursive-include docs *.rst make.py *.html *.css *.png *.gif +recursive-include docs *.rst make.py *.html *.css *.png prune docs/_build exclude release.md setversion.py diff --git a/docs/dbdep.gif b/docs/dbdep.gif deleted file mode 100644 index 8554b62b242c5f9e58916c99d1ea419c18701f18..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2653 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 N002ovPDHLkV1mFbDR}?@ literal 0 HcmV?d00001 diff --git a/docs/main.de.html b/docs/main.de.html index b26431d..3827321 100644 --- a/docs/main.de.html +++ b/docs/main.de.html @@ -117,10 +117,10 @@

      Module

      Die Abhängigkeiten der Module in der Variante für beliebige DB-API-2-Adapter sind im folgenden Diagramm dargestellt:

      -dbdep.gif +dbdep.png

      Die Abhängigkeiten der Module in der Variante für den klassischen PyGreSQL-Adapter sehen ähnlich aus:

      -pgdep.gif +pgdep.png

    Download

    @@ -202,7 +202,7 @@

    PersistentDB

    geschlossen werden.

    Das folgende Diagramm zeigt die beteiligten Verbindungsschichten, wenn Sie PersistentDB-Datenbankverbindungen einsetzen:

    -persist.gif +persist.png

    Immer wenn ein Thread eine Datenbankverbindung zum ersten Mal öffnet, wird eine neue Datenbankverbindung geöffnet, die von da an immer wieder für genau diesen Thread verwendet wird. Wenn der Thread die Datenbankverbindung schließt, @@ -227,7 +227,7 @@

    PooledDB

    dies bemerkt, wiederverwendet werden.

    Das folgende Diagramm zeigt die beteiligten Verbindungsschichten, wenn Sie PooledDB-Datenbankverbindungen einsetzen:

    -pool.gif +pool.png

    Wie im Diagramm angedeutet, kann PooledDB geöffnete Datenbankverbindungen den verschiedenen Threads beliebig zuteilen. Dies geschieht standardmäßig, wenn Sie den Verbindungspool mit einem positiven Wert für maxshared einrichten diff --git a/docs/main.de.rst b/docs/main.de.rst index f0fda86..75580f7 100644 --- a/docs/main.de.rst +++ b/docs/main.de.rst @@ -54,12 +54,12 @@ DB-API-2-Datenbankadaptern, und einer Gruppe zur Verwendung mit dem klassischen Die Abhängigkeiten der Module in der Variante für beliebige DB-API-2-Adapter sind im folgenden Diagramm dargestellt: -.. image:: dbdep.gif +.. image:: dbdep.png Die Abhängigkeiten der Module in der Variante für den klassischen PyGreSQL-Adapter sehen ähnlich aus: -.. image:: pgdep.gif +.. image:: pgdep.png Download @@ -166,7 +166,7 @@ geschlossen werden. Das folgende Diagramm zeigt die beteiligten Verbindungsschichten, wenn Sie ``PersistentDB``-Datenbankverbindungen einsetzen: -.. image:: persist.gif +.. image:: persist.png Immer wenn ein Thread eine Datenbankverbindung zum ersten Mal öffnet, wird eine neue Datenbankverbindung geöffnet, die von da an immer wieder für genau @@ -196,7 +196,7 @@ dies bemerkt, wiederverwendet werden. Das folgende Diagramm zeigt die beteiligten Verbindungsschichten, wenn Sie ``PooledDB``-Datenbankverbindungen einsetzen: -.. image:: pool.gif +.. image:: pool.png Wie im Diagramm angedeutet, kann ``PooledDB`` geöffnete Datenbankverbindungen den verschiedenen Threads beliebig zuteilen. Dies geschieht standardmäßig, wenn diff --git a/docs/main.html b/docs/main.html index a6625bf..52a6944 100644 --- a/docs/main.html +++ b/docs/main.html @@ -116,10 +116,10 @@

    Modules

    The dependencies of the modules in the universal DB-API 2 variant are as indicated in the following diagram:

    -dbdep.gif +dbdep.png

    The dependencies of the modules in the classic PyGreSQL variant are similar:

    -pgdep.gif +pgdep.png

    Download

    @@ -194,7 +194,7 @@

    PersistentDB

    connections to a database, using any DB-API 2 database module.

    The following diagram shows the connection layers involved when you are using PersistentDB connections:

    -persist.gif +persist.png

    Whenever a thread opens a database connection for the first time, a new connection to the database will be opened that will be used from now on for this specific thread. When the thread closes the database connection, @@ -216,7 +216,7 @@

    PooledDB

    DB-API 2 database module.

    The following diagram shows the connection layers involved when you are using PooledDB connections:

    -pool.gif +pool.png

    As the diagram indicates, PooledDB can share opened database connections between different threads. This will happen by default if you set up the connection pool with a positive value of maxshared and the underlying diff --git a/docs/main.rst b/docs/main.rst index 43b7905..59b0b70 100644 --- a/docs/main.rst +++ b/docs/main.rst @@ -53,12 +53,12 @@ the other one for use with the classic PyGreSQL module. The dependencies of the modules in the universal DB-API 2 variant are as indicated in the following diagram: -.. image:: dbdep.gif +.. image:: dbdep.png The dependencies of the modules in the classic PyGreSQL variant are similar: -.. image:: pgdep.gif +.. image:: pgdep.png Download @@ -157,7 +157,7 @@ connections to a database, using any DB-API 2 database module. The following diagram shows the connection layers involved when you are using ``PersistentDB`` connections: -.. image:: persist.gif +.. image:: persist.png Whenever a thread opens a database connection for the first time, a new connection to the database will be opened that will be used from now on @@ -184,7 +184,7 @@ DB-API 2 database module. The following diagram shows the connection layers involved when you are using ``PooledDB`` connections: -.. image:: pool.gif +.. image:: pool.png As the diagram indicates, ``PooledDB`` can share opened database connections between different threads. This will happen by default if you set up the diff --git a/docs/persist.gif b/docs/persist.gif deleted file mode 100644 index 43c3d0176ab4fc7bfd38467e7cc95159ab46fa04..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 7378 zcmV;@94+HVNk%w1VUPja0fPVl0000N7Z)TXBsw}eN=iymQBh}SXM1~liHV7kk&&mT zr@Xwp$jHdq+1cpm=>GoxA^8LW000jFEC2ui0FVLO0YC)*@X1N5y*TU5yZ>M)j$~<` zXsWI&z`k%S&vb3ych=_~d@crvt3=$5Uh9K3LPV?_!CfEEO51`mHgzG)?CPYYl{_QW}?}GNavCsAW;;Qs?e}RL4_FqIs$pfWJs+j6cc^9I3VLj3&>1> z1bIQ^0Fn_;e%Yw9fvc7eG}as-hy+a<33V70@o_1x4@Z|ql`-|Hh$Mr$H2m{xK_9PX zwmRr&Dj3)iO|K@C!*arbJFLF;!6=4nFbW4~Jvhr0>Ike8z_gX{Rts3Lblr}Yu}=B&}>WC(6D36CMa;W?c2DK%BCEf zw{73KMVFH>F1UqpJBk~ZH=G>s<>A~x*QIzP$PK@6M}V z&we|v_VDAoUp7DA46@|X#{d;gJH7gW6;V|Ge)xdLnM1FsbXrd(;Smge0M@X>NC{RF z1%q##a@s-h^g!W)l{A21hCxsS7;%-=woQa8uEQb^|K0MU4>Nja^|uLe^WLP@&fZ3buqH5J(=m6O=yIVxfatUP+~wT2O@Jm@TwO=9y@U zwi}r>8q{W*GbHC*dYXJ_9zG*a#@iXB3>fo8)apqpKEVK87i2lZfI(Ztx9R(r%7^Y;#zjXDvvjt zW~xrFz3wBUJ;5ew?6H_pP)8Z48VRNUMT@yaDwB6nJKmF@{xanNRhrRlk5_h?SgN9W z%WAmDrn}Itz6|h^y6^_t8=Ghr8!u+#-I=exe%{Ngz3E`5@0kGmYcOsGN&~E#!&XY; z!7YN3#TKw|!4e-*kVa5G#`s+@CZH-N_ zqQ((WJ@WWV(G=)@*X7Ylpnw7!4zFQ}Py>H_)LU!Z5brQ0XkCPzo%f zKx@i}8G7v};fLP@#Mo84)>BU~JUFt$F8_D)(_H`kvG0rj{xb9L|Nl0M-)2J4Bmpgk z1?M{-WDMnj0&0aZCNQ6*O4gTTT}4t<_z40Tb1Ai<<2k&cog1`v5{f8*B}Wj-(jd4% zo{>O=%hO4ZOo+muylZ+M8Q@6(>Rbo2r6lO7Hk{| zl30W#ZlH;`i^GY~qQemXP!RxD)BqNsNwkB}^r*(uF zM)?N`*!adSw9yC++0Yy(RmTaifeO*UBNwB%#{Mj;D9d6%AmylqND}5HtpJ1~&lnvY z1n!fd45fVjA<9yk@{~|Hr7BlB$^$i!hZ_W-EcKX17*Y)wbR>joBxV>y&hnSH867u- zc{X555l6)2l`)xvILYZRfX`fJ%mN6fWV%wC*i;k)6;?BwJQbfJRH>H3sX#p{ zRi7FkgwZQa1w9t(`V>v>jP;>{qf=N(H>S1n^l<`&Xg4|bO>pMyGsNsvki;b`bfQb0 zZq3#1N`cR9#Z#WNNobe^kWV1d%1Zns3Z?>U(1s#puI#KU{WQB-cD?npM?3%(oMF+B zTr?U5)TlBz3R>87<^XGn$$~r=t`i2)hVJVg*IH^wsNwUmBnmD~QCf+czH?MDWNmBd z>e;DwRjbecjcRn0gVpM8HLKEv&rqZ5TFyV-3|+^oyps+O0l;GI{dD65n!&><~)inRQ z2(d%L75iqYEI_c=!il{sXa6hU%!U(g{Y^1KH3qI7k(L!!cpq6(ngNyI5~F^U#au)- z3yKwmKXuTcC|WkMz4%haeA_RQQ~Y5yO75#mu52*P8s!tD)uUyrGC_+f9QqarzFMY_ zmsiwef!H^`Weu}y)2z6jmU3^VROWoue4{cmN?kKX$!O`|M@C*1u_Xv6|CVTf!Uu+(kE{nsKePq#{MO7~c145MRTVMq3#pba{!Cm1PpV zw18-5K`k~^!rwamSTy#n0M&?A0S@w`aC3d{NxcsYh42Eq$550hpmu^p{;?%i!Z~_R zauP^mnFKRnal!!7Qz0`Ns(Y&BNyoS4E~m81?Hu!X(Y)r!IxEhX%jTWG^~{U*IZrG9 zEp-32iIqrCy57X0^rkC4l}?YkDn;z>7XF5oS!U#vP3&Y&OBmC4L4(J-9=RQUJq2X> zb{@6v^^l{z(<`^SoUI%|SO%O7aCGCXAMj~b>vvsdM_LT=9tuh6Veft4i)!Uw^$x&$ zcjLLZ0THi(xc?oEjR)v#EaO$SZ=UL9&tY&lzjds49`kY9qhobahcYSw0I4}3p9u>_ z3Y<`B5=gw~rQAr3p|tj#fW2boNPA^FgO9p5{V{vbQq2MX^|2@Z8<*ISBbbR>vBqrpQ&5DKK=V_pzw`DSDwcY^Q&9*-vm!}c1vgJ8GAeKZI$H}`{r5`;oX zWg$pSVD(uL)UYoCxvW7h5uuP2s38R1a!Z|h0EcE^|gd|R)i%8b7WXQ zCU}OdlZHn`P^WTYZ%AN=Q)2BVhjHkJViO@^#~73aAZoWx-b4ea7KCglAx1MiFk?G} z@qd@LF?7`shzK>+#$XGeT1}=`zLtpJ#$ZPSh@BOBXq0J_aVnz7ft^+VilWC*nRhcI zMq+SyGIp3`Bd82gw{$L2i#pe3xCn-7*o(eMXG60ZD}aieSS!M4X`S|qFc6FuKzRT6 zF*`;vvjBPG!H6Z5XL+V-Pm^oyGg8i&i0w0pC?_cwsEiNTe&#qog_w@)=!l4xgg^I$ z^7wLXRZSgLI%buN`G|%5!;inAg;mIlS9oOsSuX_nh2)i9=B1G6C0^g6b$Do3F)5P+Hj_2k zhOlUpLL&ovc#bfs0)JR$HL`Mc){?2$a9@Ed;;2rJ5{ICWlw)B3J)BsHlO>DN_&t&+ zl^iBRo*0OrculeRlZHq(IGK|^36?tPieY(St;m+E*bBSpkKqxQ2N@l7S(gE}l6tw9 z$kZaJW^8R|YJo8-o!ASg$d~P~Ul?%;&M1vgKzYr!7tz>Z*@$7=xQN|oE0K3#;Fe&R zIgUk!n2Yq5Zzr0AVw9!{glp56PzYLLxQtC0h53P(n>QS^`Hx(6j{up40?C`VIgqc} z0>87CsPk|&v( zr!$`9Ift_dmv`x4>v@UmnK$N{mM(ddWl5j&88p;zm>59+08Zmz=~n_h;ZJ0#pFQ|j zM2MO@vumCia=q4wT{(9O8et3?JUh~#uo9sX$~@=Rj4yGZ@i{j!C~qm}JbVa?A&PM# z$0Z7|neG^fF(_~;YBX%{E*_emtoV|7iKF&;lqg1;Yk8k)`J-Y9q+}Ul=Xs<^dWWyV zQnXN^)H7;aBU_9Spgt&p$(W=}$RSIzdVeLMiBLdg#6lHT0XZ0MB(*i)Hf&QvLL2&Q zSPFs!Qb7GtK)!`3Q$T%pv7*(OML0GX$(3-E0;8fOe?vA>heSbdT7hSosOWiwbJm(F z7M!DrglZe8Wp(ubNa}r5lJYn3anJotFeO?=cSBW<$)bYtO8|d&We_87OklF zg?JVW1Q3A=MW8*Ss+X!KTiR_9)N9<rf~8a4TlP& zHMp+SN{f1uo%?E?MYpR0%aH$Cum*du2>TxcyRZz~unzmM5F3{tny{xiu@u{{7JISq zxTzR;Q4bVLOmwBGrk~s@na|)1Q=k{BAec6=qENI#5*4z4v28hujgXRWO*g~13T+>G}W0Tkb?+Fs;kBSLpYHWKSWs2avCZ$wXbot&%$x`v>2Pv z5;4SER2sJBVlHChds$Kz8L@c2X0nH21eNTcISuZqsYi^K;j(I?gS!>0(7L5sGg}F3~ zph!VW49>U}v_Jq2@CT>6xzu=MsIrs;_%c@D6(iNT+&EJc$8t`Kj7rNqB~%KwWfE75 zQn#hGwe=HU>$PD)wqXH8i&;r!%Zbg$m8U_K8qhs@u>c9Mx}LL7%4Psb`7OmO2FUw$ zIdygwFg%Z-Zp}itMsv6u_?3r37Ddbd0tP5XM++MHOQtVdt&2)1_}jlVu)pnFMbiNU z6QveGI=~uhEC?FG@5oFMd%+l-!5X~53p;ZZ+^8SClOf!#x#F!OEF-^q!Z~NFDhyV; z*}}p)tT1elCOpF^JafkxoyjSk{)(O7>BF+R!$O?H*U7^_Y{WrK#666}_{g12Y>^pj z!%z0RQe46ITgCH;#S&bfj(Wuf_N{mYdRba}QQV{Z2dV;Wq^Wp%Wvq&4yqYz;b}xjp zrHKd)%&a!+esqii_(7#>tf)rIz9&$?dONA`lYn!4e_GUnLl$T#69#0eX`DpG{}~aB z+zE}mXL2xh#D=IE2*EO&G?(1}APV=$%<`hqLw3Gvihs~Npf#Mwpsdju z9mdiMo8Q+ZoEgZ}d<7eUz!6>1Vw4Ovrn%wFzP6CPKWm;<0T?kIz$tythOr7P{l@A% z#-8RDP*ZA_vvG}p6{mpz)bCr#uExwRodJpjTl$7124E6P{nSn^$ubnx6qvD9Z8c7< z)seu}Snbt&2i74?Y}*GVY`e~*C<06y5g4RFqreEI(Ij|XyFq=DQ&HE`n?Xv06-(U` zcP)FU@Fagt#ep3fa!K@ z4aQXg+DC)hh;2wc<_54$qKLZME#1(cy|p?4+oV0)O+DH~vlbzR+d^Hx)y#j@pxJMk z(>!eh%q`as`qImN(-%F|wM@p>jb+EpsY5E&Al=>Jo!cUv##2q+ocBW+s1fD?U-wRamlLNQnZ9>@Nzw9nJH zhQ}I{3ylqa$hEY%=r&vqAiW#6;9Gg&UMb=jOX3x4;#Lfu0yD(M+2ZHL;xDemM-1Z> zDdS1(;x&%rOPtpbVHuv(v&A1Ek$_ZKV!Wh3TaF2iePti568>WJoe#pY-3t8GQ)$a>{EuERF|#6XPa zOstPIj+}SS=YL*SeQxJBb%{S8b{P=|als$_(kq&Bb*npWjW?BE0EyH|h>v>Z&ON{Q2pxz5;%H-nR~Rg-nPH zBMXw(r={UC4WMa#xCa%J>=zT7ygl8T4($2NGJl3GiRkN>K8D4k0MNW(@Jr9fu7ks~ z?Gx5KtYD$wl2fow(h&}K7cgV6;^bK+RQ!ael(oOmG1uD z1P1N+I-(AW=ooJBB5E$0*ID8Z)NA8^O#7@D4u;op7&Rfk;7C8ac*eeX#Y|XcjL9qalMaI(Bb@0A!V0 z_CMqR9Q*HkqaOsx!xO1LUACiR4BOsYM?A#E(`VpZ-u&^s zOvv$6`8bs`K9#dy zPdFqNjYp(0cv&VZ0BBS?rB>`bsHU;am7)7hk+knhXK%rN<>jhN4%ef zD9#5{D9+kX+JRUAg^32;)=OAfiCTc$0f1anUSEvOP*!OPUSwTcV`b)DsOO0V1L5g3 z4pJK#Q_x@W3DXGz2lZfz_tjzdQ;LRmZFqTo_Q0v4HZ7e#3H&Yyj5kkULV|Gr$Vt?2 zu0|7e3iJK5_mEyeNElCP^e3U=fRYauL@ngu5B~PYY+45z~nKf@7E12_V z(4hedR)Ao_0n;8ssIE!C*Ta=aSc|5ed94K0(1J4k6~%NXC-qu@RA=F?`KcwqXdfCmn+kDZTZqOcyKkZTXSP894ALx21mDyHcM zH1UnwB!CKvehxt9D%`wbuYur*qR}U1k~)S(3}EDK#1W}m?iv>v7%HnExjS)5Gg8bU zJtm`+QU@oewDQWqD#CJ0F1x%TFvh@aOiV9xATzNu6-%?si>6#Nt~c3qAUMJnPS76!y{54o&w;Wap!$ehU zuemT&b(CZSUA8d7f{pW8Ev7XnT3nZyZ3NY@jkQOjOn|W^0%KBv#;nk#cGaRzh($PP zvjp*k{EV`>x4Tsr1q7W(D&LQl*sjP50#oAXI5S zpKZRtUt7_X6$uzj;RNJ^^%29&FTM5tbXr6!o5sv8K~W&<6VPh38p zUV~e<=vKB`r&)&D?wt8f)o*yo&f?mY@!prpG37?q@VgoR4;=9@6)%De%C~T-a?B;Y zJaf*SE%tNJLl=E?(n~Mgbksk!YsYJ_iX!NJQf6Hh)y{R|+tgpZ4L;h-eSqnRm7d9? ze2>6A_gQ!Mojuljfd&&o;89JpE+lj&&~`74!QdP18{ zo5DEiD+CAjYI>$wY=77-M&_Xypc!kWd;@*0a>YZUQ6ZTThXSREpGN|e0r34!KO_s0 z&6swxRv5-7Qy5B7;^b0> zG9{WInaUP+@-DHQBrG|1OHz^%m%EfDBYg-l|ni61R^!Uahd{!iw-HJxOq*EWS1ia=#M$;1m~m-I6)O%^rJZiNcjw;0B$Vk zf+c!qP4(#|l9nK;N6lhAncAhL_Oq8yt;{Q3B}}UNL5QL>rxG#M)n8^+tYal>up$5e EJG2-cng9R* diff --git a/docs/persist.png b/docs/persist.png new file mode 100644 index 0000000000000000000000000000000000000000..e76856d7be4aaee2d008839e503b5c7d513f279d GIT binary patch literal 7063 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 literal 0 HcmV?d00001 diff --git a/docs/pgdep.gif b/docs/pgdep.gif deleted file mode 100644 index 9bdfaced5b7a62636c713fa34879e583ba254cbc..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2426 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 TVXvr+00000NkvXXu0mjfk(cn* literal 0 HcmV?d00001 diff --git a/docs/pool.gif b/docs/pool.gif deleted file mode 100644 index 105b3c8b17a13656184440407c4e139e9856ccb1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 13454 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 Date: Sat, 26 Sep 2020 20:30:52 +0200 Subject: [PATCH 07/90] Adapt documentation --- docs/changelog.html | 1 + docs/changelog.rst | 1 + docs/dbdep.png | Bin 3331 -> 0 bytes docs/dependencies_db.png | Bin 0 -> 4541 bytes docs/dependencies_pg.png | Bin 0 -> 4305 bytes docs/main.de.html | 281 +++++++++++++++++---------------------- docs/main.de.rst | 279 +++++++++++++++++--------------------- docs/main.html | 253 ++++++++++++++++------------------- docs/main.rst | 247 +++++++++++++++------------------- docs/persist.png | Bin 7063 -> 0 bytes docs/persistent.png | Bin 0 -> 7038 bytes docs/pgdep.png | Bin 3129 -> 0 bytes docs/pool.png | Bin 11963 -> 0 bytes docs/pooled.png | Bin 0 -> 12053 bytes 14 files changed, 470 insertions(+), 592 deletions(-) delete mode 100644 docs/dbdep.png create mode 100644 docs/dependencies_db.png create mode 100644 docs/dependencies_pg.png delete mode 100644 docs/persist.png create mode 100644 docs/persistent.png delete mode 100644 docs/pgdep.png delete mode 100644 docs/pool.png create mode 100644 docs/pooled.png diff --git a/docs/changelog.html b/docs/changelog.html index 7db17cd..fc37f48 100644 --- a/docs/changelog.html +++ b/docs/changelog.html @@ -79,6 +79,7 @@

    Changes:

    Particularly, you need to import dbutils instead of DBUtils now.

  • The Webware Examples folder has been removed.

  • The internal naming conventions have been changed to comply with PEP8.

  • +
  • The documentation has been adapted to reflect the changes in this version.

  • This changelog file has been created from the former release notes.

  • diff --git a/docs/changelog.rst b/docs/changelog.rst index bf41adf..25b7d88 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -19,6 +19,7 @@ Changes: Particularly, you need to import ``dbutils`` instead of ``DBUtils`` now. * The Webware ``Examples`` folder has been removed. * The internal naming conventions have been changed to comply with PEP8. +* The documentation has been adapted to reflect the changes in this version. * This changelog file has been created from the former release notes. 1.4 diff --git a/docs/dbdep.png b/docs/dbdep.png deleted file mode 100644 index 666e3a78c5e9507e722a77a28f6d55f780f1333c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3331 zcmV+e4gB(nP)004R>004l5008;`004mK004C`008P>0026e000+ooVrmw00002 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 N002ovPDHLkV1mFbDR}?@ diff --git a/docs/dependencies_db.png b/docs/dependencies_db.png new file mode 100644 index 0000000000000000000000000000000000000000..f460fc02d6bf86de7e2ff5caf79729dc3badcbf9 GIT binary patch literal 4541 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 OE979~Y+Yp;koteBsk^NJ literal 0 HcmV?d00001 diff --git a/docs/dependencies_pg.png b/docs/dependencies_pg.png new file mode 100644 index 0000000000000000000000000000000000000000..380def9a0bba68c76ba73cd87e9d946f6c8147b6 GIT binary patch literal 4305 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 für DBUtils

    Zusammenfassung

    DBUtils ist eine Sammlung von Python-Modulen, mit deren Hilfe man in Python geschriebene Multithread-Anwendungen auf sichere und effiziente Weise an -Datenbanken anbinden kann. DBUtils wurde mit Blick auf Webware for Python -als Anwendung und PyGreSQL als PostgreSQL-Datenbankadapter entwickelt, -kann aber für beliebige Python-Anwendungen und beliebige auf DB-API 2 -beruhende Python-Datenbankadapter verwendet werden.

    +Datenbanken anbinden kann.

    +

    DBUtils wurde ursprünglich speziell für Webware for Python als Anwendung +und PyGreSQL als PostgreSQL-Datenbankadapter entwickelt, +kann aber inzwischen für beliebige Python-Anwendungen und beliebige +auf DB-API 2 beruhende Python-Datenbankadapter verwendet werden.

    Module

    DBUtils ist als Python-Package realisiert worden, das aus zwei verschiedenen Gruppen von Modulen besteht: Einer Gruppe zur Verwendung mit beliebigen -DB-API-2-Datenbankadaptern, und einer Gruppe zur Verwendung mit dem klassischen PyGreSQL-Datenbankadapter-Modul.

    +DB-API-2-Datenbankadaptern, und einer Gruppe zur Verwendung mit dem klassischen +PyGreSQL-Datenbankadapter-Modul.

    --++ - + - + - + - +

    Allgemeine Variante für beliebige DB-API-2-Adapter

    SteadyDB.py

    steady_db

    Gehärtete DB-API-2-Datenbankverbindungen

    PooledDB.py

    pooled_db

    Pooling für DB-API-2-Datenbankverbindungen

    PersistentDB.py

    persistent_db

    Persistente DB-API-2-Datenbankverbindungen

    SimplePooledDB.py

    simple_pooled_db

    Einfaches Pooling für DB-API 2

    --++ - + - + - + - +

    Variante speziell für den klassischen PyGreSQL-Adapter

    SteadyPg.py

    steady_pg

    Gehärtete klassische PyGreSQL-Verbindungen

    PooledPg.py

    pooled_pg

    Pooling für klassische PyGreSQL-Verbindungen

    PersistentPg.py

    persistent_pg

    Persistente klassische PyGreSQL-Verbindungen

    SimplePooledPg.py

    simple_pooled_pg

    Einfaches Pooling für klassisches PyGreSQL

    Die Abhängigkeiten der Module in der Variante für beliebige DB-API-2-Adapter sind im folgenden Diagramm dargestellt:

    -dbdep.png +dependencies_db.png

    Die Abhängigkeiten der Module in der Variante für den klassischen PyGreSQL-Adapter sehen ähnlich aus:

    -pgdep.png +depdependencies_pg.png

    Download

    @@ -132,31 +132,19 @@

    Download

    Installation

    -
    -

    Installation als eigenständiges Paket

    -

    Wenn Sie DBUtils für andere Anwendungen als Webware for Python verwenden -möchten, empfiehlt es sich, das Paket auf die übliche Weise zu installieren:

    +
    +

    Installation

    +

    Das Paket kann auf die übliche Weise installiert werden:

    python setup.py install
    -

    Sie können auch pip für Download und Installation verwenden:

    +

    Noch einfacher ist, das Paket in einem Schritt mit pip automatisch +herunterzuladen und zu installieren:

    pip install DBUtils
    -
    -

    Installation als Unterpaket (Plug-In) von Webware for Python

    -

    Wenn Sie DBUtils nur als Ergänzung für das Web-Framework Webware for Python -verwenden wollen, sollten Sie DBUtils als Webware-Plug-In installieren:

    -
    python setup.py install --install-lib=/pfad/zu/Webware
    -

    Ersetzen Sie /pfad/zu/Webware hierbei durch den Pfad zum Wurzelverzeichnis -der Installation von Webware for Python. Sie müssen auch das Installationsskript -von Webware for Python laufen lassen, wenn dies noch nicht geschehen ist, oder -wenn Sie DBUtils in die Webware-Dokumentation integrieren wollen:

    -
    cd /pfad/zu/Webware
    -python install.py
    -

    Anforderungen

    -

    DBUtils unterstützt die Python Versionen 2.7 und 3.5 bis 3.8.

    -

    Die Module in der Variante für klassisches PyGreSQL benötigen PyGreSQL +

    DBUtils unterstützt die Python Versionen 2.7 und 3.5 bis 3.9.

    +

    Die Module in der Variante für klassisches PyGreSQL benötigen PyGreSQL Version 4.0 oder höher, während die Module in der allgemeinen Variante für DB-API 2 mit jedem beliebigen Python-Datenbankadapter-Modul zusammenarbeiten, das auf DB-API 2 basiert.

    @@ -165,44 +153,49 @@

    Anforderungen

    Funktionalität

    Dieser Abschnitt verwendet nur die Bezeichnungen der DB-API-2-Variante, aber Entsprechendes gilt auch für die PyGreSQL-Variante.

    -
    -

    SimplePooledDB

    -

    DBUtils.SimplePooledDB ist eine sehr elementare Referenz-Implementierung -eines Pools von Datenbankverbindungen. Hiermit ist ein Vorratsspeicher an -Datenbankverbindungen gemeint, aus dem sich die Python-Anwendung bedienen kann. -Diese Implementierung ist weit weniger ausgefeilt als das eigentliche -PooledDB-Modul und stellt insbesondere keine Ausfallsicherung zur Verfügung. -DBUtils.SimplePooledDB ist im Wesentlichen identisch mit dem zu Webware for -Python gehörenden Modul MiscUtils.DBPool. Es ist eher zur Verdeutlichung -des Konzepts gedacht, als zum Einsatz im produktiven Betrieb.

    +

    DBUtils installiert sich als Paket dbutils, das alle hier beschriebenen +Module enthält. Jedes dieser Modul enthält im Wesentlichen eine Klasse, die +einen analogen Namen trägt und die jeweilige Funktionalität bereitstellt. +So enthält z.B. das Modul dbutils.pooled_db die Klasse PooledDB.

    +
    +

    SimplePooledDB (simple_pooled_db)

    +

    Die Klasse SimplePooledDB in dbutils.simple_pooled_db ist eine sehr +elementare Referenz-Implementierung eines Pools von Datenbankverbindungen. +Hiermit ist ein Vorratsspeicher an Datenbankverbindungen gemeint, aus dem sich +die Python-Anwendung bedienen kann. Diese Implementierung ist weit weniger +ausgefeilt als das eigentliche pooled_db-Modul und stellt insbesondere +keine Ausfallsicherung zur Verfügung. dbutils.simple_pooled_db ist im +Wesentlichen identisch mit dem zu Webware for Python gehörenden Modul +MiscUtils.DBPool. Es ist eher zur Verdeutlichung des Konzepts gedacht, +als zum Einsatz im produktiven Betrieb.

    -
    -

    SteadyDB

    -

    DBUtils.SteadyDB ist ein Modul, das "gehärtete" Datenbankverbindungen -bereitstellt, denen gewöhnlichen Verbindungen eines DB-API-2-Datenbankadapters -zugrunde liegen. Eine "gehärtete" Verbindung wird bei Zugriff automatisch, -ohne dass die Anwendung dies bemerkt, wieder geöffnet, wenn sie geschlossen -wurde, die Datenbankverbindung unterbrochen wurde, oder wenn sie öfter als -ein optionales Limit genutzt wurde.

    +
    +

    SteadyDBConnection (steady_db)

    +

    Die Klasse SteadyDBConnection im Modul dbutils.steady_db stellt +"gehärtete" Datenbankverbindungen bereit, denen gewöhnlichen Verbindungen +eines DB-API-2-Datenbankadapters zugrunde liegen. Eine "gehärtete" Verbindung +wird bei Zugriff automatisch, ohne dass die Anwendung dies bemerkt, wieder +geöffnet, wenn sie geschlossen wurde, die Datenbankverbindung unterbrochen +wurde, oder wenn sie öfter als ein optionales Limit genutzt wurde.

    Ein typisches Beispiel wo dies benötig wird, ist, wenn die Datenbank neu gestartet wurde, während Ihre Anwendung immer noch läuft und Verbindungen zur Datenbank offen hat, oder wenn Ihre Anwendung auf eine entfernte Datenbank über ein Netzwerk zugreift, das durch eine Firewall geschützt ist, und die Firewall neu gestartet wurde und dabei ihren Verbindungsstatus verloren hat.

    -

    Normalerweise benutzen Sie das SteadyDB-Modul nicht direkt; es wird aber -von den beiden nächsten Modulen benötigt, PersistentDB und PooledDB.

    +

    Normalerweise benutzen Sie das steady_db-Modul nicht direkt; es wird aber +von den beiden nächsten Modulen benötigt, persistent_db und pooled_db.

    -
    -

    PersistentDB

    -

    DBUtils.PersistentDB stellt gehärtete, thread-affine, persistente -Datenbankverbindungen zur Verfügung, unter Benutzung eines beliebigen -DB-API-2-Datenbankadapters. Mit "thread-affin" und "persistent" ist -hierbei gemeint, dass die einzelnen Datenbankverbindungen den jeweiligen -Threads fest zugeordnet bleiben und während der Laufzeit des Threads nicht -geschlossen werden.

    +
    +

    PersistentDB (persistent_db)

    +

    Die Klasse PersistentDB im Modul dbutils.persistent_db stellt +gehärtete, thread-affine, persistente Datenbankverbindungen zur Verfügung, +unter Benutzung eines beliebigen DB-API-2-Datenbankadapters. Mit "thread-affin" +und "persistent" ist hierbei gemeint, dass die einzelnen Datenbankverbindungen +den jeweiligen Threads fest zugeordnet bleiben und während der Laufzeit des +Threads nicht geschlossen werden.

    Das folgende Diagramm zeigt die beteiligten Verbindungsschichten, wenn Sie -PersistentDB-Datenbankverbindungen einsetzen:

    -persist.png +persistent_db-Datenbankverbindungen einsetzen:

    +persistent.png

    Immer wenn ein Thread eine Datenbankverbindung zum ersten Mal öffnet, wird eine neue Datenbankverbindung geöffnet, die von da an immer wieder für genau diesen Thread verwendet wird. Wenn der Thread die Datenbankverbindung schließt, @@ -210,25 +203,25 @@

    PersistentDB

    gleiche Thread wieder eine Datenbankverbindung anfordert, diese gleiche bereits geöffnete Datenbankverbindung wieder verwendet werden kann. Die Verbindung wird automatisch geschlossen, wenn der Thread beendet wird.

    -

    Kurz gesagt versucht PersistentDB Datenbankverbindungen wiederzuverwerten, +

    Kurz gesagt versucht persistent_db Datenbankverbindungen wiederzuverwerten, um die Gesamteffizienz der Datenbankzugriffe Ihrer Multithread-Anwendungen zu steigern, aber es wird dabei sichergestellt, dass verschiedene Threads niemals die gleiche Verbindung benutzen.

    -

    Daher arbeitet PersistentDB sogar dann problemlos, wenn der zugrunde +

    Daher arbeitet persistent_db sogar dann problemlos, wenn der zugrunde liegende DB-API-2-Datenbankadapter nicht thread-sicher auf der Verbindungsebene ist, oder wenn parallele Threads Parameter der Datenbank-Sitzung verändern oder Transaktionen mit mehreren SQL-Befehlen durchführen.

    -
    -

    PooledDB

    -

    DBUtils.PooledDB stellt, unter Benutzung eines beliebigen -DB-API-2-Datenbankadapters, einen Pool von gehärteten, thread-sicheren -Datenbankverbindungen zur Verfügung, die automatisch, ohne dass die Anwendung -dies bemerkt, wiederverwendet werden.

    +
    +

    PooledDB (pooled_db)

    +

    Die Klasse PooledDB im Modul dbutils.pooled_db stellt, unter Benutzung +eines beliebigen DB-API-2-Datenbankadapters, einen Pool von gehärteten, +thread-sicheren Datenbankverbindungen zur Verfügung, die automatisch, ohne dass +die Anwendung dies bemerkt, wiederverwendet werden.

    Das folgende Diagramm zeigt die beteiligten Verbindungsschichten, wenn Sie -PooledDB-Datenbankverbindungen einsetzen:

    -pool.png -

    Wie im Diagramm angedeutet, kann PooledDB geöffnete Datenbankverbindungen +pooled_db-Datenbankverbindungen einsetzen:

    +pooled.png +

    Wie im Diagramm angedeutet, kann pooled_db geöffnete Datenbankverbindungen den verschiedenen Threads beliebig zuteilen. Dies geschieht standardmäßig, wenn Sie den Verbindungspool mit einem positiven Wert für maxshared einrichten und der zugrunde liegende DB-API-2-Datenbankadapter auf der Verbindungsebene @@ -244,23 +237,23 @@

    PooledDB

    Datenbankverbindungen zurückgegeben, damit sie wiederverwertet werden kann.

    Wenn der zugrunde liegende DB-API-Datenbankadapter nicht thread-sicher ist, werden Thread-Locks verwendet, um sicherzustellen, dass die -PooledDB-Verbindungen dennoch thread-sicher sind. Sie brauchen sich also +pooled_db-Verbindungen dennoch thread-sicher sind. Sie brauchen sich also hierum keine Sorgen zu machen, aber Sie sollten darauf achten, dedizierte Datenbankverbindungen zu verwenden, sobald Sie Parameter der Datenbanksitzung verändern oder Transaktionen mit mehreren SQL-Befehlen ausführen.

    Die Qual der Wahl

    -

    Sowohl PersistentDB als auch PooledDB dienen dem gleichen Zweck, +

    Sowohl persistent_db als auch pooled_db dienen dem gleichen Zweck, nämlich die Effizienz des Datenbankzugriffs durch Wiederverwendung von Datenbankverbindungen zu steigern, und dabei gleichzeitig die Stabilität zu gewährleisten, selbst wenn die Datenbankverbindung unterbrochen wird.

    Welches der beiden Module sollte also verwendet werden? Nach den obigen -Erklärungen ist es klar, dass PersistentDB dann sinnvoller ist, wenn +Erklärungen ist es klar, dass persistent_db dann sinnvoller ist, wenn Ihre Anwendung eine gleich bleibende Anzahl Threads verwendet, die häufig auf die Datenbank zugreifen. In diesem Fall werden Sie ungefähr die gleiche Anzahl geöffneter Datenbankverbindungen erhalten. Wenn jedoch Ihre Anwendung -häufig Threads beendet und neu startet, dann ist PooledDB die bessere +häufig Threads beendet und neu startet, dann ist pooled_db die bessere Lösung, die auch mehr Möglichkeiten zur Feineinstellung zur Verbesserung der Effizienz erlaubt, insbesondere bei Verwendung eines thread-sicheren DB-API-2-Datenbankadapters.

    @@ -274,17 +267,17 @@

    Benutzung

    der Initialisierung auch einige Unterschiede, sowohl zwischen den "Pooled"- und den "Persistent"-Varianten, als auch zwischen den DB-API-2- und den PyGreSQL-Varianten.

    -

    Wir werden hier nur auf das PersistentDB-Modul und das etwas kompliziertere -PooledDB-Modul eingehen. Einzelheiten zu den anderen Modulen finden Sie +

    Wir werden hier nur auf das persistent_db-Modul und das etwas kompliziertere +pooled_db-Modul eingehen. Einzelheiten zu den anderen Modulen finden Sie in deren Docstrings. Unter Verwendung der Python-Interpreter-Konsole können Sie -sich die Dokumentation des PooledDB-Moduls wie folgt anzeigen lassen (dies +sich die Dokumentation des pooled_db-Moduls wie folgt anzeigen lassen (dies funktioniert entsprechend auch mit den anderen Modulen):

    -
    help(PooledDB)
    -
    -

    PersistentDB

    -

    Wenn Sie das PersistentDB-Modul einsetzen möchten, müssen Sie zuerst einen +

    help(pooled_db)
    +
    +

    PersistentDB (persistent_db)

    +

    Wenn Sie das persistent_db-Modul einsetzen möchten, müssen Sie zuerst einen Generator für die von Ihnen gewünschte Art von Datenbankverbindungen einrichten, -indem Sie eine Instanz der Klasse PersistentDB erzeugen, wobei Sie folgende +indem Sie eine Instanz der Klasse persistent_db erzeugen, wobei Sie folgende Parameter angeben müssen:

    • creator: entweder eine Funktion, die neue DB-API-2-Verbindungen @@ -319,14 +312,14 @@

      PersistentDB

      möchten, dass jede Verbindung Ihrer lokalen Datenbank meinedb 1000 mal wiederverwendet werden soll, sieht die Initialisierung so aus:

      import pgdb  # importiere das verwendete DB-API-2-Modul
      -from DBUtils.PersistentDB import PersistentDB
      +from dbutils.persistent_db import PersistentDB
       persist = PersistentDB(pgdb, 1000, database='meinedb')

      Nachdem Sie den Generator mit diesen Parametern eingerichtet haben, können Sie derartige Datenbankverbindungen von da an wie folgt anfordern:

      db = persist.connection()

      Sie können diese Verbindungen verwenden, als wären sie gewöhnliche DB-API-2-Datenbankverbindungen. Genauer genommen erhalten Sie die -"gehärtete" SteadyDB-Version der zugrunde liegenden DB-API-2-Verbindung.

      +"gehärtete" steady_db-Version der zugrunde liegenden DB-API-2-Verbindung.

      Wenn Sie eine solche persistente Verbindung mit db.close() schließen, wird dies stillschweigend ignoriert, denn sie würde beim nächsten Zugriff sowieso wieder geöffnet, und das wäre nicht im Sinne persistenter Verbindungen. @@ -344,11 +337,11 @@

      PersistentDB

      mod_wsgi hier Probleme bereitet, da es Daten, die mit threading.local gespeichert wurden, zwischen Requests löscht).

    -
    -

    PooledDB

    -

    Wenn Sie das PooledDB-Modul einsetzen möchten, müssen Sie zuerst einen +

    +

    PooledDB (pooled_db)

    +

    Wenn Sie das pooled_db-Modul einsetzen möchten, müssen Sie zuerst einen Pool für die von Ihnen gewünschte Art von Datenbankverbindungen einrichten, -indem Sie eine Instanz der Klasse PooledDB erzeugen, wobei Sie folgende +indem Sie eine Instanz der Klasse pooled_db erzeugen, wobei Sie folgende Parameter angeben müssen:

    • creator: entweder eine Funktion, die neue DB-API-2-Verbindungen @@ -403,14 +396,14 @@

      PooledDB

      und einen Pool von mindestens fünf Datenbankverbindungen zu Ihrer Datenbank meinedb verwenden möchten, dann sieht die Initialisierung so aus:

      import pgdb  # importiere das verwendete DB-API-2-Modul
      -from DBUtils.PooledDB import PooledDB
      +from dbutils.pooled_db import PooledDB
       pool = PooledDB(pgdb, 5, database='meinedb')

      Nachdem Sie den Pool für Datenbankverbindungen so eingerichtet haben, können Sie Verbindungen daraus wie folgt anfordern:

      db = pool.connection()

      Sie können diese Verbindungen verwenden, als wären sie gewöhnliche DB-API-2-Datenbankverbindungen. Genauer genommen erhalten Sie die -"gehärtete" SteadyDB-Version der zugrunde liegenden DB-API-2-Verbindung.

      +"gehärtete" steady_db-Version der zugrunde liegenden DB-API-2-Verbindung.

      Bitte beachten Sie, dass die Verbindung von anderen Threads mitgenutzt werden kann, wenn Sie den Parameter maxshared auf einen Wert größer als Null gesetzt haben, und der zugrunde liegende DB-API-2-Datenbankadapter dies erlaubt. @@ -441,48 +434,24 @@

      PooledDB

      ausgesetzt wird, und dass die Verbindung zurückgerollt wird, bevor sie wieder an den Verbindungspool zurückgegeben wird.

    -
    -

    Benutzung in Webware for Python

    -

    Wenn Sie DBUtils verwenden, um von Servlets des Web-Frameworks Webware -for Python auf eine Datenbank zuzugreifen, dann müssen Sie sicherstellen, -dass die Generatoren zur Erzeugung von Datenbankverbindungen nur einmal -eingerichtet werden, wenn die Anwendung startet, und nicht jedes Mal, wenn -eine Servlet-Instanz erzeugt wird. Den hierfür nötigen Code können Sie -bei der Basis-Servlet-Klasse einfügen, dort wo das Modul oder die Klasse -initialisiert wird, oder Sie können die Funktion contextInitialize() -im __init__.py-Skript Ihres Anwendungskontextes verwenden.

    -

    Das zusammen mit DButils ausgelieferte Verzeichnis Examples enthält -einen Beispielkontext für Webware for Python, der eine kleine Demo-Datenbank -verwendet, um Teilnehmer an einer Seminarreihe zu verwalten (die Idee für -dieses Beispiel wurde dem Artikel "The Python DB-API" von Andrew Kuchling -entnommen).

    -

    Der Beispielkontext kann konfiguriert werden, indem entweder eine Konfig-Datei -Configs/Database.config angelegt wird, oder indem die Standard-Parameter -direkt im Beispielservlet Examples/DBUtilsExample.py geändert werden. -Auf diese Weise können Sie einen passenden Datenbanknutzer und sein Passwort -festlegen, sowie den zugrunde liegenden Datenbankadapter auswählen (das -klassische PyGreSQL-Modul oder irgendein DB-API-2-Modul). Wenn der Parameter -maxcached vorhanden ist, verwendet das Beispielservlet die -Pooled-Variante, andernfalls die Persistent-Variante.

    -

    Anmerkungen

    -

    Wenn Sie einen der bekannten "Object-Relational Mapper" SQLObject oder -SQLAlchemy verwenden, dann benötigen Sie DBUtils nicht, denn diese haben +

    Wenn Sie einen der bekannten "Object-Relational Mapper" SQLObject oder +SQLAlchemy verwenden, dann benötigen Sie DBUtils nicht, denn diese haben ihre eigenen Mechanismen zum Pooling von Datenbankverbindungen eingebaut. Tatsächlich hat SQLObject 2 (SQL-API) das Pooling in eine separate Schicht ausgelagert, in der Code von DBUtils verwendet wird.

    Wenn Sie eine Lösung verwenden wie den Apache-Webserver mit mod_python oder mod_wsgi, dann sollten Sie bedenken, dass Ihr Python-Code normalerweise im Kontext der Kindprozesse des Webservers läuft. Wenn Sie also das -PooledDB-Modul einsetzen, und mehrere dieser Kindprozesse laufen, dann +pooled_db-Modul einsetzen, und mehrere dieser Kindprozesse laufen, dann werden Sie ebensoviele Pools mit Datenbankverbindungen erhalten. Wenn diese Prozesse viele Threads laufen lassen, dann mag dies eine sinnvoller Ansatz sein, wenn aber diese Prozesse nicht mehr als einen Worker-Thread starten, wie im Fall des Multi-Processing Moduls "prefork" für den Apache-Webserver, dann sollten Sie auf eine Middleware für das Connection-Pooling zurückgreifen, -die Multi-Processing unterstützt, wie zum Beispiel pgpool oder pgbouncer +die Multi-Processing unterstützt, wie zum Beispiel pgpool oder pgbouncer für die PostgreSQL-Datenbank.

    @@ -491,7 +460,7 @@

    Zukunft

    • Alternativ zur Obergrenze in der Anzahl der Nutzung einer Datenbankverbindung könnte eine maximale Lebensdauer für die Verbindung implementiert werden.

    • -
    • Es könnten Module MonitorDB und MonitorPg hinzugefügt werden, die +

    • Es könnten Module monitor_db und monitor_pg hinzugefügt werden, die in einem separaten Thread ständig den "idle pool" und eventuell auch den "shared pool" bzw. die persistenten Verbindungen überwachen. Wenn eine unterbrochene Datenbankverbindung entdeckt wird, wird diese automatisch durch @@ -509,10 +478,8 @@

      Zukunft

    Fehlermeldungen und Feedback

    -

    Bitte Senden Sie Fehlermeldungen, Patches und Feedback direkt an den -Autor (unter Verwendung der unten angegebenen E-Mail-Adresse).

    -

    Probleme, die Webware betreffen, können auch in der Webware for Python -mailing list diskutiert werden.

    +

    Fehlermeldungen, Patches und Feedback können Sie als Issues oder +Pull Requests auf der GitHub-Projektseite von DBUtils übermitteln.

    Autoren

    Autor
    -

    Christoph Zwerschke <cito@online.de>

    +

    Christoph Zwerschke

    Beiträge

    DBUtils benutzt Code, Anmerkungen und Vorschläge von @@ -547,7 +514,7 @@

    Autoren