├── doc ├── html ├── _static │ └── favicon.ico ├── _build │ ├── doctrees │ │ ├── faqs.doctree │ │ ├── index.doctree │ │ ├── tutorial.doctree │ │ ├── environment.pickle │ │ └── reference.doctree │ └── html │ │ ├── _static │ │ ├── file.png │ │ ├── minus.png │ │ ├── plus.png │ │ ├── favicon.ico │ │ ├── pygments.css │ │ ├── default.css │ │ ├── doctools.js │ │ ├── basic.css │ │ └── searchtools.js │ │ ├── .buildinfo │ │ ├── _sources │ │ ├── index.txt │ │ ├── faqs.txt │ │ ├── tutorial.txt │ │ └── reference.txt │ │ ├── objects.inv │ │ ├── search.html │ │ ├── modindex.html │ │ ├── searchindex.js │ │ ├── index.html │ │ ├── faqs.html │ │ ├── genindex.html │ │ └── tutorial.html ├── index.rst ├── faqs.rst ├── Makefile ├── make.bat ├── tutorial.rst ├── conf.py └── reference.rst ├── .gitignore ├── update_version.sh ├── src ├── MANIFEST ├── PySQLPool │ ├── log.py │ ├── __init__.py │ ├── pool.py │ ├── connection.py │ └── query.py └── ChangeLog ├── test ├── __init__.py ├── testLogging.py ├── testTransaction.py ├── README ├── testQuery.py ├── testPool.py └── testConnection.py ├── setup.py ├── README.rst └── LICENSE /doc/html: -------------------------------------------------------------------------------- 1 | _build/html/ -------------------------------------------------------------------------------- /doc/_static/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nerdynick/PySQLPool/HEAD/doc/_static/favicon.ico -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.svn* 2 | .project 3 | .pydevproject 4 | *.pyc 5 | PySQLPool/dist/* 6 | PySQLPool/build/* 7 | -------------------------------------------------------------------------------- /doc/_build/doctrees/faqs.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nerdynick/PySQLPool/HEAD/doc/_build/doctrees/faqs.doctree -------------------------------------------------------------------------------- /doc/_build/doctrees/index.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nerdynick/PySQLPool/HEAD/doc/_build/doctrees/index.doctree -------------------------------------------------------------------------------- /doc/_build/html/_static/file.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nerdynick/PySQLPool/HEAD/doc/_build/html/_static/file.png -------------------------------------------------------------------------------- /doc/_build/html/_static/minus.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nerdynick/PySQLPool/HEAD/doc/_build/html/_static/minus.png -------------------------------------------------------------------------------- /doc/_build/html/_static/plus.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nerdynick/PySQLPool/HEAD/doc/_build/html/_static/plus.png -------------------------------------------------------------------------------- /doc/_build/doctrees/tutorial.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nerdynick/PySQLPool/HEAD/doc/_build/doctrees/tutorial.doctree -------------------------------------------------------------------------------- /doc/_build/html/_static/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nerdynick/PySQLPool/HEAD/doc/_build/html/_static/favicon.ico -------------------------------------------------------------------------------- /doc/_build/doctrees/environment.pickle: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nerdynick/PySQLPool/HEAD/doc/_build/doctrees/environment.pickle -------------------------------------------------------------------------------- /doc/_build/doctrees/reference.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nerdynick/PySQLPool/HEAD/doc/_build/doctrees/reference.doctree -------------------------------------------------------------------------------- /update_version.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | sed -e "s#^__version__ = .*#__version__ = '$1'#" -i src/PySQLPool/__init__.py setup.py 3 | -------------------------------------------------------------------------------- /src/MANIFEST: -------------------------------------------------------------------------------- 1 | setup.py 2 | PySQLPool/PySQLConnection.py 3 | PySQLPool/PySQLPool.py 4 | PySQLPool/PySQLQuery.py 5 | PySQLPool/__init__.py 6 | -------------------------------------------------------------------------------- /doc/_build/html/.buildinfo: -------------------------------------------------------------------------------- 1 | # Sphinx build info version 1 2 | # This file hashes the configuration used when building these files. When it is not found, a full rebuild will be done. 3 | config: 513373bb6db90e2937c185cbfd4e4cb3 4 | tags: fbb0d17656682115ca4d033fb2f83ba1 5 | -------------------------------------------------------------------------------- /test/__init__.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | def suite(): 4 | modules = ['testConnection', 'testConnectionManager', 'testPool', 'testQuery', 'testTransaction', 'testLogging'] 5 | alltests = unittest.TestSuite() 6 | for module in map(__import__, modules): 7 | alltests.addTest(unittest.findTestCases(module)) 8 | 9 | return alltests 10 | 11 | if __name__ == "__main__": 12 | unittest.main(defaultTest="suite") -------------------------------------------------------------------------------- /test/testLogging.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Created on Jun 12, 2010 3 | 4 | @author: nick 5 | ''' 6 | import unittest 7 | import PySQLPool 8 | 9 | def suite(): 10 | return unittest.TestLoader().loadTestsFromTestCase(Logging) 11 | 12 | class Logging(unittest.TestCase): 13 | 14 | def setUp(self): 15 | pass 16 | 17 | def tearDown(self): 18 | pass 19 | 20 | def testLogging(self): 21 | pass 22 | 23 | def testQueryLogging(self): 24 | pass 25 | 26 | if __name__ == "__main__": 27 | unittest.main(defaultTest='suite') -------------------------------------------------------------------------------- /test/testTransaction.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Created on Jun 12, 2010 3 | 4 | @author: nick 5 | ''' 6 | import unittest 7 | import PySQLPool 8 | 9 | def suite(): 10 | return unittest.TestLoader().loadTestsFromTestCase(Transaction) 11 | 12 | class Transaction(unittest.TestCase): 13 | 14 | def setUp(self): 15 | pass 16 | 17 | def tearDown(self): 18 | pass 19 | 20 | def testContext(self): 21 | pass 22 | 23 | def testSingleThread(self): 24 | pass 25 | 26 | def testMultiThread(self): 27 | pass 28 | 29 | if __name__ == "__main__": 30 | unittest.main(defaultTest='suite') -------------------------------------------------------------------------------- /src/PySQLPool/log.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Created on Jun 14, 2010 3 | 4 | @author: nick 5 | ''' 6 | from logging import Handler 7 | import logging 8 | import PySQLPool 9 | 10 | class LogHandler(Handler): 11 | def __init__(self, level=PySQLPool.log_level): 12 | Handler.__init__(self, level) 13 | self.formatter = logging.Formatter("%(asctime)s - %(name)s:%(threadName)s - %(levelname)s - %(message)s") 14 | 15 | def flush(self): 16 | if PySQLPool.logger is not None: 17 | PySQLPool.logger.flush() 18 | 19 | def close(self): 20 | if PySQLPool.logger is not None: 21 | PySQLPool.logger.close() 22 | 23 | def emit(self, record): 24 | if PySQLPool.logger is not None: 25 | PySQLPool.logger.write(record) 26 | 27 | logger = logging.getLogger('pysqlpool') 28 | logger.setLevel(PySQLPool.log_level) 29 | logger.addHandler(LogHandler()) -------------------------------------------------------------------------------- /doc/index.rst: -------------------------------------------------------------------------------- 1 | .. PySQLPool documentation master file, created by 2 | sphinx-quickstart on Fri Nov 27 17:37:59 2009. 3 | You can adapt this file completely to your liking, but it should at least 4 | contain the root `toctree` directive. 5 | 6 | Welcome to PySQLPool's documentation! 7 | ===================================== 8 | 9 | PySQLPool_ is at the heart a Thread Safe MySQL Connection Pooling library for use with the MySQLDB Python bindings. 10 | 11 | Part of the PySQLPool_ is the MySQL Query class that handles all the thread safe connection locking, 12 | connection management in association with the Connection Manager, and cursor management. 13 | Leaving all the work you have to do in your code is write MySQL Queries. Saving you hours of work. 14 | 15 | .. _PySQLPool: http://www.code.google.com/p/pysqlpool/ 16 | 17 | .. toctree:: 18 | :maxdepth: 3 19 | 20 | tutorial.rst 21 | reference.rst 22 | faqs.rst 23 | 24 | Indices and tables 25 | ================== 26 | 27 | * :ref:`genindex` 28 | * :ref:`modindex` 29 | * :ref:`search` 30 | 31 | -------------------------------------------------------------------------------- /doc/_build/html/_sources/index.txt: -------------------------------------------------------------------------------- 1 | .. PySQLPool documentation master file, created by 2 | sphinx-quickstart on Fri Nov 27 17:37:59 2009. 3 | You can adapt this file completely to your liking, but it should at least 4 | contain the root `toctree` directive. 5 | 6 | Welcome to PySQLPool's documentation! 7 | ===================================== 8 | 9 | PySQLPool_ is at the heart a Thread Safe MySQL Connection Pooling library for use with the MySQLDB Python bindings. 10 | 11 | Part of the PySQLPool_ is the MySQL Query class that handles all the thread safe connection locking, 12 | connection management in association with the Connection Manager, and cursor management. 13 | Leaving all the work you have to do in your code is write MySQL Queries. Saving you hours of work. 14 | 15 | .. _PySQLPool: http://www.code.google.com/p/pysqlpool/ 16 | 17 | .. toctree:: 18 | :maxdepth: 3 19 | 20 | tutorial.rst 21 | reference.rst 22 | faqs.rst 23 | 24 | Indices and tables 25 | ================== 26 | 27 | * :ref:`genindex` 28 | * :ref:`modindex` 29 | * :ref:`search` 30 | 31 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | from distutils.core import setup 4 | 5 | __version__ = '0.4' 6 | __author__ = 'Nick Verbeck' 7 | __author_email__ = 'nerdynick@gmail.com' 8 | 9 | setup(name='PySQLPool', 10 | version=__version__, 11 | author=__author__, 12 | author_email=__author_email__, 13 | license='LGPL V3', 14 | platforms=['ALL'], 15 | description='Python MySQL Connection Pooling and MySQL Query management', 16 | url='https://github.com/nerdynick/PySQLPool/', 17 | download_url="http://code.google.com/p/pysqlpool/downloads/list", 18 | classifiers = [ 19 | 'Topic :: Software Development :: Libraries :: Python Modules', 20 | 'Topic :: Database', 21 | 'Programming Language :: Python', 22 | 'Operating System :: OS Independent', 23 | 'Development Status :: 5 - Production/Stable'], 24 | install_requires=['MySQL_python'], 25 | provides=['pysqlpool','PySQLPool'], 26 | packages=['PySQLPool'], 27 | package_dir={'PySQLPool': 'src/PySQLPool'} 28 | ) 29 | -------------------------------------------------------------------------------- /src/ChangeLog: -------------------------------------------------------------------------------- 1 | 0.3.6 2 | * Started Sphinx/RST style Documentation 3 | * Added LICENSE File 4 | * Added README File 5 | * Updated Email in setup.py 6 | * Added favicon to docs 7 | * Added ChangeLog 8 | * Fixes to Thread Locking Contention 9 | * Improved Hash Generation for Pool Key 10 | * Cleaned up Import Statements 11 | * Starts to future improvements to thread based MySQL transactions 12 | * Improved Python2.4 Support 13 | * Added returns of affect rows to queryMulti and queryMany 14 | * Added alias's for executeMulti, executeMany, execute, executeOne matching queryMulti, queryMany, query, queryOne respectfully 15 | * Added support for use of 'with'. ie Context Management. Submitted by Denis Malinovsky 16 | 17 | 0.4 18 | * Renaming of modules PySQLQuery to query, PySQLConnection to connection, and PySQLPool to pool. 19 | If you are importing these directly you will need to change your code. Legacy support does exist 20 | from just `import PySQLPool` and accessing them via PySQLPool.PySQLPool. 21 | * Improved transaction support 22 | * New logging system. Legacy version is not longer supported in anyway. Uses python's logging module. 23 | * Unittests. Enough said. 24 | * Renaming of base code structure. Doesn't effect release just development. -------------------------------------------------------------------------------- /test/README: -------------------------------------------------------------------------------- 1 | Unit Test Suit for PySQLPool 2 | Started 6/23/2009 3 | 4 | =========================== 5 | Sample Data 6 | =========================== 7 | All unit test provided use the Employee Sample data provided by MySQL. 8 | Make sure that the data is imported using InnoDB. This allows for 9 | transaction based tests. 10 | 11 | To get a copy of this data visit 1 of the following URLs: 12 | http://launchpad.net/test-db 13 | http://dev.mysql.com/doc/employee/en/employee.html 14 | http://dev.mysql.com/doc/#sampledb 15 | 16 | You will also need to create a user with the following info 17 | U: unittest 18 | P: zEzaj37u 19 | This user also needs full permissions to the, what should now be created, employees schema 20 | This use can be created for localhost access only or remote access. 21 | Just make sure that the user can connect to this db from the location you wish to run the tests. 22 | 23 | 24 | =========================== 25 | The Tests 26 | =========================== 27 | 28 | Each test module contains both a suit() function as well as a default run method. 29 | To allow you to run each test suit from the interactive shell as well as executing the file. 30 | 31 | The __init__.py module also contains a test suit to run all unit tests. This can be executed from 32 | the interactive shell as well a executed. -------------------------------------------------------------------------------- /doc/faqs.rst: -------------------------------------------------------------------------------- 1 | ===== 2 | FAQs 3 | ===== 4 | 5 | In an attempt to help answer some questions preemptively. A FAQ page has been create along 6 | side the with the docs. Lets hope this helps. 7 | 8 | How do I enable debugging? 9 | =========================== 10 | 11 | Currently debugging is very limited, but we do contain a simple debugging capability. You can 12 | enable debugging by assigning PySQLQuery.logging_path to a string value of a file to write the 13 | debugging output to. This will cause every query executed and any errors to be written to the 14 | supplied file. 15 | 16 | Example:: 17 | 18 | import PySQLPool 19 | 20 | PySQLPool.PySQLQuery.logging_path = '/path/to/file.txt' 21 | 22 | 23 | 24 | What type of exception are raised? 25 | =================================== 26 | 27 | At this time PySQLPool does not wrap the exceptions that come out of MySQLdb. So any and all errors 28 | thrown from any of your queries and/or other actions by MySQLdb will be of its types. Of which the base is 29 | MySQLdb.Error. To find out what error you have caused. MySQLdb.Error contains a two-element tuple called args. 30 | The 1st value will contain the MySQL error number, and the second will contain the error message. 31 | 32 | Example:: 33 | 34 | try: 35 | connection = PySQLPool.getNewConnection(username='root', password='123456', host='localhost', db='mydb') 36 | query = PySQLPool.getNewQuery(connection) 37 | query.Query('select * from table') 38 | except MySQLdb.Error, e: 39 | print "Error %d: %s" % (e.args[0], e.args[1]) 40 | sys.exit (1) 41 | -------------------------------------------------------------------------------- /doc/_build/html/_sources/faqs.txt: -------------------------------------------------------------------------------- 1 | ===== 2 | FAQs 3 | ===== 4 | 5 | In an attempt to help answer some questions preemptively. A FAQ page has been create along 6 | side the with the docs. Lets hope this helps. 7 | 8 | How do I enable debugging? 9 | =========================== 10 | 11 | Currently debugging is very limited, but we do contain a simple debugging capability. You can 12 | enable debugging by assigning PySQLQuery.logging_path to a string value of a file to write the 13 | debugging output to. This will cause every query executed and any errors to be written to the 14 | supplied file. 15 | 16 | Example:: 17 | 18 | import PySQLPool 19 | 20 | PySQLPool.PySQLQuery.logging_path = '/path/to/file.txt' 21 | 22 | 23 | 24 | What type of exception are raised? 25 | =================================== 26 | 27 | At this time PySQLPool does not wrap the exceptions that come out of MySQLdb. So any and all errors 28 | thrown from any of your queries and/or other actions by MySQLdb will be of its types. Of which the base is 29 | MySQLdb.Error. To find out what error you have caused. MySQLdb.Error contains a two-element tuple called args. 30 | The 1st value will contain the MySQL error number, and the second will contain the error message. 31 | 32 | Example:: 33 | 34 | try: 35 | connection = PySQLPool.getNewConnection(username='root', password='123456', host='localhost', db='mydb') 36 | query = PySQLPool.getNewQuery(connection) 37 | query.Query('select * from table') 38 | except MySQLdb.Error, e: 39 | print "Error %d: %s" % (e.args[0], e.args[1]) 40 | sys.exit (1) 41 | -------------------------------------------------------------------------------- /test/testQuery.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Created on Mar 22, 2011 3 | 4 | @author: nick 5 | ''' 6 | ''' 7 | Created on Jun 23, 2009 8 | 9 | @author: nick 10 | ''' 11 | import unittest 12 | import PySQLPool 13 | 14 | def suite(): 15 | return unittest.TestLoader().loadTestsFromTestCase(Query) 16 | 17 | class Query(unittest.TestCase): 18 | 19 | def setUp(self): 20 | self.username = 'unittest' 21 | self.password = 'zEzaj37u' 22 | self.host = 'localhost' 23 | self.db = 'employees' 24 | self.connDict = { 25 | "host":self.host, 26 | "user":self.username, 27 | "passwd":self.password, 28 | "db":self.db} 29 | self.connection = PySQLPool.connection.PySQLConnection(**self.connDict) 30 | 31 | def testRawQueryCreation(self): 32 | """ 33 | Raw Query Creation 34 | """ 35 | try: 36 | query = PySQLPool.query.PySQLQuery(self.connection) 37 | self.assertTrue(isinstance(query, PySQLPool.query.PySQLQuery)) 38 | except Exception, e: 39 | self.fail('Failed to create PySQLQuery Object with error: '+str(e)) 40 | 41 | def testQuickQueryCreation(self): 42 | """ 43 | Quick Query Creation 44 | """ 45 | try: 46 | query = PySQLPool.getNewQuery(self.connection) 47 | self.assertTrue(isinstance(query, PySQLPool.query.PySQLQuery)) 48 | except Exception, e: 49 | self.fail('Failed to create PySQLQuery Object with error: '+str(e)) 50 | 51 | 52 | if __name__ == "__main__": 53 | unittest.main(defaultTest='suite') -------------------------------------------------------------------------------- /README.rst: -------------------------------------------------------------------------------- 1 | ================= 2 | What is PySQLPool 3 | ================= 4 | 5 | PySQLPool is at the heart a MySQL Connection Pooling library for use with the MySQLDB Python bindings. 6 | 7 | Part of the PySQLPool is the MySQL Query class that handles all the thread safe connection locking, 8 | connection management in association with the Connection Manager, and cursor management. 9 | Leaving all the work you have to do in your code is write MySQL Queries. Saving you hours of work. 10 | 11 | ============ 12 | Installation 13 | ============ 14 | 15 | Linux/Mac OS X:: 16 | 17 | cd PySQLPool 18 | python setup.py build 19 | sudo python setup.py install 20 | 21 | - or - 22 | 23 | sudo easy_install PySQLPool 24 | 25 | Windows:: 26 | 27 | cd PySQLPool 28 | python setup.py build 29 | python setup.py install 30 | 31 | ==================== 32 | Documentation 33 | ==================== 34 | 35 | The documentation for PySQLPool is constructed using Sphinx. You can view the raw text files in 36 | doc/*, or if you wish to view an html version in doc/html/* or via the web at 37 | http://packages.python.org/PySQLPool/ 38 | 39 | ======= 40 | License 41 | ======= 42 | 43 | PySQLPool is licensed under the LGPL. You can find out more in the included LICENSE file. 44 | 45 | ================================================= 46 | Got a Bug, Question, or Idea to Improve PySQLPool 47 | ================================================= 48 | 49 | Bugs can be submitted at https://bugs.launchpad.net/pysqlpool 50 | Blueprints/Ideas can be submitted at https://blueprints.launchpad.net/pysqlpool 51 | Questions/Answers can be submitted at https://answers.edge.launchpad.net/pysqlpool 52 | 53 | ===== 54 | Links 55 | ===== 56 | 57 | Homepages: 58 | 59 | - https://github.com/nerdynick/PySQLPool (Primary Site) 60 | - http://code.google.com/p/pysqlpool/ (Legacy Site) 61 | - https://launchpad.net/pysqlpool/ (Soon to be Legacy Site) 62 | 63 | Documentation: 64 | 65 | - http://packages.python.org/PySQLPool/ 66 | 67 | 68 | =========== 69 | Development 70 | =========== 71 | 72 | Contributing 73 | ============ 74 | 75 | If you would like to contribute back to PySQLPool. Fill free to fork a branch and ask for a pull, or just submit me a patch. 76 | Eather via 'git format-patch' if you want true tracked credit or just a normal diff patch. 77 | 78 | 79 | Basic Folder Structure 80 | ====================== 81 | 82 | /doc - RST based documentation 83 | /src - Base Source Code 84 | /src/PySQLPool - Actual Source Code 85 | /test - Unittest via PyUnit 86 | -------------------------------------------------------------------------------- /src/PySQLPool/__init__.py: -------------------------------------------------------------------------------- 1 | __version__ = '0.4' 2 | __author__ = 'Nick Verbeck' 3 | __author_email__ = 'nerdynick@gmail.com' 4 | 5 | import logging 6 | logger = None 7 | log_level = logging.INFO 8 | 9 | #We rename these for legacy support. Will phase out with 1.0 most likely 10 | import connection 11 | import query 12 | import pool 13 | 14 | #Connection short cuts 15 | def getNewConnection(*args, **kargs): 16 | """ 17 | Quickly Create a new PySQLConnection class 18 | 19 | @param host: Hostname for your database 20 | @param username: Username to use to connect to database 21 | @param password: Password to use to connect to database 22 | @param schema: Schema to use 23 | @param port: Port to connect on 24 | @param commitOnEnd: Default False, When query is complete do you wish to auto commit. This is a always on for this connection 25 | @author: Nick Verbeck 26 | @since: 5/12/2008 27 | @updated: 7/19/2008 - Added commitOnEnd support 28 | """ 29 | kargs = dict(kargs) 30 | if len(args) > 0: 31 | if len(args) >= 1: 32 | kargs['host'] = args[0] 33 | if len(args) >= 2: 34 | kargs['user'] = args[1] 35 | if len(args) >= 3: 36 | kargs['passwd'] = args[2] 37 | if len(args) >= 4: 38 | kargs['db'] = args[3] 39 | if len(args) >= 5: 40 | kargs['port'] = args[4] 41 | if len(args) >= 6: 42 | kargs['commitOnEnd'] = args[5] 43 | return connection.Connection(*args, **kargs) 44 | 45 | #Query short cuts 46 | def getNewQuery(connection = None, commitOnEnd=False, *args, **kargs): 47 | """ 48 | Create a new PySQLQuery Class 49 | 50 | @param PySQLConnectionObj: Connection Object representing your connection string 51 | @param commitOnEnd: Default False, When query is complete do you wish to auto commit. This is a one time auto commit 52 | @author: Nick Verbeck 53 | @since: 5/12/2008 54 | @updated: 7/19/2008 - Added commitOnEnd support 55 | """ 56 | if connection is None: 57 | return query.PySQLQuery(getNewConnection(*args, **kargs), commitOnEnd = commitOnEnd) 58 | else: 59 | #Updated 7/24/08 to include commitOnEnd here 60 | #-Chandler Prall 61 | return query.PySQLQuery(connection, commitOnEnd = commitOnEnd) 62 | 63 | 64 | #Pool short cuts 65 | def getNewPool(): 66 | """ 67 | Create a new PySQLPool 68 | 69 | @author: Nick Verbeck 70 | @since: 5/12/2008 71 | """ 72 | return pool.Pool() 73 | 74 | def terminatePool(): 75 | """ 76 | Terminate all Connection 77 | 78 | @author: Nick Verbeck 79 | @since: 5/12/2008 80 | """ 81 | pool.Pool().Terminate() 82 | 83 | def commitPool(): 84 | """ 85 | Commits All changes in pool 86 | 87 | @author: Nick Verbeck 88 | @since: 9/12/2008 89 | """ 90 | pool.Pool().Commit() 91 | 92 | def cleanupPool(): 93 | """ 94 | Cleanup connection pool. Closing all inactive connections. 95 | 96 | @author: Nick Verbeck 97 | @since: 9/12/2008 98 | """ 99 | pool.Pool().Cleanup() -------------------------------------------------------------------------------- /doc/_build/html/objects.inv: -------------------------------------------------------------------------------- 1 | # Sphinx inventory version 1 2 | # Project: PySQLPool 3 | # Version: 0.3 4 | PySQLPool mod reference.html 5 | PySQLPool.PySQLQuery.lastError attribute reference.html 6 | PySQLPool.PySQLPool.GetConnection method reference.html 7 | PySQLPool.commitPool function reference.html 8 | PySQLPool.PySQLQuery.queryMany method reference.html 9 | PySQLPool.PySQLConnectionManager class reference.html 10 | PySQLPool.__author__ attribute reference.html 11 | PySQLPool.PySQLQuery.commitOnEnd attribute reference.html 12 | PySQLPool.PySQLQuery.QueryOne method reference.html 13 | PySQLPool.PySQLPool.maxActivePerConnection attribute reference.html 14 | PySQLPool.PySQLQuery._GetConnection method reference.html 15 | PySQLPool.PySQLQuery.Query method reference.html 16 | PySQLPool.PySQLConnectionManager.Connect method reference.html 17 | PySQLPool.PySQLConnection.key attribute reference.html 18 | PySQLPool.PySQLPool.Cleanup method reference.html 19 | PySQLPool.__version__ attribute reference.html 20 | PySQLPool.PySQLQuery.lastInsertID attribute reference.html 21 | PySQLPool.PySQLQuery.conn attribute reference.html 22 | PySQLPool.PySQLConnectionManager.Close method reference.html 23 | PySQLPool.PySQLQuery.affectedRows attribute reference.html 24 | PySQLPool.getNewQuery function reference.html 25 | PySQLPool.PySQLConnectionManager.__init__ method reference.html 26 | PySQLPool.PySQLQuery.__del__ method reference.html 27 | PySQLPool.PySQLQuery.queryOne method reference.html 28 | PySQLPool.PySQLQuery.Pool attribute reference.html 29 | PySQLPool.PySQLPool class reference.html 30 | PySQLPool.PySQLQuery.executeMany method reference.html 31 | PySQLPool.PySQLQuery.connInfo attribute reference.html 32 | PySQLPool.getNewConnection function reference.html 33 | PySQLPool.PySQLConnectionManager.TestConnection method reference.html 34 | PySQLPool.PySQLConnectionManager.ReConnect method reference.html 35 | PySQLPool.terminatePool function reference.html 36 | PySQLPool.PySQLQuery._ReturnConnection method reference.html 37 | PySQLPool.getNewPool function reference.html 38 | PySQLPool.PySQLQuery.queryMulti method reference.html 39 | PySQLPool.PySQLQuery.executeMulti method reference.html 40 | PySQLPool.PySQLConnection.info attribute reference.html 41 | PySQLPool.PySQLPool.returnConnection method reference.html 42 | PySQLPool.PySQLPool.Commit method reference.html 43 | PySQLPool.PySQLConnectionManager.Commit method reference.html 44 | PySQLPool.PySQLConnectionManager.updateCheckTime method reference.html 45 | PySQLPool.PySQLQuery.escape method reference.html 46 | PySQLPool.PySQLQuery.record attribute reference.html 47 | PySQLPool.PySQLConnection class reference.html 48 | PySQLPool.cleanupPool function reference.html 49 | PySQLPool.connection_timeout attribute reference.html 50 | PySQLPool.PySQLPool.Terminate method reference.html 51 | PySQLPool.PySQLConnection.__getattr__ method reference.html 52 | PySQLPool.PySQLQuery.escape_string method reference.html 53 | PySQLPool.PySQLPool.__pool attribute reference.html 54 | PySQLPool.PySQLQuery class reference.html 55 | PySQLPool.PySQLQuery.escapeString method reference.html 56 | PySQLPool.PySQLPool.maxActiveConnections attribute reference.html 57 | PySQLPool.PySQLQuery.query method reference.html 58 | PySQLPool.PySQLQuery.rowcount attribute reference.html 59 | -------------------------------------------------------------------------------- /doc/Makefile: -------------------------------------------------------------------------------- 1 | # Makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line. 5 | SPHINXOPTS = 6 | SPHINXBUILD = sphinx-build 7 | PAPER = 8 | 9 | # Internal variables. 10 | PAPEROPT_a4 = -D latex_paper_size=a4 11 | PAPEROPT_letter = -D latex_paper_size=letter 12 | ALLSPHINXOPTS = -d _build/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . 13 | 14 | .PHONY: help clean html dirhtml pickle json htmlhelp qthelp latex changes linkcheck doctest 15 | 16 | help: 17 | @echo "Please use \`make ' where is one of" 18 | @echo " html to make standalone HTML files" 19 | @echo " dirhtml to make HTML files named index.html in directories" 20 | @echo " pickle to make pickle files" 21 | @echo " json to make JSON files" 22 | @echo " htmlhelp to make HTML files and a HTML help project" 23 | @echo " qthelp to make HTML files and a qthelp project" 24 | @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" 25 | @echo " changes to make an overview of all changed/added/deprecated items" 26 | @echo " linkcheck to check all external links for integrity" 27 | @echo " doctest to run all doctests embedded in the documentation (if enabled)" 28 | 29 | clean: 30 | -rm -rf _build/* 31 | 32 | html: 33 | $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) _build/html 34 | @echo 35 | @echo "Build finished. The HTML pages are in _build/html." 36 | 37 | dirhtml: 38 | $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) _build/dirhtml 39 | @echo 40 | @echo "Build finished. The HTML pages are in _build/dirhtml." 41 | 42 | pickle: 43 | $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) _build/pickle 44 | @echo 45 | @echo "Build finished; now you can process the pickle files." 46 | 47 | json: 48 | $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) _build/json 49 | @echo 50 | @echo "Build finished; now you can process the JSON files." 51 | 52 | htmlhelp: 53 | $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) _build/htmlhelp 54 | @echo 55 | @echo "Build finished; now you can run HTML Help Workshop with the" \ 56 | ".hhp project file in _build/htmlhelp." 57 | 58 | qthelp: 59 | $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) _build/qthelp 60 | @echo 61 | @echo "Build finished; now you can run "qcollectiongenerator" with the" \ 62 | ".qhcp project file in _build/qthelp, like this:" 63 | @echo "# qcollectiongenerator _build/qthelp/PySQLPool.qhcp" 64 | @echo "To view the help file:" 65 | @echo "# assistant -collectionFile _build/qthelp/PySQLPool.qhc" 66 | 67 | latex: 68 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) _build/latex 69 | @echo 70 | @echo "Build finished; the LaTeX files are in _build/latex." 71 | @echo "Run \`make all-pdf' or \`make all-ps' in that directory to" \ 72 | "run these through (pdf)latex." 73 | 74 | changes: 75 | $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) _build/changes 76 | @echo 77 | @echo "The overview file is in _build/changes." 78 | 79 | linkcheck: 80 | $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) _build/linkcheck 81 | @echo 82 | @echo "Link check complete; look for any errors in the above output " \ 83 | "or in _build/linkcheck/output.txt." 84 | 85 | doctest: 86 | $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) _build/doctest 87 | @echo "Testing of doctests in the sources finished, look at the " \ 88 | "results in _build/doctest/output.txt." 89 | -------------------------------------------------------------------------------- /test/testPool.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Created on May 14, 2011 3 | 4 | @author: nick 5 | ''' 6 | import unittest 7 | from PySQLPool import pool, connection 8 | from mock import Mock 9 | 10 | def suite(): 11 | loader = unittest.TestLoader() 12 | alltests = unittest.TestSuite() 13 | alltests.addTest(loader.loadTestsFromTestCase(Pool)) 14 | 15 | return alltests 16 | 17 | class Pool(unittest.TestCase): 18 | def setUp(self): 19 | 20 | self.connDict = { 21 | "host":'localhost', 22 | "user":'unittest', 23 | "passwd":'zEzaj37u', 24 | "db":'employees'} 25 | 26 | def testPoolBorg(self): 27 | poolObj = pool.Pool() 28 | poolObj2 = pool.Pool() 29 | 30 | self.assertTrue(poolObj.connections is poolObj2.connections, msg="Connections don't match") 31 | self.assertTrue(poolObj.lock is poolObj2.lock, msg="Lock dosn't match") 32 | 33 | 34 | def testPoolGetConnection(self): 35 | #Create a mock connection object 36 | connObj = Mock(spec=connection.Connection) 37 | connObj.getKey.return_value = 'test_key' 38 | 39 | #Override the ConnectionManager for the Pool 40 | connManager = Mock(spec=connection.ConnectionManager) 41 | connManager.return_value = connManager 42 | connManager.is_locked.return_value = False 43 | pool.ConnectionManager = connManager 44 | 45 | #Make sure we get a ConnectionManager Object back 46 | connManObj = pool.Pool().GetConnection(connObj) 47 | self.assertTrue(isinstance(connManObj, connection.ConnectionManager), msg="Didn't get a ConnectionManager Object back") 48 | 49 | #Make sure our pool set persisted 50 | self.assertTrue(pool.Pool().connections.has_key('test_key'), msg="Pool doesn't contain our pool set") 51 | 52 | #Make sure our pool set only contains 1 connection object 53 | self.assertTrue(len(pool.Pool().connections['test_key']) == 1, msg="Pool doesn't contain only 1 connection for our pool set") 54 | 55 | #Re-fetch our ConnectionManager to make sure 2nd lookup work 56 | connManObj = pool.Pool().GetConnection(connObj) 57 | 58 | #Make sure our pool set only contains 1 connection object even after a 2nd call 59 | self.assertTrue(len(pool.Pool().connections['test_key']) == 1, msg="Pool doesn't contain only 1 connection for our pool set on 2nd call") 60 | 61 | #Make sure the correct methods where called as needed on the ConnectionManager 62 | connManager.Connect.assert_called_once_with() 63 | connManager.lock.assert_called_once_with() 64 | connManager.TestConnection.assert_called_once_with() 65 | connManager.release.assert_called_once_with() 66 | 67 | 68 | def testPoolTerminate(self): 69 | pass 70 | 71 | def testPoolCleanup(self): 72 | pass 73 | 74 | def testPoolCommit(self): 75 | pass 76 | 77 | def testPoolConnectionCreation(self): 78 | pass 79 | 80 | def testPoolMultiThreadGetConnection(self): 81 | pass 82 | 83 | def testPoolMultiThreadGetConnectionWithTransactions(self): 84 | pass 85 | 86 | if __name__ == "__main__": 87 | unittest.main(defaultTest='suite') -------------------------------------------------------------------------------- /doc/_build/html/_static/pygments.css: -------------------------------------------------------------------------------- 1 | .hll { background-color: #ffffcc } 2 | .c { color: #408090; font-style: italic } /* Comment */ 3 | .err { border: 1px solid #FF0000 } /* Error */ 4 | .k { color: #007020; font-weight: bold } /* Keyword */ 5 | .o { color: #666666 } /* Operator */ 6 | .cm { color: #408090; font-style: italic } /* Comment.Multiline */ 7 | .cp { color: #007020 } /* Comment.Preproc */ 8 | .c1 { color: #408090; font-style: italic } /* Comment.Single */ 9 | .cs { color: #408090; background-color: #fff0f0 } /* Comment.Special */ 10 | .gd { color: #A00000 } /* Generic.Deleted */ 11 | .ge { font-style: italic } /* Generic.Emph */ 12 | .gr { color: #FF0000 } /* Generic.Error */ 13 | .gh { color: #000080; font-weight: bold } /* Generic.Heading */ 14 | .gi { color: #00A000 } /* Generic.Inserted */ 15 | .go { color: #303030 } /* Generic.Output */ 16 | .gp { color: #c65d09; font-weight: bold } /* Generic.Prompt */ 17 | .gs { font-weight: bold } /* Generic.Strong */ 18 | .gu { color: #800080; font-weight: bold } /* Generic.Subheading */ 19 | .gt { color: #0040D0 } /* Generic.Traceback */ 20 | .kc { color: #007020; font-weight: bold } /* Keyword.Constant */ 21 | .kd { color: #007020; font-weight: bold } /* Keyword.Declaration */ 22 | .kn { color: #007020; font-weight: bold } /* Keyword.Namespace */ 23 | .kp { color: #007020 } /* Keyword.Pseudo */ 24 | .kr { color: #007020; font-weight: bold } /* Keyword.Reserved */ 25 | .kt { color: #902000 } /* Keyword.Type */ 26 | .m { color: #208050 } /* Literal.Number */ 27 | .s { color: #4070a0 } /* Literal.String */ 28 | .na { color: #4070a0 } /* Name.Attribute */ 29 | .nb { color: #007020 } /* Name.Builtin */ 30 | .nc { color: #0e84b5; font-weight: bold } /* Name.Class */ 31 | .no { color: #60add5 } /* Name.Constant */ 32 | .nd { color: #555555; font-weight: bold } /* Name.Decorator */ 33 | .ni { color: #d55537; font-weight: bold } /* Name.Entity */ 34 | .ne { color: #007020 } /* Name.Exception */ 35 | .nf { color: #06287e } /* Name.Function */ 36 | .nl { color: #002070; font-weight: bold } /* Name.Label */ 37 | .nn { color: #0e84b5; font-weight: bold } /* Name.Namespace */ 38 | .nt { color: #062873; font-weight: bold } /* Name.Tag */ 39 | .nv { color: #bb60d5 } /* Name.Variable */ 40 | .ow { color: #007020; font-weight: bold } /* Operator.Word */ 41 | .w { color: #bbbbbb } /* Text.Whitespace */ 42 | .mf { color: #208050 } /* Literal.Number.Float */ 43 | .mh { color: #208050 } /* Literal.Number.Hex */ 44 | .mi { color: #208050 } /* Literal.Number.Integer */ 45 | .mo { color: #208050 } /* Literal.Number.Oct */ 46 | .sb { color: #4070a0 } /* Literal.String.Backtick */ 47 | .sc { color: #4070a0 } /* Literal.String.Char */ 48 | .sd { color: #4070a0; font-style: italic } /* Literal.String.Doc */ 49 | .s2 { color: #4070a0 } /* Literal.String.Double */ 50 | .se { color: #4070a0; font-weight: bold } /* Literal.String.Escape */ 51 | .sh { color: #4070a0 } /* Literal.String.Heredoc */ 52 | .si { color: #70a0d0; font-style: italic } /* Literal.String.Interpol */ 53 | .sx { color: #c65d09 } /* Literal.String.Other */ 54 | .sr { color: #235388 } /* Literal.String.Regex */ 55 | .s1 { color: #4070a0 } /* Literal.String.Single */ 56 | .ss { color: #517918 } /* Literal.String.Symbol */ 57 | .bp { color: #007020 } /* Name.Builtin.Pseudo */ 58 | .vc { color: #bb60d5 } /* Name.Variable.Class */ 59 | .vg { color: #bb60d5 } /* Name.Variable.Global */ 60 | .vi { color: #bb60d5 } /* Name.Variable.Instance */ 61 | .il { color: #208050 } /* Literal.Number.Integer.Long */ -------------------------------------------------------------------------------- /doc/make.bat: -------------------------------------------------------------------------------- 1 | @ECHO OFF 2 | 3 | REM Command file for Sphinx documentation 4 | 5 | set SPHINXBUILD=sphinx-build 6 | set ALLSPHINXOPTS=-d _build/doctrees %SPHINXOPTS% . 7 | if NOT "%PAPER%" == "" ( 8 | set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS% 9 | ) 10 | 11 | if "%1" == "" goto help 12 | 13 | if "%1" == "help" ( 14 | :help 15 | echo.Please use `make ^` where ^ is one of 16 | echo. html to make standalone HTML files 17 | echo. dirhtml to make HTML files named index.html in directories 18 | echo. pickle to make pickle files 19 | echo. json to make JSON files 20 | echo. htmlhelp to make HTML files and a HTML help project 21 | echo. qthelp to make HTML files and a qthelp project 22 | echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter 23 | echo. changes to make an overview over all changed/added/deprecated items 24 | echo. linkcheck to check all external links for integrity 25 | echo. doctest to run all doctests embedded in the documentation if enabled 26 | goto end 27 | ) 28 | 29 | if "%1" == "clean" ( 30 | for /d %%i in (_build\*) do rmdir /q /s %%i 31 | del /q /s _build\* 32 | goto end 33 | ) 34 | 35 | if "%1" == "html" ( 36 | %SPHINXBUILD% -b html %ALLSPHINXOPTS% _build/html 37 | echo. 38 | echo.Build finished. The HTML pages are in _build/html. 39 | goto end 40 | ) 41 | 42 | if "%1" == "dirhtml" ( 43 | %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% _build/dirhtml 44 | echo. 45 | echo.Build finished. The HTML pages are in _build/dirhtml. 46 | goto end 47 | ) 48 | 49 | if "%1" == "pickle" ( 50 | %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% _build/pickle 51 | echo. 52 | echo.Build finished; now you can process the pickle files. 53 | goto end 54 | ) 55 | 56 | if "%1" == "json" ( 57 | %SPHINXBUILD% -b json %ALLSPHINXOPTS% _build/json 58 | echo. 59 | echo.Build finished; now you can process the JSON files. 60 | goto end 61 | ) 62 | 63 | if "%1" == "htmlhelp" ( 64 | %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% _build/htmlhelp 65 | echo. 66 | echo.Build finished; now you can run HTML Help Workshop with the ^ 67 | .hhp project file in _build/htmlhelp. 68 | goto end 69 | ) 70 | 71 | if "%1" == "qthelp" ( 72 | %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% _build/qthelp 73 | echo. 74 | echo.Build finished; now you can run "qcollectiongenerator" with the ^ 75 | .qhcp project file in _build/qthelp, like this: 76 | echo.^> qcollectiongenerator _build\qthelp\PySQLPool.qhcp 77 | echo.To view the help file: 78 | echo.^> assistant -collectionFile _build\qthelp\PySQLPool.ghc 79 | goto end 80 | ) 81 | 82 | if "%1" == "latex" ( 83 | %SPHINXBUILD% -b latex %ALLSPHINXOPTS% _build/latex 84 | echo. 85 | echo.Build finished; the LaTeX files are in _build/latex. 86 | goto end 87 | ) 88 | 89 | if "%1" == "changes" ( 90 | %SPHINXBUILD% -b changes %ALLSPHINXOPTS% _build/changes 91 | echo. 92 | echo.The overview file is in _build/changes. 93 | goto end 94 | ) 95 | 96 | if "%1" == "linkcheck" ( 97 | %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% _build/linkcheck 98 | echo. 99 | echo.Link check complete; look for any errors in the above output ^ 100 | or in _build/linkcheck/output.txt. 101 | goto end 102 | ) 103 | 104 | if "%1" == "doctest" ( 105 | %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% _build/doctest 106 | echo. 107 | echo.Testing of doctests in the sources finished, look at the ^ 108 | results in _build/doctest/output.txt. 109 | goto end 110 | ) 111 | 112 | :end 113 | -------------------------------------------------------------------------------- /doc/_build/html/search.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 7 | 8 | Search — PySQLPool v0.3.6 documentation 9 | 10 | 11 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 39 | 40 |
41 |
42 |
43 |
44 | 45 |

Search

46 |
47 | 48 |

49 | Please activate JavaScript to enable the search 50 | functionality. 51 |

52 |
53 |

54 | From here you can search these documents. Enter your search 55 | words into the box below and click "search". Note that the search 56 | function will automatically search for all of the words. Pages 57 | containing fewer words won't appear in the result list. 58 |

59 |
60 | 61 | 62 | 63 |
64 | 65 |
66 | 67 |
68 | 69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 | 90 | 91 | 96 | 97 | 98 | 99 | -------------------------------------------------------------------------------- /doc/tutorial.rst: -------------------------------------------------------------------------------- 1 | .. The "tutorial.rst" file 2 | 3 | ============================== 4 | Getting Started with PySQLPool 5 | ============================== 6 | 7 | The basic usage of PySQLPool is pretty simple as you can see in this basic example:: 8 | 9 | import PySQLPool 10 | 11 | connection = PySQLPool.getNewConnection(username='root', password='123456', host='localhost', db='mydb') 12 | query = PySQLPool.getNewQuery(connection) 13 | query.Query('select * from table') 14 | for row in query.record: 15 | print row['column'] 16 | 17 | Selecting Data 18 | ============== 19 | 20 | Here is how you would select a set of data from the DB and print it out 21 | 22 | >>> query.Query('select * from table') 23 | >>> for row in query.record: 24 | >>> print 'Column Value:', row['column'] 25 | Column Value: 0 26 | 27 | 28 | Updating Data 29 | ============= 30 | 31 | Here is how you would update a table and see how many rows your update statement affected 32 | 33 | >>> query.Query('update table set column = 1') 34 | >>> print 'Affected Rows:', query.affectedRows 35 | Affected Rows: 10 36 | 37 | Inserting New Data 38 | ================== 39 | 40 | Here is how you would insert a new row and get back its insert ID for Auto-Increment indexes 41 | 42 | >>> query.Query('insert into table ('column') values ('1')') 43 | >>> print 'Last Insert ID:', query.lastInsertID 44 | Last Insert ID: 11 45 | 46 | 47 | Using PySQLPool with Threads 48 | ============================ 49 | 50 | When using PySQLPool with threads you need to do things a little bit different from a single threaded app. 51 | The following example will show you a basic code structure you would use with a thread:: 52 | 53 | import PySQLPool 54 | import threading 55 | 56 | connection = PySQLPool.getNewConnection(username='root', password='123456', host='localhost', db='mydb') 57 | 58 | class MyThread(threading.thread): 59 | def __init__(self): 60 | ... 61 | 62 | def run(self): 63 | query = PySQLPool.getNewQuery(connection) 64 | query.Query('insert into table ('column') values ('1')') 65 | 66 | By requesting a new PySQLQuery object in the threads run method you allow the pooling layer to create new connections 67 | to the DB as needed for each thread. Don't worry you will not create 1 connect per thread but will create new ones as 68 | demand rises based on speed of threads and query execution time, but you will not create more then the limit. 69 | 70 | Setting the Max Connection Limit 71 | ================================ 72 | 73 | The max connection limit is a limiter on the auto creation of new connections based on thread demand. The limit is set 74 | globally to be used by each set of connection credentials. What that means is that for each set of connection arguments 75 | you use, specifically the host/username/password/db, the max connection limiter will keep those connections <= to its 76 | value. There currently is no way to set a limit per connection credentials. 77 | 78 | By default the limit is set to 10, but you can change it farely easy.:: 79 | 80 | import PySQLPool 81 | PySQLPool.getNewPool().maxActiveConnections = 1 82 | 83 | 84 | Stream Selected Data 85 | ==================== 86 | 87 | Sometimes you may be dealing with a very large dataset and would wish not to load it all up into memory on your local 88 | machine, but would rather let it stream back from the MySQL server row by row. You can achieve this by simply changing 89 | out what method you call on your PySQLQuery object.:: 90 | 91 | import PySQLPool 92 | 93 | connection = PySQLPool.getNewConnection(username='root', password='123456', host='localhost', db='mydb') 94 | query = PySQLPool.getNewQuery(connection) 95 | query.QueryOne('select * from table') 96 | for row in query.record: 97 | print row['column'] 98 | 99 | As you will notice we switched out the query.Query() with a query.QueryOne(). This causes PySQLPool/MySQLdb to return 100 | back to you a Python Generator that will fetch from the server row by row as you iterate through the results. 101 | 102 | -------------------------------------------------------------------------------- /doc/_build/html/_sources/tutorial.txt: -------------------------------------------------------------------------------- 1 | .. The "tutorial.rst" file 2 | 3 | ============================== 4 | Getting Started with PySQLPool 5 | ============================== 6 | 7 | The basic usage of PySQLPool is pretty simple as you can see in this basic example:: 8 | 9 | import PySQLPool 10 | 11 | connection = PySQLPool.getNewConnection(username='root', password='123456', host='localhost', db='mydb') 12 | query = PySQLPool.getNewQuery(connection) 13 | query.Query('select * from table') 14 | for row in query.record: 15 | print row['column'] 16 | 17 | Selecting Data 18 | ============== 19 | 20 | Here is how you would select a set of data from the DB and print it out 21 | 22 | >>> query.Query('select * from table') 23 | >>> for row in query.record: 24 | >>> print 'Column Value:', row['column'] 25 | Column Value: 0 26 | 27 | 28 | Updating Data 29 | ============= 30 | 31 | Here is how you would update a table and see how many rows your update statement affected 32 | 33 | >>> query.Query('update table set column = 1') 34 | >>> print 'Affected Rows:', query.affectedRows 35 | Affected Rows: 10 36 | 37 | Inserting New Data 38 | ================== 39 | 40 | Here is how you would insert a new row and get back its insert ID for Auto-Increment indexes 41 | 42 | >>> query.Query('insert into table ('column') values ('1')') 43 | >>> print 'Last Insert ID:', query.lastInsertID 44 | Last Insert ID: 11 45 | 46 | 47 | Using PySQLPool with Threads 48 | ============================ 49 | 50 | When using PySQLPool with threads you need to do things a little bit different from a single threaded app. 51 | The following example will show you a basic code structure you would use with a thread:: 52 | 53 | import PySQLPool 54 | import threading 55 | 56 | connection = PySQLPool.getNewConnection(username='root', password='123456', host='localhost', db='mydb') 57 | 58 | class MyThread(threading.thread): 59 | def __init__(self): 60 | ... 61 | 62 | def run(self): 63 | query = PySQLPool.getNewQuery(connection) 64 | query.Query('insert into table ('column') values ('1')') 65 | 66 | By requesting a new PySQLQuery object in the threads run method you allow the pooling layer to create new connections 67 | to the DB as needed for each thread. Don't worry you will not create 1 connect per thread but will create new ones as 68 | demand rises based on speed of threads and query execution time, but you will not create more then the limit. 69 | 70 | Setting the Max Connection Limit 71 | ================================ 72 | 73 | The max connection limit is a limiter on the auto creation of new connections based on thread demand. The limit is set 74 | globally to be used by each set of connection credentials. What that means is that for each set of connection arguments 75 | you use, specifically the host/username/password/db, the max connection limiter will keep those connections <= to its 76 | value. There currently is no way to set a limit per connection credentials. 77 | 78 | By default the limit is set to 10, but you can change it farely easy.:: 79 | 80 | import PySQLPool 81 | PySQLPool.getNewPool().maxActiveConnections = 1 82 | 83 | 84 | Stream Selected Data 85 | ==================== 86 | 87 | Sometimes you may be dealing with a very large dataset and would wish not to load it all up into memory on your local 88 | machine, but would rather let it stream back from the MySQL server row by row. You can achieve this by simply changing 89 | out what method you call on your PySQLQuery object.:: 90 | 91 | import PySQLPool 92 | 93 | connection = PySQLPool.getNewConnection(username='root', password='123456', host='localhost', db='mydb') 94 | query = PySQLPool.getNewQuery(connection) 95 | query.QueryOne('select * from table') 96 | for row in query.record: 97 | print row['column'] 98 | 99 | As you will notice we switched out the query.Query() with a query.QueryOne(). This causes PySQLPool/MySQLdb to return 100 | back to you a Python Generator that will fetch from the server row by row as you iterate through the results. 101 | 102 | -------------------------------------------------------------------------------- /doc/_build/html/modindex.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 7 | 8 | Global Module Index — PySQLPool v0.3.6 documentation 9 | 10 | 11 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 29 | 30 | 31 | 32 | 33 | 45 | 46 |
47 |
48 |
49 |
50 | 51 | 52 |

Global Module Index

53 | P 54 |
55 | 56 | 57 | 58 | 59 | 62 |
 
P
60 | PySQLPool 61 | MySQL Connection Pooling
63 | 64 | 65 |
66 |
67 |
68 |
69 |
70 | 82 | 83 |
84 |
85 |
86 |
87 | 99 | 104 | 105 | -------------------------------------------------------------------------------- /test/testConnection.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Created on Jun 23, 2009 3 | 4 | @author: nick 5 | ''' 6 | import unittest 7 | import PySQLPool 8 | from mock import Mock 9 | try: 10 | from hashlib import md5 11 | except Exception, e: 12 | from md5 import md5 13 | 14 | def suite(): 15 | loader = unittest.TestLoader() 16 | alltests = unittest.TestSuite() 17 | alltests.addTest(loader.loadTestsFromTestCase(Connection)) 18 | 19 | return alltests 20 | # return unittest.TestLoader().loadTestsFromTestCase(Connection) 21 | 22 | class Connection(unittest.TestCase): 23 | 24 | def setUp(self): 25 | self.username = 'unittest' 26 | self.password = 'zEzaj37u' 27 | self.host = 'localhost' 28 | self.db = 'employees' 29 | 30 | 31 | self.connDict = { 32 | "host":self.host, 33 | "user":self.username, 34 | "passwd":self.password, 35 | "db":self.db} 36 | 37 | def testRawConnectionCreation(self): 38 | """ 39 | Raw Connection Creation 40 | """ 41 | try: 42 | connection = PySQLPool.connection.Connection(host=self.host, user=self.username, passwd=self.password, db=self.db) 43 | self.assertTrue(isinstance(connection, PySQLPool.connection.Connection)) 44 | except Exception, e: 45 | self.fail("Failed to create connection with error: "+str(e)) 46 | 47 | def testRawDictConnectionCreation(self): 48 | """ 49 | Raw Connection Creation using Kargs/Dict 50 | """ 51 | try: 52 | connection = PySQLPool.connection.Connection(**self.connDict) 53 | self.assertTrue(isinstance(connection, PySQLPool.connection.Connection)) 54 | except Exception, e: 55 | self.fail("Failed to create connection with error: "+str(e)) 56 | 57 | def testQuickConnectionCreation(self): 58 | """ 59 | Quick Connection Creation 60 | """ 61 | try: 62 | connection = PySQLPool.getNewConnection(host=self.host, user=self.username, passwd=self.password, db=self.db) 63 | self.assertTrue(isinstance(connection, PySQLPool.connection.Connection)) 64 | except Exception, e: 65 | self.fail("Failed to create connection with error: "+str(e)) 66 | 67 | def testQuickDictConnectionCreation(self): 68 | """ 69 | Quick Connection Creation using Kargs/Dict 70 | """ 71 | try: 72 | connection = PySQLPool.getNewConnection(**self.connDict) 73 | self.assertTrue(isinstance(connection, PySQLPool.connection.Connection)) 74 | except Exception, e: 75 | self.fail("Failed to create connection with error: "+str(e)) 76 | 77 | def testAltConnectionOptions(self): 78 | """ 79 | Test Creating a connection with alternate arguments 80 | """ 81 | try: 82 | conArgs = { 83 | "username":"tUser", 84 | "password":"tPass", 85 | "schema":"tDB", 86 | } 87 | connection = PySQLPool.getNewConnection(**conArgs) 88 | self.assertEqual(connection.info['user'], conArgs['username'], msg="Usernames don't match") 89 | self.assertEqual(connection.info['passwd'], conArgs['password'], msg="Passwords don't match") 90 | self.assertEqual(connection.info['db'], conArgs['schema'], msg="DBs don't match") 91 | except Exception, e: 92 | self.fail("Failed to create connection with error: "+str(e)) 93 | 94 | def testHashKeyGen(self): 95 | """ 96 | Test Hash Key Generation 97 | """ 98 | try: 99 | connection = PySQLPool.getNewConnection(**self.connDict) 100 | hashStr = ''.join([str(x) for x in connection.info.values()]) 101 | key = md5(hashStr).hexdigest() 102 | self.assertEqual(connection.key, key, msg="Hash Keys don't match") 103 | except Exception, e: 104 | self.fail("Failed to create connection with error: "+str(e)) 105 | 106 | def testPossitionBasedConnectionArgs(self): 107 | """ 108 | Test Creating a connection with position based arguments 109 | """ 110 | try: 111 | conArgs = [ 112 | "tHost", 113 | "tUser", 114 | "tPass", 115 | "tDB", 116 | 3306 117 | ] 118 | connection = PySQLPool.getNewConnection(*conArgs) 119 | self.assertEqual(connection.info['host'], conArgs[0], msg="Hosts don't match") 120 | self.assertEqual(connection.info['user'], conArgs[1], msg="Usernames don't match") 121 | self.assertEqual(connection.info['passwd'], conArgs[2], msg="Passwords don't match") 122 | self.assertEqual(connection.info['db'], conArgs[3], msg="DBs don't match") 123 | self.assertEqual(connection.info['port'], conArgs[4], msg="Ports don't match") 124 | except Exception, e: 125 | self.fail("Failed to create connection with error: "+str(e)) 126 | 127 | if __name__ == "__main__": 128 | unittest.main(defaultTest='suite') -------------------------------------------------------------------------------- /doc/_build/html/_static/default.css: -------------------------------------------------------------------------------- 1 | /** 2 | * Sphinx stylesheet -- default theme 3 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 4 | */ 5 | 6 | @import url("basic.css"); 7 | 8 | /* -- page layout ----------------------------------------------------------- */ 9 | 10 | body { 11 | font-family: sans-serif; 12 | font-size: 100%; 13 | background-color: #11303d; 14 | color: #000; 15 | margin: 0; 16 | padding: 0; 17 | } 18 | 19 | div.document { 20 | background-color: #1c4e63; 21 | } 22 | 23 | div.documentwrapper { 24 | float: left; 25 | width: 100%; 26 | } 27 | 28 | div.bodywrapper { 29 | margin: 0 0 0 230px; 30 | } 31 | 32 | div.body { 33 | background-color: #ffffff; 34 | color: #000000; 35 | padding: 0 20px 30px 20px; 36 | } 37 | 38 | div.footer { 39 | color: #ffffff; 40 | width: 100%; 41 | padding: 9px 0 9px 0; 42 | text-align: center; 43 | font-size: 75%; 44 | } 45 | 46 | div.footer a { 47 | color: #ffffff; 48 | text-decoration: underline; 49 | } 50 | 51 | div.related { 52 | background-color: #133f52; 53 | line-height: 30px; 54 | color: #ffffff; 55 | } 56 | 57 | div.related a { 58 | color: #ffffff; 59 | } 60 | 61 | div.sphinxsidebar { 62 | } 63 | 64 | div.sphinxsidebar h3 { 65 | font-family: 'Trebuchet MS', sans-serif; 66 | color: #ffffff; 67 | font-size: 1.4em; 68 | font-weight: normal; 69 | margin: 0; 70 | padding: 0; 71 | } 72 | 73 | div.sphinxsidebar h3 a { 74 | color: #ffffff; 75 | } 76 | 77 | div.sphinxsidebar h4 { 78 | font-family: 'Trebuchet MS', sans-serif; 79 | color: #ffffff; 80 | font-size: 1.3em; 81 | font-weight: normal; 82 | margin: 5px 0 0 0; 83 | padding: 0; 84 | } 85 | 86 | div.sphinxsidebar p { 87 | color: #ffffff; 88 | } 89 | 90 | div.sphinxsidebar p.topless { 91 | margin: 5px 10px 10px 10px; 92 | } 93 | 94 | div.sphinxsidebar ul { 95 | margin: 10px; 96 | padding: 0; 97 | color: #ffffff; 98 | } 99 | 100 | div.sphinxsidebar a { 101 | color: #98dbcc; 102 | } 103 | 104 | div.sphinxsidebar input { 105 | border: 1px solid #98dbcc; 106 | font-family: sans-serif; 107 | font-size: 1em; 108 | } 109 | 110 | /* -- body styles ----------------------------------------------------------- */ 111 | 112 | a { 113 | color: #355f7c; 114 | text-decoration: none; 115 | } 116 | 117 | a:hover { 118 | text-decoration: underline; 119 | } 120 | 121 | div.body p, div.body dd, div.body li { 122 | text-align: justify; 123 | line-height: 130%; 124 | } 125 | 126 | div.body h1, 127 | div.body h2, 128 | div.body h3, 129 | div.body h4, 130 | div.body h5, 131 | div.body h6 { 132 | font-family: 'Trebuchet MS', sans-serif; 133 | background-color: #f2f2f2; 134 | font-weight: normal; 135 | color: #20435c; 136 | border-bottom: 1px solid #ccc; 137 | margin: 20px -20px 10px -20px; 138 | padding: 3px 0 3px 10px; 139 | } 140 | 141 | div.body h1 { margin-top: 0; font-size: 200%; } 142 | div.body h2 { font-size: 160%; } 143 | div.body h3 { font-size: 140%; } 144 | div.body h4 { font-size: 120%; } 145 | div.body h5 { font-size: 110%; } 146 | div.body h6 { font-size: 100%; } 147 | 148 | a.headerlink { 149 | color: #c60f0f; 150 | font-size: 0.8em; 151 | padding: 0 4px 0 4px; 152 | text-decoration: none; 153 | } 154 | 155 | a.headerlink:hover { 156 | background-color: #c60f0f; 157 | color: white; 158 | } 159 | 160 | div.body p, div.body dd, div.body li { 161 | text-align: justify; 162 | line-height: 130%; 163 | } 164 | 165 | div.admonition p.admonition-title + p { 166 | display: inline; 167 | } 168 | 169 | div.admonition p { 170 | margin-bottom: 5px; 171 | } 172 | 173 | div.admonition pre { 174 | margin-bottom: 5px; 175 | } 176 | 177 | div.admonition ul, div.admonition ol { 178 | margin-bottom: 5px; 179 | } 180 | 181 | div.note { 182 | background-color: #eee; 183 | border: 1px solid #ccc; 184 | } 185 | 186 | div.seealso { 187 | background-color: #ffc; 188 | border: 1px solid #ff6; 189 | } 190 | 191 | div.topic { 192 | background-color: #eee; 193 | } 194 | 195 | div.warning { 196 | background-color: #ffe4e4; 197 | border: 1px solid #f66; 198 | } 199 | 200 | p.admonition-title { 201 | display: inline; 202 | } 203 | 204 | p.admonition-title:after { 205 | content: ":"; 206 | } 207 | 208 | pre { 209 | padding: 5px; 210 | background-color: #eeffcc; 211 | color: #333333; 212 | line-height: 120%; 213 | border: 1px solid #ac9; 214 | border-left: none; 215 | border-right: none; 216 | } 217 | 218 | tt { 219 | background-color: #ecf0f3; 220 | padding: 0 1px 0 1px; 221 | font-size: 0.95em; 222 | } 223 | 224 | .warning tt { 225 | background: #efc2c2; 226 | } 227 | 228 | .note tt { 229 | background: #d6d6d6; 230 | } -------------------------------------------------------------------------------- /doc/_build/html/searchindex.js: -------------------------------------------------------------------------------- 1 | Search.setIndex({desctypes:{"0":"attribute","1":"method","2":"function","3":"class"},terms:{all:[0,1,2,3],code:[0,2],queri:[0,1,2,3],global:2,maxactiveperconnect:1,"catch":1,legal:1,follow:2,row:[1,2],privat:1,under:1,exit:3,everi:[1,3],string:[1,3],far:1,faq:[0,3],veri:[2,3],affect:[1,2],testconnect:1,iter:[1,2],"try":3,item:1,alia:1,impli:1,hors:1,mysqldb:[0,1,2,3],pass:1,further:1,port:1,index:[0,2],what:[0,1,2,3],access:1,delet:1,version:1,"new":[0,1,2],net:1,preemptiv:3,gener:[1,2],here:2,commitonend:1,path:3,along:3,standard:1,accessor:1,valu:[1,2,3],wait:1,search:0,convers:1,checksum:1,unix_socket:1,action:3,chang:[1,2],via:1,regardless:1,app:2,layer:[1,2],"boolean":1,"1st":[1,3],total:1,select:[0,1,2,3],from:[1,2,3],would:2,memori:2,two:3,next:1,call:[2,3],type:[0,3],tell:1,lastinsertid:[1,2],more:[1,2],notic:2,"__author__":1,flag:1,getconnect:1,cursorclass:1,must:1,hour:0,local:[1,2],work:[0,1],local_inifil:1,can:[1,2,3],root:[2,3],fetch:[1,2],def:2,heart:[0,1],stream:[0,2],lock:[0,1],indic:0,maxactiveconnect:[1,2],alwai:1,end:1,rather:2,charset:1,write:[0,3],how:[0,2,3],conn:1,answer:3,instead:1,simpl:[2,3],connect_timeout:1,updat:[0,1,2],fare:2,map:1,rise:2,timedelta:1,getnewqueri:[1,2,3],sql_mode:1,befor:1,mai:[1,2],associ:0,attempt:[1,3],bind:0,author:1,credenti:2,element:3,caus:[1,2,3],inform:1,"switch":2,maintain:1,allow:2,logging_path:3,talk:1,help:3,through:2,reconnect:1,queryon:[1,2],still:1,paramet:1,style:1,group:1,querymani:1,window:1,mydb:[2,3],non:1,"return":[1,2],thei:1,python:[0,1,2],auto:[1,2],safe:0,initi:1,placehold:1,document:[0,1],name:1,achiev:2,mode:1,each:[1,2],debug:[0,3],unicod:1,side:3,mean:2,replac:1,connect:[0,1,2,3],forcecheck:1,out:[2,3],estabish:1,max:[0,2],print:[2,3],given:1,free:1,infil:1,reason:1,base:[2,3],dictionari:1,releas:1,md5:1,thrown:3,thread:[0,2],keep:2,thing:2,assign:3,onc:1,number:[1,3],yourself:1,wrapper:1,differ:2,data:[0,1,2],sometim:2,messag:3,statement:[1,2],termin:1,store:1,schema:1,option:1,"__del__":1,biggest:1,part:0,kind:1,executemulti:1,keyword:1,provid:1,second:[1,3],structur:2,charact:1,"__pool":1,respons:1,argument:[1,2],karg:1,increment:2,tabl:[0,2,3],need:[1,2],zero:1,escapestr:1,self:2,note:1,exampl:[2,3],which:[1,3],singl:2,normal:1,passwd:1,object:[0,1,2],compress:1,getnewpool:[1,2],"class":[0,1,2],don:2,doc:[1,3],request:2,doe:[1,3],pipe:1,clean:1,databas:1,show:2,text:1,session:1,find:3,current:[1,2,3],onli:1,locat:1,pretti:2,notsupportederror:1,configur:1,activ:1,should:1,variu:1,analys:1,hope:3,get:[0,2],ssl:1,use_unicod:1,enabl:[0,1,3],method:[1,2],"default":[1,2],contain:[1,3],where:1,set:[0,1,2],cleanuppool:1,see:[1,2],result:[1,2],arg:[1,3],fail:1,close:1,pattern:1,written:3,"import":[2,3],kei:1,come:3,querymulti:1,last:[1,2],getnewconnect:[1,2,3],against:1,instanc:1,mani:[1,2],whole:1,load:[1,2],commitpool:1,undocu:1,"2nd":1,suppli:[1,3],pysqlqueri:[0,1,2,3],mythread:2,been:[1,3],destructor:1,basic:2,"_getconnect":1,convert:1,ani:[1,3],incrament:1,demand:2,pysqlpool:[0,1,2,3],connection_timeout:1,those:[1,2],multi:1,updatechecktim:1,sourceforg:1,cursor:[0,1],executemani:1,error:[1,3],cleanup:1,conninfo:1,have:[0,1,3],conv:1,"_returnconnect":1,worri:2,itself:1,"__init__":[1,2],let:[2,3],welcom:0,datetim:1,perform:1,terminatepool:1,same:1,client_flag:1,handl:[0,1],timestamp:1,"__version__":1,http:1,capabl:3,rais:[0,1,3],user:1,improv:1,off:1,well:1,connobj:1,client:1,command:1,thi:[1,2,3],execut:[1,2,3],tcp:1,returnconnect:1,mysql:[0,1,2,3],simpli:2,speed:2,password:[1,2,3],easi:2,hint:1,except:[0,3],littl:2,pysqlconnect:[0,1],other:3,depric:1,save:0,modul:0,match:1,around:1,read:1,escape_str:1,bit:2,lasterror:1,insert:[0,1,2],like:1,specif:2,integ:1,server:[1,2],api:1,leav:0,output:3,page:[0,3],mysql_ssl_set:1,deal:2,creation:2,some:[1,3],back:2,dead:1,librari:[0,1],init_command:1,txt:3,handal:1,"__getattr__":1,usernam:[1,2,3],larg:2,localhost:[2,3],refer:[0,1],machin:2,run:[1,2],usag:2,named_pip:1,host:[1,2,3],central:1,column:[1,2],manag:0,rowcount:1,fals:1,commit:1,disabl:1,encod:1,dataset:2,wrap:3,storag:1,your:[0,1,2,3],per:2,wai:2,support:1,question:3,fast:1,start:[0,2],lot:1,forward:1,"function":1,tupl:3,newer:1,"true":1,info:1,pysqlconnectionobj:1,wish:2,record:[1,2],limit:[0,2,3],otherwis:1,constant:1,creat:[1,2,3],repres:1,internali:1,file:[1,3],check:1,when:2,detail:1,valid:1,test:1,you:[0,1,2,3],affectedrow:[1,2],read_default_group:1,sequenc:1,sql:1,pool:[0,1,2],read_default_fil:1,time:[1,2,3],escap:1,pysqlconnectionmanag:1},titles:["Welcome to PySQLPool’s documentation!","PySQLPool Object Reference","Getting Started with PySQLPool","FAQs"],modules:{PySQLPool:1},descrefs:{"PySQLPool.PySQLQuery":{queryMany:[1,1],executeMany:[1,1],executeMulti:[1,1],affectedRows:[1,0],commitOnEnd:[1,0],escape:[1,1],query:[1,1],escape_string:[1,1],conn:[1,0],"_GetConnection":[1,1],rowcount:[1,0],Pool:[1,0],queryMulti:[1,1],"__del__":[1,1],queryOne:[1,1],"_ReturnConnection":[1,1],escapeString:[1,1],connInfo:[1,0],QueryOne:[1,1],record:[1,0],Query:[1,1],lastError:[1,0],lastInsertID:[1,0]},"PySQLPool.PySQLPool":{GetConnection:[1,1],Terminate:[1,1],"__pool":[1,0],Cleanup:[1,1],returnConnection:[1,1],maxActiveConnections:[1,0],Commit:[1,1],maxActivePerConnection:[1,0]},PySQLPool:{commitPool:[1,2],getNewConnection:[1,2],PySQLQuery:[1,3],PySQLConnection:[1,3],cleanupPool:[1,2],"__author__":[1,0],getNewPool:[1,2],PySQLPool:[1,3],getNewQuery:[1,2],connection_timeout:[1,0],"__version__":[1,0],terminatePool:[1,2],PySQLConnectionManager:[1,3]},"PySQLPool.PySQLConnectionManager":{updateCheckTime:[1,1],TestConnection:[1,1],Connect:[1,1],ReConnect:[1,1],Close:[1,1],Commit:[1,1],"__init__":[1,1]},"PySQLPool.PySQLConnection":{info:[1,0],"__getattr__":[1,1],key:[1,0]}},filenames:["index","reference","tutorial","faqs"]}) -------------------------------------------------------------------------------- /src/PySQLPool/pool.py: -------------------------------------------------------------------------------- 1 | """ 2 | @author: Nick Verbeck 3 | @since: date 5/12/2008 4 | @version: 0.2 5 | """ 6 | from threading import Condition 7 | from connection import ConnectionManager 8 | 9 | class Pool(object): 10 | """ 11 | MySQL Connection Pool Manager 12 | 13 | This is the heart of the PySQLPool Library. The borg pattern is used here to store connections and manage the connections. 14 | 15 | @author: Nick Verbeck 16 | @since: 5/18/2008 17 | @version: 0.2 18 | """ 19 | 20 | #Dictionary used for storing all Connection information 21 | __Pool = {} 22 | 23 | #Max Connections that can be opened among all connections 24 | maxActiveConnections = 10 25 | 26 | def __init__(self): 27 | """ 28 | Constructor for PySQLPool 29 | 30 | @author: Nick Verbeck 31 | @since: 5/12/2008 32 | """ 33 | self.__dict__ = self.__Pool 34 | 35 | #For 1st instantiation lets setup all our variables 36 | if not self.__dict__.has_key('lock'): 37 | self.lock = Condition() 38 | 39 | if not self.__dict__.has_key('connections'): 40 | self.connections = {} 41 | 42 | def Terminate(self): 43 | """ 44 | Close all open connections 45 | 46 | Loop though all the connections and commit all queries and close all the connections. 47 | This should be called at the end of your application. 48 | 49 | @author: Nick Verbeck 50 | @since: 5/12/2008 51 | """ 52 | 53 | self.lock.acquire() 54 | try: 55 | for bucket in self.connections.values(): 56 | try: 57 | for conn in bucket: 58 | conn.lock() 59 | try: 60 | conn.Close() 61 | except Exception: 62 | #We may throw exceptions due to already closed connections 63 | pass 64 | conn.release() 65 | except Exception: 66 | pass 67 | self.connections = {} 68 | finally: 69 | self.lock.release() 70 | 71 | def Cleanup(self): 72 | """ 73 | Cleanup Timed out connections 74 | 75 | Loop though all the connections and test if still active. If inactive close socket. 76 | 77 | @author: Nick Verbeck 78 | @since: 2/20/2009 79 | """ 80 | self.lock.acquire() 81 | try: 82 | for bucket in self.connections.values(): 83 | try: 84 | for conn in bucket: 85 | conn.lock() 86 | try: 87 | open = conn.TestConnection(forceCheck=True) 88 | if open is True: 89 | conn.commit() 90 | else: 91 | #Remove the connection from the pool. Its dead better of recreating it. 92 | index = bucket.index(conn) 93 | del bucket[index] 94 | conn.release() 95 | except Exception: 96 | conn.release() 97 | except Exception: 98 | pass 99 | finally: 100 | self.lock.release() 101 | 102 | def Commit(self): 103 | """ 104 | Commits all currently open connections 105 | 106 | @author: Nick Verbeck 107 | @since: 9/12/2008 108 | """ 109 | self.lock.acquire() 110 | try: 111 | for bucket in self.connections.values(): 112 | try: 113 | for conn in bucket: 114 | conn.lock() 115 | try: 116 | conn.commit() 117 | conn.release() 118 | except Exception: 119 | conn.release() 120 | except Exception: 121 | pass 122 | finally: 123 | self.lock.release() 124 | 125 | def GetConnection(self, ConnectionObj): 126 | """ 127 | Get a Open and active connection 128 | 129 | Returns a PySQLConnectionManager if one is open else it will create a new one if the max active connections hasn't been hit. 130 | If all possible connections are used. Then None is returned. 131 | 132 | @param PySQLConnectionObj: PySQLConnection Object representing your connection string 133 | @author: Nick Verbeck 134 | @since: 5/12/2008 135 | """ 136 | 137 | key = ConnectionObj.getKey() 138 | 139 | connection = None 140 | 141 | if self.connections.has_key(key): 142 | connection = self._getConnectionFromPoolSet(key) 143 | 144 | if connection is None: 145 | self.lock.acquire() 146 | if len(self.connections[key]) < self.maxActiveConnections: 147 | #Create a new connection 148 | connection = self._createConnection(ConnectionObj) 149 | self.connections[key].append(connection) 150 | self.lock.release() 151 | else: 152 | #Wait for a free connection. We maintain the lock on the pool so we are the 1st to get a connection. 153 | while connection is None: 154 | connection = self._getConnectionFromPoolSet(key) 155 | self.lock.release() 156 | 157 | #Create new Connection Pool Set 158 | else: 159 | self.lock.acquire() 160 | #We do a double check now that its locked to be sure some other thread didn't create this while we may have been waiting. 161 | if not self.connections.has_key(key): 162 | self.connections[key] = [] 163 | 164 | if len(self.connections[key]) < self.maxActiveConnections: 165 | #Create a new connection 166 | connection = self._createConnection(ConnectionObj) 167 | self.connections[key].append(connection) 168 | else: 169 | #A rare thing happened. So many threads created connections so fast we need to wait for a free one. 170 | while connection is None: 171 | connection = self._getConnectionFromPoolSet(key) 172 | self.lock.release() 173 | 174 | return connection 175 | 176 | def _getConnectionFromPoolSet(self, key): 177 | connection = None 178 | 179 | for conn in self.connections[key]: 180 | #Grab an active connection if maxActivePerConnection is not meet 181 | #TODO: Implement a max usage per connection object 182 | if not conn.is_locked(): 183 | conn.lock() 184 | try: 185 | if conn.TestConnection() is False: 186 | conn.ReConnect() 187 | 188 | connection = conn 189 | conn.release() 190 | except Exception: 191 | conn.release() 192 | raise 193 | 194 | return connection 195 | 196 | 197 | def _createConnection(self, info): 198 | connection = ConnectionManager(info) 199 | connection.Connect() 200 | 201 | return connection 202 | -------------------------------------------------------------------------------- /doc/conf.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # PySQLPool documentation build configuration file, created by 4 | # sphinx-quickstart on Fri Nov 27 17:37:59 2009. 5 | # 6 | # This file is execfile()d with the current directory set to its containing dir. 7 | # 8 | # Note that not all possible configuration values are present in this 9 | # autogenerated file. 10 | # 11 | # All configuration values have a default; values that are commented out 12 | # serve to show the default. 13 | 14 | import sys, os 15 | 16 | # If extensions (or modules to document with autodoc) are in another directory, 17 | # add these directories to sys.path here. If the directory is relative to the 18 | # documentation root, use os.path.abspath to make it absolute, like shown here. 19 | #sys.path.append(os.path.abspath('.')) 20 | 21 | # -- General configuration ----------------------------------------------------- 22 | 23 | # Add any Sphinx extension module names here, as strings. They can be extensions 24 | # coming with Sphinx (named 'sphinx.ext.*') or your custom ones. 25 | extensions = ['sphinx.ext.coverage'] 26 | 27 | # Add any paths that contain templates here, relative to this directory. 28 | templates_path = ['_templates'] 29 | 30 | # The suffix of source filenames. 31 | source_suffix = '.rst' 32 | 33 | # The encoding of source files. 34 | #source_encoding = 'utf-8' 35 | 36 | # The master toctree document. 37 | master_doc = 'index' 38 | 39 | # General information about the project. 40 | project = u'PySQLPool' 41 | copyright = u'2009, Nick Verbeck' 42 | 43 | # The version info for the project you're documenting, acts as replacement for 44 | # |version| and |release|, also used in various other places throughout the 45 | # built documents. 46 | # 47 | # The short X.Y version. 48 | version = '0.3' 49 | # The full version, including alpha/beta/rc tags. 50 | release = '0.3.6' 51 | 52 | # The language for content autogenerated by Sphinx. Refer to documentation 53 | # for a list of supported languages. 54 | #language = None 55 | 56 | # There are two options for replacing |today|: either, you set today to some 57 | # non-false value, then it is used: 58 | #today = '' 59 | # Else, today_fmt is used as the format for a strftime call. 60 | #today_fmt = '%B %d, %Y' 61 | 62 | # List of documents that shouldn't be included in the build. 63 | #unused_docs = [] 64 | 65 | # List of directories, relative to source directory, that shouldn't be searched 66 | # for source files. 67 | exclude_trees = ['_build'] 68 | 69 | # The reST default role (used for this markup: `text`) to use for all documents. 70 | #default_role = None 71 | 72 | # If true, '()' will be appended to :func: etc. cross-reference text. 73 | #add_function_parentheses = True 74 | 75 | # If true, the current module name will be prepended to all description 76 | # unit titles (such as .. function::). 77 | #add_module_names = True 78 | 79 | # If true, sectionauthor and moduleauthor directives will be shown in the 80 | # output. They are ignored by default. 81 | #show_authors = False 82 | 83 | # The name of the Pygments (syntax highlighting) style to use. 84 | pygments_style = 'sphinx' 85 | 86 | # A list of ignored prefixes for module index sorting. 87 | #modindex_common_prefix = [] 88 | 89 | 90 | # -- Options for HTML output --------------------------------------------------- 91 | 92 | # The theme to use for HTML and HTML Help pages. Major themes that come with 93 | # Sphinx are currently 'default' and 'sphinxdoc'. 94 | html_theme = 'default' 95 | 96 | # Theme options are theme-specific and customize the look and feel of a theme 97 | # further. For a list of options available for each theme, see the 98 | # documentation. 99 | #html_theme_options = {} 100 | 101 | # Add any paths that contain custom themes here, relative to this directory. 102 | #html_theme_path = [] 103 | 104 | # The name for this set of Sphinx documents. If None, it defaults to 105 | # " v documentation". 106 | #html_title = None 107 | 108 | # A shorter title for the navigation bar. Default is the same as html_title. 109 | #html_short_title = None 110 | 111 | # The name of an image file (relative to this directory) to place at the top 112 | # of the sidebar. 113 | #html_logo = None 114 | 115 | # The name of an image file (within the static path) to use as favicon of the 116 | # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 117 | # pixels large. 118 | html_favicon = "favicon.ico" 119 | 120 | # Add any paths that contain custom static files (such as style sheets) here, 121 | # relative to this directory. They are copied after the builtin static files, 122 | # so a file named "default.css" will overwrite the builtin "default.css". 123 | html_static_path = ['_static'] 124 | 125 | # If not '', a 'Last updated on:' timestamp is inserted at every page bottom, 126 | # using the given strftime format. 127 | html_last_updated_fmt = '%b %d, %Y' 128 | 129 | # If true, SmartyPants will be used to convert quotes and dashes to 130 | # typographically correct entities. 131 | #html_use_smartypants = True 132 | 133 | # Custom sidebar templates, maps document names to template names. 134 | #html_sidebars = {} 135 | 136 | # Additional templates that should be rendered to pages, maps page names to 137 | # template names. 138 | #html_additional_pages = {} 139 | 140 | # If false, no module index is generated. 141 | #html_use_modindex = True 142 | 143 | # If false, no index is generated. 144 | #html_use_index = True 145 | 146 | # If true, the index is split into individual pages for each letter. 147 | #html_split_index = False 148 | 149 | # If true, links to the reST sources are added to the pages. 150 | #html_show_sourcelink = True 151 | 152 | # If true, an OpenSearch description file will be output, and all pages will 153 | # contain a tag referring to it. The value of this option must be the 154 | # base URL from which the finished HTML is served. 155 | #html_use_opensearch = '' 156 | 157 | # If nonempty, this is the file name suffix for HTML files (e.g. ".xhtml"). 158 | #html_file_suffix = '' 159 | 160 | # Output file base name for HTML help builder. 161 | htmlhelp_basename = 'PySQLPooldoc' 162 | 163 | 164 | # -- Options for LaTeX output -------------------------------------------------- 165 | 166 | # The paper size ('letter' or 'a4'). 167 | #latex_paper_size = 'letter' 168 | 169 | # The font size ('10pt', '11pt' or '12pt'). 170 | #latex_font_size = '10pt' 171 | 172 | # Grouping the document tree into LaTeX files. List of tuples 173 | # (source start file, target name, title, author, documentclass [howto/manual]). 174 | latex_documents = [ 175 | ('index', 'PySQLPool.tex', u'PySQLPool Documentation', 176 | u'Nick Verbeck', 'manual'), 177 | ] 178 | 179 | # The name of an image file (relative to this directory) to place at the top of 180 | # the title page. 181 | #latex_logo = None 182 | 183 | # For "manual" documents, if this is true, then toplevel headings are parts, 184 | # not chapters. 185 | #latex_use_parts = False 186 | 187 | # Additional stuff for the LaTeX preamble. 188 | #latex_preamble = '' 189 | 190 | # Documents to append as an appendix to all manuals. 191 | #latex_appendices = [] 192 | 193 | # If false, no module index is generated. 194 | #latex_use_modindex = True 195 | -------------------------------------------------------------------------------- /doc/_build/html/_static/doctools.js: -------------------------------------------------------------------------------- 1 | /// XXX: make it cross browser 2 | 3 | /** 4 | * make the code below compatible with browsers without 5 | * an installed firebug like debugger 6 | */ 7 | if (!window.console || !console.firebug) { 8 | var names = ["log", "debug", "info", "warn", "error", "assert", "dir", "dirxml", 9 | "group", "groupEnd", "time", "timeEnd", "count", "trace", "profile", "profileEnd"]; 10 | window.console = {}; 11 | for (var i = 0; i < names.length; ++i) 12 | window.console[names[i]] = function() {} 13 | } 14 | 15 | /** 16 | * small helper function to urldecode strings 17 | */ 18 | jQuery.urldecode = function(x) { 19 | return decodeURIComponent(x).replace(/\+/g, ' '); 20 | } 21 | 22 | /** 23 | * small helper function to urlencode strings 24 | */ 25 | jQuery.urlencode = encodeURIComponent; 26 | 27 | /** 28 | * This function returns the parsed url parameters of the 29 | * current request. Multiple values per key are supported, 30 | * it will always return arrays of strings for the value parts. 31 | */ 32 | jQuery.getQueryParameters = function(s) { 33 | if (typeof s == 'undefined') 34 | s = document.location.search; 35 | var parts = s.substr(s.indexOf('?') + 1).split('&'); 36 | var result = {}; 37 | for (var i = 0; i < parts.length; i++) { 38 | var tmp = parts[i].split('=', 2); 39 | var key = jQuery.urldecode(tmp[0]); 40 | var value = jQuery.urldecode(tmp[1]); 41 | if (key in result) 42 | result[key].push(value); 43 | else 44 | result[key] = [value]; 45 | } 46 | return result; 47 | } 48 | 49 | /** 50 | * small function to check if an array contains 51 | * a given item. 52 | */ 53 | jQuery.contains = function(arr, item) { 54 | for (var i = 0; i < arr.length; i++) { 55 | if (arr[i] == item) 56 | return true; 57 | } 58 | return false; 59 | } 60 | 61 | /** 62 | * highlight a given string on a jquery object by wrapping it in 63 | * span elements with the given class name. 64 | */ 65 | jQuery.fn.highlightText = function(text, className) { 66 | function highlight(node) { 67 | if (node.nodeType == 3) { 68 | var val = node.nodeValue; 69 | var pos = val.toLowerCase().indexOf(text); 70 | if (pos >= 0 && !jQuery.className.has(node.parentNode, className)) { 71 | var span = document.createElement("span"); 72 | span.className = className; 73 | span.appendChild(document.createTextNode(val.substr(pos, text.length))); 74 | node.parentNode.insertBefore(span, node.parentNode.insertBefore( 75 | document.createTextNode(val.substr(pos + text.length)), 76 | node.nextSibling)); 77 | node.nodeValue = val.substr(0, pos); 78 | } 79 | } 80 | else if (!jQuery(node).is("button, select, textarea")) { 81 | jQuery.each(node.childNodes, function() { 82 | highlight(this) 83 | }); 84 | } 85 | } 86 | return this.each(function() { 87 | highlight(this); 88 | }); 89 | } 90 | 91 | /** 92 | * Small JavaScript module for the documentation. 93 | */ 94 | var Documentation = { 95 | 96 | init : function() { 97 | this.fixFirefoxAnchorBug(); 98 | this.highlightSearchWords(); 99 | this.initModIndex(); 100 | }, 101 | 102 | /** 103 | * i18n support 104 | */ 105 | TRANSLATIONS : {}, 106 | PLURAL_EXPR : function(n) { return n == 1 ? 0 : 1; }, 107 | LOCALE : 'unknown', 108 | 109 | // gettext and ngettext don't access this so that the functions 110 | // can savely bound to a different name (_ = Documentation.gettext) 111 | gettext : function(string) { 112 | var translated = Documentation.TRANSLATIONS[string]; 113 | if (typeof translated == 'undefined') 114 | return string; 115 | return (typeof translated == 'string') ? translated : translated[0]; 116 | }, 117 | 118 | ngettext : function(singular, plural, n) { 119 | var translated = Documentation.TRANSLATIONS[singular]; 120 | if (typeof translated == 'undefined') 121 | return (n == 1) ? singular : plural; 122 | return translated[Documentation.PLURALEXPR(n)]; 123 | }, 124 | 125 | addTranslations : function(catalog) { 126 | for (var key in catalog.messages) 127 | this.TRANSLATIONS[key] = catalog.messages[key]; 128 | this.PLURAL_EXPR = new Function('n', 'return +(' + catalog.plural_expr + ')'); 129 | this.LOCALE = catalog.locale; 130 | }, 131 | 132 | /** 133 | * add context elements like header anchor links 134 | */ 135 | addContextElements : function() { 136 | $('div[id] > :header:first').each(function() { 137 | $('\u00B6'). 138 | attr('href', '#' + this.id). 139 | attr('title', _('Permalink to this headline')). 140 | appendTo(this); 141 | }); 142 | $('dt[id]').each(function() { 143 | $('\u00B6'). 144 | attr('href', '#' + this.id). 145 | attr('title', _('Permalink to this definition')). 146 | appendTo(this); 147 | }); 148 | }, 149 | 150 | /** 151 | * workaround a firefox stupidity 152 | */ 153 | fixFirefoxAnchorBug : function() { 154 | if (document.location.hash && $.browser.mozilla) 155 | window.setTimeout(function() { 156 | document.location.href += ''; 157 | }, 10); 158 | }, 159 | 160 | /** 161 | * highlight the search words provided in the url in the text 162 | */ 163 | highlightSearchWords : function() { 164 | var params = $.getQueryParameters(); 165 | var terms = (params.highlight) ? params.highlight[0].split(/\s+/) : []; 166 | if (terms.length) { 167 | var body = $('div.body'); 168 | window.setTimeout(function() { 169 | $.each(terms, function() { 170 | body.highlightText(this.toLowerCase(), 'highlight'); 171 | }); 172 | }, 10); 173 | $('') 175 | .appendTo($('.sidebar .this-page-menu')); 176 | } 177 | }, 178 | 179 | /** 180 | * init the modindex toggle buttons 181 | */ 182 | initModIndex : function() { 183 | var togglers = $('img.toggler').click(function() { 184 | var src = $(this).attr('src'); 185 | var idnum = $(this).attr('id').substr(7); 186 | console.log($('tr.cg-' + idnum).toggle()); 187 | if (src.substr(-9) == 'minus.png') 188 | $(this).attr('src', src.substr(0, src.length-9) + 'plus.png'); 189 | else 190 | $(this).attr('src', src.substr(0, src.length-8) + 'minus.png'); 191 | }).css('display', ''); 192 | if (DOCUMENTATION_OPTIONS.COLLAPSE_MODINDEX) { 193 | togglers.click(); 194 | } 195 | }, 196 | 197 | /** 198 | * helper function to hide the search marks again 199 | */ 200 | hideSearchWords : function() { 201 | $('.sidebar .this-page-menu li.highlight-link').fadeOut(300); 202 | $('span.highlight').removeClass('highlight'); 203 | }, 204 | 205 | /** 206 | * make the url absolute 207 | */ 208 | makeURL : function(relativeURL) { 209 | return DOCUMENTATION_OPTIONS.URL_ROOT + '/' + relativeURL; 210 | }, 211 | 212 | /** 213 | * get the current relative url 214 | */ 215 | getCurrentURL : function() { 216 | var path = document.location.pathname; 217 | var parts = path.split(/\//); 218 | $.each(DOCUMENTATION_OPTIONS.URL_ROOT.split(/\//), function() { 219 | if (this == '..') 220 | parts.pop(); 221 | }); 222 | var url = parts.join('/'); 223 | return path.substring(url.lastIndexOf('/') + 1, path.length - 1); 224 | } 225 | }; 226 | 227 | // quick alias for translations 228 | _ = Documentation.gettext; 229 | 230 | $(document).ready(function() { 231 | Documentation.init(); 232 | }); 233 | -------------------------------------------------------------------------------- /src/PySQLPool/connection.py: -------------------------------------------------------------------------------- 1 | """ 2 | @author: Nick Verbeck 3 | @since: 5/12/2008 4 | """ 5 | import MySQLdb 6 | import datetime 7 | from threading import Semaphore 8 | 9 | try: 10 | from hashlib import md5 11 | except Exception, e: 12 | from md5 import md5 13 | 14 | class Connection(object): 15 | """ 16 | Command Pattern Object to store connection information for use in PySQLPool 17 | 18 | @author: Nick Verbeck 19 | @since: 5/12/2008 20 | @version: 0.1 21 | """ 22 | 23 | def __init__(self, *args, **kargs): 24 | """ 25 | Constructor for the Connection class 26 | @param commitOnEnd: Default False, When query is complete do you wish to auto commit. This is a always on for this connection 27 | @author: Nick Verbeck 28 | @since: 5/12/2008 29 | @updated: 7/19/2008 - Added commitOnEnd 30 | @updated: 10/26/2008 - Switched to use *args and **kargs 31 | """ 32 | self.info = { 33 | 'host': 'localhost', 34 | 'user': 'root', 35 | 'passwd': '', 36 | 'db': '', 37 | 'port': 3306 38 | } 39 | if kargs.has_key('host'): 40 | self.info['host'] = kargs['host'] 41 | if kargs.has_key('user'): 42 | self.info['user'] = kargs['user'] 43 | if kargs.has_key('passwd'): 44 | self.info['passwd'] = kargs['passwd'] 45 | if kargs.has_key('db'): 46 | self.info['db'] = kargs['db'] 47 | if kargs.has_key('port'): 48 | self.info['port'] = int(kargs['port']) 49 | if kargs.has_key('connect_timeout'): 50 | self.info['connect_timeout'] = kargs['connect_timeout'] 51 | if kargs.has_key('use_unicode'): 52 | self.info['use_unicode'] = kargs['use_unicode'] 53 | if kargs.has_key('charset'): 54 | self.info['charset'] = kargs['charset'] 55 | if kargs.has_key('local_infile'): 56 | self.info['local_infile'] = kargs['local_infile'] 57 | 58 | #Support Legacy Username 59 | if kargs.has_key('username'): 60 | self.info['user'] = kargs['username'] 61 | #Support Legacy Password 62 | if kargs.has_key('password'): 63 | self.info['passwd'] = kargs['password'] 64 | #Support Legacy Schema 65 | if kargs.has_key('schema'): 66 | self.info['db'] = kargs['schema'] 67 | 68 | if kargs.has_key('commitOnEnd'): 69 | self.commitOnEnd = kargs['commitOnEnd'] 70 | else: 71 | self.commitOnEnd = False 72 | 73 | hashStr = ''.join([str(x) for x in self.info.values()]) 74 | self.key = md5(hashStr).hexdigest() 75 | 76 | def __getattr__(self, name): 77 | try: 78 | return self.info[name] 79 | except Exception, e: 80 | return None 81 | 82 | def getKey(self): 83 | return self.key 84 | 85 | connection_timeout = datetime.timedelta(seconds=20) 86 | 87 | class ConnectionManager(object): 88 | """ 89 | Physical Connection manager 90 | 91 | Used to manage the physical MySQL connection and the thread safe locks on that connection 92 | 93 | @author: Nick Verbeck 94 | @since: 5/12/2008 95 | @version: 0.1 96 | """ 97 | def __init__(self, connectionInfo): 98 | """ 99 | Constructor for ConnectionManager 100 | 101 | @param connectionInfo: Connection Object representing your connection string 102 | @author: Nick Verbeck 103 | @since: 5/12/2008 104 | """ 105 | 106 | self.connectionInfo = connectionInfo 107 | self.connection = None 108 | 109 | #Lock management 110 | self._lock = Semaphore() 111 | self._locked = False 112 | 113 | self.activeConnections = 0 114 | self.query = None 115 | self.lastConnectionCheck = None 116 | 117 | def lock(self, block=True): 118 | """ 119 | Lock connection from being used else where 120 | """ 121 | self._locked = True 122 | return self._lock.acquire(block) 123 | 124 | def release(self): 125 | """ 126 | Release the connection lock 127 | """ 128 | if self._locked is True: 129 | self._locked = False 130 | self._lock.release() 131 | 132 | def is_locked(self): 133 | """ 134 | Returns the status of this connection 135 | """ 136 | return self._locked 137 | 138 | def getCursor(self): 139 | """ 140 | Get a Dictionary Cursor for executing queries 141 | """ 142 | if self.connection is None: 143 | self.Connect() 144 | 145 | return self.connection.cursor(MySQLdb.cursors.DictCursor) 146 | 147 | def _updateCheckTime(self): 148 | """ 149 | Updates the connection check timestamp 150 | """ 151 | self.lastConnectionCheck = datetime.datetime.now() 152 | 153 | def Connect(self): 154 | """ 155 | Creates a new physical connection to the database 156 | 157 | @author: Nick Verbeck 158 | @since: 5/12/2008 159 | """ 160 | if self.connection is None: 161 | self.connection = MySQLdb.connect(*[], **self.connectionInfo.info) 162 | 163 | if self.connectionInfo.commitOnEnd is True: 164 | self.connection.autocommit() 165 | 166 | self._updateCheckTime() 167 | 168 | def autoCommit(self, autocommit): 169 | self.connectionInfo.commitOnEnd = autocommit 170 | if autocommit is True and self.connection is not None: 171 | self.connection.autocommit() 172 | 173 | def ReConnect(self): 174 | """ 175 | Attempts to close current connection if open and re-opens a new connection to the database 176 | 177 | @author: Nick Verbeck 178 | @since: 5/12/2008 179 | """ 180 | self.Close() 181 | self.Connect() 182 | 183 | def TestConnection(self, forceCheck = False): 184 | """ 185 | Tests the current physical connection if it is open and hasn't timed out 186 | 187 | @return: boolean True is connection is open, False if connection is closed 188 | @author: Nick Verbeck 189 | @since: 5/12/2008 190 | """ 191 | if self.connection is None: 192 | return False 193 | elif forceCheck is True or (datetime.datetime.now() - self.lastConnectionCheck) >= connection_timeout: 194 | try: 195 | #TODO: Find a better way to test if connection is open 196 | cursor = self.connection.cursor(MySQLdb.cursors.DictCursor) 197 | cursor.execute('select current_user') 198 | self._updateCheckTime() 199 | return True 200 | except Exception, e: 201 | self.connection.close() 202 | self.connection = None 203 | return False 204 | else: 205 | return True 206 | 207 | def being(self): 208 | """ 209 | Being a Transaction 210 | 211 | @author: Nick Verbeck 212 | @since: 5/14/2011 213 | """ 214 | try: 215 | if self.connection is not None: 216 | self.lock() 217 | c = self.getCursor() 218 | c.execute('BEGIN;') 219 | c.close() 220 | except Exception, e: 221 | pass 222 | 223 | 224 | def commit(self): 225 | """ 226 | Commit MySQL Transaction to database. 227 | MySQLDB: If the database and the tables support transactions, 228 | this commits the current transaction; otherwise 229 | this method successfully does nothing. 230 | 231 | @author: Nick Verbeck 232 | @since: 5/12/2008 233 | """ 234 | try: 235 | if self.connection is not None: 236 | self.connection.commit() 237 | self._updateCheckTime() 238 | self.release() 239 | except Exception, e: 240 | pass 241 | Commit = commit 242 | 243 | def rollback(self): 244 | """ 245 | Rollback MySQL Transaction to database. 246 | MySQLDB: If the database and tables support transactions, this rolls 247 | back (cancels) the current transaction; otherwise a 248 | NotSupportedError is raised. 249 | 250 | @author: Nick Verbeck 251 | @since: 5/12/2008 252 | """ 253 | try: 254 | if self.connection is not None: 255 | self.connection.rollback() 256 | self._updateCheckTime() 257 | self.release() 258 | except Exception, e: 259 | pass 260 | 261 | def Close(self): 262 | """ 263 | Commits and closes the current connection 264 | 265 | @author: Nick Verbeck 266 | @since: 5/12/2008 267 | """ 268 | if self.connection is not None: 269 | try: 270 | self.connection.commit() 271 | self.connection.close() 272 | self.connection = None 273 | except Exception, e: 274 | pass 275 | -------------------------------------------------------------------------------- /doc/_build/html/index.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 7 | 8 | Welcome to PySQLPool’s documentation! — PySQLPool v0.3.6 documentation 9 | 10 | 11 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 42 | 43 |
44 |
45 |
46 |
47 | 48 |
49 |

Welcome to PySQLPool’s documentation!

50 |

PySQLPool is at the heart a Thread Safe MySQL Connection Pooling library for use with the MySQLDB Python bindings.

51 |

Part of the PySQLPool is the MySQL Query class that handles all the thread safe connection locking, 52 | connection management in association with the Connection Manager, and cursor management. 53 | Leaving all the work you have to do in your code is write MySQL Queries. Saving you hours of work.

54 | 77 |
78 |
79 |

Indices and tables

80 | 85 |
86 | 87 | 88 |
89 |
90 |
91 |
92 |
93 |

Table Of Contents

94 | 100 | 101 |

Next topic

102 |

Getting Started with PySQLPool

104 |

This Page

105 | 109 | 121 | 122 |
123 |
124 |
125 |
126 | 141 | 146 | 147 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU LESSER GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | 9 | This version of the GNU Lesser General Public License incorporates 10 | the terms and conditions of version 3 of the GNU General Public 11 | License, supplemented by the additional permissions listed below. 12 | 13 | 0. Additional Definitions. 14 | 15 | As used herein, "this License" refers to version 3 of the GNU Lesser 16 | General Public License, and the "GNU GPL" refers to version 3 of the GNU 17 | General Public License. 18 | 19 | "The Library" refers to a covered work governed by this License, 20 | other than an Application or a Combined Work as defined below. 21 | 22 | An "Application" is any work that makes use of an interface provided 23 | by the Library, but which is not otherwise based on the Library. 24 | Defining a subclass of a class defined by the Library is deemed a mode 25 | of using an interface provided by the Library. 26 | 27 | A "Combined Work" is a work produced by combining or linking an 28 | Application with the Library. The particular version of the Library 29 | with which the Combined Work was made is also called the "Linked 30 | Version". 31 | 32 | The "Minimal Corresponding Source" for a Combined Work means the 33 | Corresponding Source for the Combined Work, excluding any source code 34 | for portions of the Combined Work that, considered in isolation, are 35 | based on the Application, and not on the Linked Version. 36 | 37 | The "Corresponding Application Code" for a Combined Work means the 38 | object code and/or source code for the Application, including any data 39 | and utility programs needed for reproducing the Combined Work from the 40 | Application, but excluding the System Libraries of the Combined Work. 41 | 42 | 1. Exception to Section 3 of the GNU GPL. 43 | 44 | You may convey a covered work under sections 3 and 4 of this License 45 | without being bound by section 3 of the GNU GPL. 46 | 47 | 2. Conveying Modified Versions. 48 | 49 | If you modify a copy of the Library, and, in your modifications, a 50 | facility refers to a function or data to be supplied by an Application 51 | that uses the facility (other than as an argument passed when the 52 | facility is invoked), then you may convey a copy of the modified 53 | version: 54 | 55 | a) under this License, provided that you make a good faith effort to 56 | ensure that, in the event an Application does not supply the 57 | function or data, the facility still operates, and performs 58 | whatever part of its purpose remains meaningful, or 59 | 60 | b) under the GNU GPL, with none of the additional permissions of 61 | this License applicable to that copy. 62 | 63 | 3. Object Code Incorporating Material from Library Header Files. 64 | 65 | The object code form of an Application may incorporate material from 66 | a header file that is part of the Library. You may convey such object 67 | code under terms of your choice, provided that, if the incorporated 68 | material is not limited to numerical parameters, data structure 69 | layouts and accessors, or small macros, inline functions and templates 70 | (ten or fewer lines in length), you do both of the following: 71 | 72 | a) Give prominent notice with each copy of the object code that the 73 | Library is used in it and that the Library and its use are 74 | covered by this License. 75 | 76 | b) Accompany the object code with a copy of the GNU GPL and this license 77 | document. 78 | 79 | 4. Combined Works. 80 | 81 | You may convey a Combined Work under terms of your choice that, 82 | taken together, effectively do not restrict modification of the 83 | portions of the Library contained in the Combined Work and reverse 84 | engineering for debugging such modifications, if you also do each of 85 | the following: 86 | 87 | a) Give prominent notice with each copy of the Combined Work that 88 | the Library is used in it and that the Library and its use are 89 | covered by this License. 90 | 91 | b) Accompany the Combined Work with a copy of the GNU GPL and this license 92 | document. 93 | 94 | c) For a Combined Work that displays copyright notices during 95 | execution, include the copyright notice for the Library among 96 | these notices, as well as a reference directing the user to the 97 | copies of the GNU GPL and this license document. 98 | 99 | d) Do one of the following: 100 | 101 | 0) Convey the Minimal Corresponding Source under the terms of this 102 | License, and the Corresponding Application Code in a form 103 | suitable for, and under terms that permit, the user to 104 | recombine or relink the Application with a modified version of 105 | the Linked Version to produce a modified Combined Work, in the 106 | manner specified by section 6 of the GNU GPL for conveying 107 | Corresponding Source. 108 | 109 | 1) Use a suitable shared library mechanism for linking with the 110 | Library. A suitable mechanism is one that (a) uses at run time 111 | a copy of the Library already present on the user's computer 112 | system, and (b) will operate properly with a modified version 113 | of the Library that is interface-compatible with the Linked 114 | Version. 115 | 116 | e) Provide Installation Information, but only if you would otherwise 117 | be required to provide such information under section 6 of the 118 | GNU GPL, and only to the extent that such information is 119 | necessary to install and execute a modified version of the 120 | Combined Work produced by recombining or relinking the 121 | Application with a modified version of the Linked Version. (If 122 | you use option 4d0, the Installation Information must accompany 123 | the Minimal Corresponding Source and Corresponding Application 124 | Code. If you use option 4d1, you must provide the Installation 125 | Information in the manner specified by section 6 of the GNU GPL 126 | for conveying Corresponding Source.) 127 | 128 | 5. Combined Libraries. 129 | 130 | You may place library facilities that are a work based on the 131 | Library side by side in a single library together with other library 132 | facilities that are not Applications and are not covered by this 133 | License, and convey such a combined library under terms of your 134 | choice, if you do both of the following: 135 | 136 | a) Accompany the combined library with a copy of the same work based 137 | on the Library, uncombined with any other library facilities, 138 | conveyed under the terms of this License. 139 | 140 | b) Give prominent notice with the combined library that part of it 141 | is a work based on the Library, and explaining where to find the 142 | accompanying uncombined form of the same work. 143 | 144 | 6. Revised Versions of the GNU Lesser General Public License. 145 | 146 | The Free Software Foundation may publish revised and/or new versions 147 | of the GNU Lesser General Public License from time to time. Such new 148 | versions will be similar in spirit to the present version, but may 149 | differ in detail to address new problems or concerns. 150 | 151 | Each version is given a distinguishing version number. If the 152 | Library as you received it specifies that a certain numbered version 153 | of the GNU Lesser General Public License "or any later version" 154 | applies to it, you have the option of following the terms and 155 | conditions either of that published version or of any later version 156 | published by the Free Software Foundation. If the Library as you 157 | received it does not specify a version number of the GNU Lesser 158 | General Public License, you may choose any version of the GNU Lesser 159 | General Public License ever published by the Free Software Foundation. 160 | 161 | If the Library as you received it specifies that a proxy can decide 162 | whether future versions of the GNU Lesser General Public License shall 163 | apply, that proxy's public statement of acceptance of any version is 164 | permanent authorization for you to choose that version for the 165 | Library. 166 | -------------------------------------------------------------------------------- /doc/_build/html/faqs.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 7 | 8 | FAQs — PySQLPool v0.3.6 documentation 9 | 10 | 11 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 42 | 43 |
44 |
45 |
46 |
47 | 48 |
49 |

FAQs

50 |

In an attempt to help answer some questions preemptively. A FAQ page has been create along 51 | side the with the docs. Lets hope this helps.

52 |
53 |

How do I enable debugging?

54 |

Currently debugging is very limited, but we do contain a simple debugging capability. You can 55 | enable debugging by assigning PySQLQuery.logging_path to a string value of a file to write the 56 | debugging output to. This will cause every query executed and any errors to be written to the 57 | supplied file.

58 |

Example:

59 |
import PySQLPool
 60 | 
 61 | PySQLPool.PySQLQuery.logging_path = '/path/to/file.txt'
 62 | 
63 |
64 |
65 |
66 |

What type of exception are raised?

67 |

At this time PySQLPool does not wrap the exceptions that come out of MySQLdb. So any and all errors 68 | thrown from any of your queries and/or other actions by MySQLdb will be of its types. Of which the base is 69 | MySQLdb.Error. To find out what error you have caused. MySQLdb.Error contains a two-element tuple called args. 70 | The 1st value will contain the MySQL error number, and the second will contain the error message.

71 |

Example:

72 |
try:
 73 |     connection = PySQLPool.getNewConnection(username='root', password='123456', host='localhost', db='mydb')
 74 |     query = PySQLPool.getNewQuery(connection)
 75 |     query.Query('select * from table')
 76 | except MySQLdb.Error, e:
 77 |     print "Error %d: %s" % (e.args[0], e.args[1])
 78 |     sys.exit (1)
 79 | 
80 |
81 |
82 |
83 | 84 | 85 |
86 |
87 |
88 |
89 |
90 |

Table Of Contents

91 | 98 | 99 |

Previous topic

100 |

PySQLPool Object Reference

102 |

This Page

103 | 107 | 119 | 120 |
121 |
122 |
123 |
124 | 139 | 144 | 145 | -------------------------------------------------------------------------------- /doc/_build/html/_static/basic.css: -------------------------------------------------------------------------------- 1 | /** 2 | * Sphinx stylesheet -- basic theme 3 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 4 | */ 5 | 6 | /* -- main layout ----------------------------------------------------------- */ 7 | 8 | div.clearer { 9 | clear: both; 10 | } 11 | 12 | /* -- relbar ---------------------------------------------------------------- */ 13 | 14 | div.related { 15 | width: 100%; 16 | font-size: 90%; 17 | } 18 | 19 | div.related h3 { 20 | display: none; 21 | } 22 | 23 | div.related ul { 24 | margin: 0; 25 | padding: 0 0 0 10px; 26 | list-style: none; 27 | } 28 | 29 | div.related li { 30 | display: inline; 31 | } 32 | 33 | div.related li.right { 34 | float: right; 35 | margin-right: 5px; 36 | } 37 | 38 | /* -- sidebar --------------------------------------------------------------- */ 39 | 40 | div.sphinxsidebarwrapper { 41 | padding: 10px 5px 0 10px; 42 | } 43 | 44 | div.sphinxsidebar { 45 | float: left; 46 | width: 230px; 47 | margin-left: -100%; 48 | font-size: 90%; 49 | } 50 | 51 | div.sphinxsidebar ul { 52 | list-style: none; 53 | } 54 | 55 | div.sphinxsidebar ul ul, 56 | div.sphinxsidebar ul.want-points { 57 | margin-left: 20px; 58 | list-style: square; 59 | } 60 | 61 | div.sphinxsidebar ul ul { 62 | margin-top: 0; 63 | margin-bottom: 0; 64 | } 65 | 66 | div.sphinxsidebar form { 67 | margin-top: 10px; 68 | } 69 | 70 | div.sphinxsidebar input { 71 | border: 1px solid #98dbcc; 72 | font-family: sans-serif; 73 | font-size: 1em; 74 | } 75 | 76 | img { 77 | border: 0; 78 | } 79 | 80 | /* -- search page ----------------------------------------------------------- */ 81 | 82 | ul.search { 83 | margin: 10px 0 0 20px; 84 | padding: 0; 85 | } 86 | 87 | ul.search li { 88 | padding: 5px 0 5px 20px; 89 | background-image: url(file.png); 90 | background-repeat: no-repeat; 91 | background-position: 0 7px; 92 | } 93 | 94 | ul.search li a { 95 | font-weight: bold; 96 | } 97 | 98 | ul.search li div.context { 99 | color: #888; 100 | margin: 2px 0 0 30px; 101 | text-align: left; 102 | } 103 | 104 | ul.keywordmatches li.goodmatch a { 105 | font-weight: bold; 106 | } 107 | 108 | /* -- index page ------------------------------------------------------------ */ 109 | 110 | table.contentstable { 111 | width: 90%; 112 | } 113 | 114 | table.contentstable p.biglink { 115 | line-height: 150%; 116 | } 117 | 118 | a.biglink { 119 | font-size: 1.3em; 120 | } 121 | 122 | span.linkdescr { 123 | font-style: italic; 124 | padding-top: 5px; 125 | font-size: 90%; 126 | } 127 | 128 | /* -- general index --------------------------------------------------------- */ 129 | 130 | table.indextable td { 131 | text-align: left; 132 | vertical-align: top; 133 | } 134 | 135 | table.indextable dl, table.indextable dd { 136 | margin-top: 0; 137 | margin-bottom: 0; 138 | } 139 | 140 | table.indextable tr.pcap { 141 | height: 10px; 142 | } 143 | 144 | table.indextable tr.cap { 145 | margin-top: 10px; 146 | background-color: #f2f2f2; 147 | } 148 | 149 | img.toggler { 150 | margin-right: 3px; 151 | margin-top: 3px; 152 | cursor: pointer; 153 | } 154 | 155 | /* -- general body styles --------------------------------------------------- */ 156 | 157 | a.headerlink { 158 | visibility: hidden; 159 | } 160 | 161 | h1:hover > a.headerlink, 162 | h2:hover > a.headerlink, 163 | h3:hover > a.headerlink, 164 | h4:hover > a.headerlink, 165 | h5:hover > a.headerlink, 166 | h6:hover > a.headerlink, 167 | dt:hover > a.headerlink { 168 | visibility: visible; 169 | } 170 | 171 | div.body p.caption { 172 | text-align: inherit; 173 | } 174 | 175 | div.body td { 176 | text-align: left; 177 | } 178 | 179 | .field-list ul { 180 | padding-left: 1em; 181 | } 182 | 183 | .first { 184 | margin-top: 0 !important; 185 | } 186 | 187 | p.rubric { 188 | margin-top: 30px; 189 | font-weight: bold; 190 | } 191 | 192 | /* -- sidebars -------------------------------------------------------------- */ 193 | 194 | div.sidebar { 195 | margin: 0 0 0.5em 1em; 196 | border: 1px solid #ddb; 197 | padding: 7px 7px 0 7px; 198 | background-color: #ffe; 199 | width: 40%; 200 | float: right; 201 | } 202 | 203 | p.sidebar-title { 204 | font-weight: bold; 205 | } 206 | 207 | /* -- topics ---------------------------------------------------------------- */ 208 | 209 | div.topic { 210 | border: 1px solid #ccc; 211 | padding: 7px 7px 0 7px; 212 | margin: 10px 0 10px 0; 213 | } 214 | 215 | p.topic-title { 216 | font-size: 1.1em; 217 | font-weight: bold; 218 | margin-top: 10px; 219 | } 220 | 221 | /* -- admonitions ----------------------------------------------------------- */ 222 | 223 | div.admonition { 224 | margin-top: 10px; 225 | margin-bottom: 10px; 226 | padding: 7px; 227 | } 228 | 229 | div.admonition dt { 230 | font-weight: bold; 231 | } 232 | 233 | div.admonition dl { 234 | margin-bottom: 0; 235 | } 236 | 237 | p.admonition-title { 238 | margin: 0px 10px 5px 0px; 239 | font-weight: bold; 240 | } 241 | 242 | div.body p.centered { 243 | text-align: center; 244 | margin-top: 25px; 245 | } 246 | 247 | /* -- tables ---------------------------------------------------------------- */ 248 | 249 | table.docutils { 250 | border: 0; 251 | border-collapse: collapse; 252 | } 253 | 254 | table.docutils td, table.docutils th { 255 | padding: 1px 8px 1px 0; 256 | border-top: 0; 257 | border-left: 0; 258 | border-right: 0; 259 | border-bottom: 1px solid #aaa; 260 | } 261 | 262 | table.field-list td, table.field-list th { 263 | border: 0 !important; 264 | } 265 | 266 | table.footnote td, table.footnote th { 267 | border: 0 !important; 268 | } 269 | 270 | th { 271 | text-align: left; 272 | padding-right: 5px; 273 | } 274 | 275 | /* -- other body styles ----------------------------------------------------- */ 276 | 277 | dl { 278 | margin-bottom: 15px; 279 | } 280 | 281 | dd p { 282 | margin-top: 0px; 283 | } 284 | 285 | dd ul, dd table { 286 | margin-bottom: 10px; 287 | } 288 | 289 | dd { 290 | margin-top: 3px; 291 | margin-bottom: 10px; 292 | margin-left: 30px; 293 | } 294 | 295 | dt:target, .highlight { 296 | background-color: #fbe54e; 297 | } 298 | 299 | dl.glossary dt { 300 | font-weight: bold; 301 | font-size: 1.1em; 302 | } 303 | 304 | .field-list ul { 305 | margin: 0; 306 | padding-left: 1em; 307 | } 308 | 309 | .field-list p { 310 | margin: 0; 311 | } 312 | 313 | .refcount { 314 | color: #060; 315 | } 316 | 317 | .optional { 318 | font-size: 1.3em; 319 | } 320 | 321 | .versionmodified { 322 | font-style: italic; 323 | } 324 | 325 | .system-message { 326 | background-color: #fda; 327 | padding: 5px; 328 | border: 3px solid red; 329 | } 330 | 331 | .footnote:target { 332 | background-color: #ffa 333 | } 334 | 335 | .line-block { 336 | display: block; 337 | margin-top: 1em; 338 | margin-bottom: 1em; 339 | } 340 | 341 | .line-block .line-block { 342 | margin-top: 0; 343 | margin-bottom: 0; 344 | margin-left: 1.5em; 345 | } 346 | 347 | /* -- code displays --------------------------------------------------------- */ 348 | 349 | pre { 350 | overflow: auto; 351 | } 352 | 353 | td.linenos pre { 354 | padding: 5px 0px; 355 | border: 0; 356 | background-color: transparent; 357 | color: #aaa; 358 | } 359 | 360 | table.highlighttable { 361 | margin-left: 0.5em; 362 | } 363 | 364 | table.highlighttable td { 365 | padding: 0 0.5em 0 0.5em; 366 | } 367 | 368 | tt.descname { 369 | background-color: transparent; 370 | font-weight: bold; 371 | font-size: 1.2em; 372 | } 373 | 374 | tt.descclassname { 375 | background-color: transparent; 376 | } 377 | 378 | tt.xref, a tt { 379 | background-color: transparent; 380 | font-weight: bold; 381 | } 382 | 383 | h1 tt, h2 tt, h3 tt, h4 tt, h5 tt, h6 tt { 384 | background-color: transparent; 385 | } 386 | 387 | /* -- math display ---------------------------------------------------------- */ 388 | 389 | img.math { 390 | vertical-align: middle; 391 | } 392 | 393 | div.body div.math p { 394 | text-align: center; 395 | } 396 | 397 | span.eqno { 398 | float: right; 399 | } 400 | 401 | /* -- printout stylesheet --------------------------------------------------- */ 402 | 403 | @media print { 404 | div.document, 405 | div.documentwrapper, 406 | div.bodywrapper { 407 | margin: 0 !important; 408 | width: 100%; 409 | } 410 | 411 | div.sphinxsidebar, 412 | div.related, 413 | div.footer, 414 | #top-link { 415 | display: none; 416 | } 417 | } 418 | -------------------------------------------------------------------------------- /src/PySQLPool/query.py: -------------------------------------------------------------------------------- 1 | """ 2 | @author: Nick Verbeck 3 | @since: date 5/12/2008 4 | """ 5 | 6 | import time 7 | import MySQLdb 8 | from pool import Pool 9 | import log 10 | 11 | class PySQLQuery(object): 12 | """ 13 | Front-End class used for interaction with the PySQLPool core 14 | 15 | This class is used to execute queries and to request a currently open connection from the pool. 16 | If no open connections exist a new one is created by the pool. 17 | 18 | @author: Nick Verbeck 19 | @since: 5/12/2008 20 | @version: 0.1 21 | """ 22 | 23 | def __init__(self, PySQLConnectionObj, commitOnEnd = False): 24 | """ 25 | Constructor for PySQLQuery Class 26 | 27 | @param PySQLConnectionObj: PySQLConnection Object representing your connection string 28 | @param commitOnEnd: Default False, When query is complete do you wish to auto commit. This is a one time auto commit 29 | @author: Nick Verbeck 30 | @since: 5/12/2008 31 | """ 32 | self.connInfo = PySQLConnectionObj 33 | self.record = {} 34 | self.rowcount = 0 35 | self.affectedRows = None 36 | #The Real Connection to the DB 37 | self.conn = None 38 | self.lastError = None 39 | self.lastInsertID = None 40 | 41 | def __del__(self): 42 | """ 43 | On destruct make sure the current connection is returned back to the pool for use later 44 | 45 | @author: Nick Verbeck 46 | @since: 5/12/2008 47 | """ 48 | if self.conn is not None: 49 | self._ReturnConnection() 50 | 51 | def __enter__(self): 52 | """ 53 | Starts transaction, used with the 'with' statement. 54 | @author: Denis Malinovsky 55 | @since: 5/21/2010 56 | """ 57 | self.Query('START TRANSACTION') 58 | log.logger.info('Starting Transaction') 59 | 60 | def __exit__(self, exc_type, exc_value, traceback): 61 | """ 62 | Commits transaction, if no exception was raised. 63 | @author: Denis Malinovsky 64 | @since: 5/21/2010 65 | """ 66 | if exc_type is None: 67 | self.Query('COMMIT') 68 | log.logger.info('Commiting Transaction') 69 | else: 70 | self.Query('ROLLBACK') 71 | log.logger.info('Rolling Back Transaction') 72 | 73 | #TODO: In the future lets decorate all our query calls with a connection fetching and releasing handler. Help to centralize all this logic for use in transactions in the future. 74 | def query(self, query, args=None): 75 | """ 76 | Execute the passed in query against the database 77 | 78 | @param query: MySQL Query to execute. %s or %(key)s will be replaced by parameter args sequence 79 | @param args: Sequence of value to replace in your query. A mapping may also be used but your query must use %(key)s 80 | @author: Nick Verbeck 81 | @since: 5/12/2008 82 | """ 83 | self.affectedRows = None 84 | self.lastError = None 85 | cursor = None 86 | 87 | try: 88 | try: 89 | self._GetConnection() 90 | 91 | log.logger.debug('Running query "%s" with args "%s"', query, args) 92 | self.conn.query = query 93 | 94 | #Execute query and store results 95 | cursor = self.conn.getCursor() 96 | self.affectedRows = cursor.execute(query, args) 97 | self.lastInsertID = self.conn.connection.insert_id() 98 | self.rowcount = cursor.rowcount 99 | 100 | log.logger.debug('Query Resulted in %s affected rows, %s rows returned, %s last insert id', self.affectedRows, self.lastInsertID, self.rowcount) 101 | 102 | self.record = cursor.fetchall() 103 | self.conn.updateCheckTime() 104 | except Exception, e: 105 | self.lastError = e 106 | self.affectedRows = None 107 | finally: 108 | if cursor is not None: 109 | cursor.close() 110 | self._ReturnConnection() 111 | if self.lastError is not None: 112 | raise self.lastError 113 | else: 114 | return self.affectedRows 115 | execute = Query = query 116 | 117 | def queryOne(self, query, args=None): 118 | """ 119 | Execute the passed in query against the database. 120 | Uses a Generator & fetchone to reduce your process memory size. 121 | 122 | @param query: MySQL Query to execute. %s or %(key)s will be replaced by parameter args sequence 123 | @param args: Sequence of value to replace in your query. A mapping may also be used but your query must use %(key)s 124 | @author: Nick Verbeck 125 | @since: 5/12/2008 126 | """ 127 | 128 | self.affectedRows = None 129 | self.lastError = None 130 | cursor = None 131 | try: 132 | try: 133 | self._GetConnection() 134 | self.conn.query = query 135 | #Execute query 136 | cursor = self.conn.getCursor() 137 | self.affectedRows = cursor.execute(query, args) 138 | self.conn.updateCheckTime() 139 | while 1: 140 | row = cursor.fetchone() 141 | if row is None: 142 | break 143 | else: 144 | self.record = row 145 | yield row 146 | 147 | self.rowcount = cursor.rowcount 148 | except Exception, e: 149 | self.lastError = e 150 | self.affectedRows = None 151 | finally: 152 | if cursor is not None: 153 | cursor.close() 154 | self._ReturnConnection() 155 | if self.lastError is not None: 156 | raise self.lastError 157 | else: 158 | raise StopIteration 159 | executeOne = QueryOne = queryOne 160 | 161 | def queryMany(self, query, args): 162 | """ 163 | Executes a series of the same Insert Statments 164 | 165 | Each tuple in the args list will be applied to the query and executed. 166 | This is the equivilant of MySQLDB.cursor.executemany() 167 | 168 | @author: Nick Verbeck 169 | @since: 9/7/2008 170 | """ 171 | self.lastError = None 172 | self.affectedRows = None 173 | self.rowcount = None 174 | self.record = None 175 | cursor = None 176 | 177 | try: 178 | try: 179 | self._GetConnection() 180 | self.conn.query = query 181 | #Execute query and store results 182 | cursor = self.conn.getCursor() 183 | self.affectedRows = cursor.executemany(query, args) 184 | self.conn.updateCheckTime() 185 | except Exception, e: 186 | self.lastError = e 187 | finally: 188 | if cursor is not None: 189 | cursor.close() 190 | self._ReturnConnection() 191 | if self.lastError is not None: 192 | raise self.lastError 193 | else: 194 | return self.affectedRows 195 | executeMany = queryMany 196 | 197 | def queryMulti(self, queries): 198 | """ 199 | Execute a series of Deletes,Inserts, & Updates in the Queires List 200 | 201 | @author: Nick Verbeck 202 | @since: 9/7/2008 203 | """ 204 | self.lastError = None 205 | self.affectedRows = 0 206 | self.rowcount = None 207 | self.record = None 208 | cursor = None 209 | 210 | try: 211 | try: 212 | self._GetConnection() 213 | #Execute query and store results 214 | cursor = self.conn.getCursor() 215 | for query in queries: 216 | self.conn.query = query 217 | if query.__class__ == [].__class__: 218 | self.affectedRows += cursor.execute(query[0], query[1]) 219 | else: 220 | self.affectedRows += cursor.execute(query) 221 | self.conn.updateCheckTime() 222 | except Exception, e: 223 | self.lastError = e 224 | finally: 225 | if cursor is not None: 226 | cursor.close() 227 | self._ReturnConnection() 228 | if self.lastError is not None: 229 | raise self.lastError 230 | else: 231 | return self.affectedRows 232 | executeMulti = queryMulti 233 | 234 | def _GetConnection(self): 235 | """ 236 | Retieves a prelocked connection from the Pool 237 | 238 | @author: Nick Verbeck 239 | @since: 9/7/2008 240 | """ 241 | #Attempt to get a connection. If all connections are in use and we have reached the max number of connections, 242 | #we wait 1 second and try again. 243 | #The Connection is returned locked to be thread safe 244 | while self.conn is None: 245 | self.conn = Pool().GetConnection(self.connInfo) 246 | if self.conn is not None: 247 | break 248 | else: 249 | time.sleep(1) 250 | 251 | def _ReturnConnection(self): 252 | """ 253 | Returns a connection back to the pool 254 | 255 | @author: Nick Verbeck 256 | @since: 9/7/2008 257 | """ 258 | if self.conn is not None: 259 | if self.connInfo.commitOnEnd is True or self.commitOnEnd is True: 260 | self.conn.Commit() 261 | 262 | Pool().returnConnection(self.conn) 263 | self.conn = None 264 | 265 | def escape_string(self, string): 266 | """ 267 | This is just an adapter function to allow previus users of MySQLdb. 268 | To be familier with there names of functions. 269 | 270 | @see: escapeString 271 | """ 272 | return MySQLdb.escape_string(string) 273 | 274 | def escapeString(self, string): 275 | """ 276 | Escapes a string for use in a query 277 | 278 | This is the equivilate and MySQLdb.escape_string() 279 | 280 | @author: Nick Verbeck 281 | @since: 9/7/2008 282 | """ 283 | return MySQLdb.escapeString(string) 284 | 285 | def escape(self, string): 286 | """ 287 | Escapes a string for use in a query 288 | 289 | This is the equivilate and MySQLdb.escape() 290 | 291 | @author: Nick Verbeck 292 | @since: 9/7/2008 293 | """ 294 | return MySQLdb.escape(string) 295 | -------------------------------------------------------------------------------- /doc/reference.rst: -------------------------------------------------------------------------------- 1 | .. "reference.rst" file 2 | .. moduleauthor:: NerdyNick 3 | .. sectionauthor:: NerdyNick 4 | .. sectionauthor:: NerdyNick 5 | .. module:: PySQLPool 6 | :synopsis: MySQL Connection Pooling 7 | 8 | =========================== 9 | PySQLPool Object Reference 10 | =========================== 11 | 12 | This is a standard object reference for PySQLPool. Being that PySQLPool is a connection pooling wrapper 13 | around MySQLdb many of the same methods and parameters are support. You can kind hints or further docs 14 | by reading the MySQLdb Documentation at http://mysql-python.sourceforge.net/MySQLdb-1.2.2/ 15 | 16 | :mod:`PySQLPool` 17 | ================== 18 | 19 | .. attribute:: __version__ 20 | 21 | PySQLPool Version Number 22 | 23 | .. attribute:: __author__ 24 | 25 | PySQLPool Author String 26 | 27 | .. function:: getNewConnection(*args, **kargs) 28 | 29 | Fast function to generate a new PySQLConnection instance. Arguments are those of :class:`PySQLConnection` 30 | 31 | .. function:: getNewQuery([connection[, commitOnEnd[, **kargs]]]) 32 | 33 | Fast method to generate a new PySQLQuery instance. 34 | 35 | If an instance of a PySQLConnection object is passes for the connection parameter. It will be used for the 36 | connection. Otherwise \**kargs will be used to generate a PySQLConnection instance via the :meth:`getNewConnection` method. 37 | 38 | .. function:: getNewPool() 39 | 40 | Returns a reference to the current PySQLPool object 41 | 42 | .. function:: terminatePool() 43 | 44 | Causes PySQLPool to commit and terminate all your current MySQL connections 45 | 46 | .. function:: commitPool() 47 | 48 | Causes PySQLPool to commit all your current MySQL connections 49 | 50 | .. function:: cleanupPool() 51 | 52 | Causes PySQLPool to analyse all current MySQL connections, and clean up an dead connections. 53 | 54 | 55 | 56 | :mod:`PySQLPool.PySQLQuery` 57 | ============================= 58 | 59 | The PySQLQuery class is by far one of the biggest work horses in the whole PySQLPool library, next to the PySQLPool class. 60 | It is responsable for handaling the execution of your query(s). Which in itself is a lot of work. PySQLQuery handles talking 61 | to the heart of PySQLPool, The PySQLPool class. To fetch a new connection or one that has been estabished. It then creates a 62 | MySQL cursor object to handle the execution of your sql statement against your MySQL database. 63 | 64 | .. class:: PySQLQuery(PySQLConnectionObj[, commitOnEnd]) 65 | 66 | .. attribute:: Pool 67 | 68 | Used to store a reference to the PySQLPool object 69 | 70 | .. attribute:: connInfo 71 | 72 | Used to store the connection information to be used for talking to the db. This is a PySQLConnection instance. 73 | 74 | .. attribute:: commitOnEnd 75 | 76 | A boolean flag used to tell the connection that it should auto commit your statement at the end of its execution. 77 | 78 | .. attribute:: record 79 | 80 | A storage reference to your results that where returned from your last select statement. 81 | 82 | .. attribute:: rowcount 83 | 84 | The number of rows returned by your last select statement. 85 | 86 | .. attribute:: affectedRows 87 | 88 | The number of affected rows that your last delete/insert/update statement affected. 89 | 90 | .. attribute:: conn 91 | 92 | An internaly used reference to the current locked connection as returned by the PySQLPool class. This is an 93 | instance of a PySQLConnectionManager object. 94 | 95 | .. attribute:: lastError 96 | 97 | A reference to the last MySQL error as returned by the under lying MySQLdb library. You can reference this if you need. 98 | But PySQLQuery will raise this error forward for you to catch yourself. 99 | 100 | .. attribute:: lastInsertID 101 | 102 | The last auto incrament ID that an insert statement create. 103 | 104 | .. method:: __del__() 105 | 106 | The destructor method used for freeing up any locked connections that may not have be release do to some reason. 107 | 108 | .. method:: Query(query[, args]) 109 | 110 | Depricated alias for :meth:`query` 111 | 112 | .. method:: query(query[, args]) 113 | 114 | Executes the given query. 115 | 116 | query - string, query to execute on server 117 | args - optional sequence or mapping, parameters to use with query 118 | 119 | Note: If args is a sequence, then %s must be used as the parameter placeholder in the query. 120 | If a mapping is used, %(key)s must be used as the placeholder. 121 | 122 | Returns the number of affected rows. 123 | 124 | .. method:: QueryOne(query[, args]) 125 | 126 | Depricated alias for :meth:`queryOne` 127 | 128 | .. method:: queryOne(query[, args]) 129 | 130 | A generator style version of :meth:`query`. 131 | 132 | Parameters are the same as :meth:`query`, but instead of fetching all the data from the server at once. 133 | It is returned one row at a time for every iteration. Each row will be returned as well as record can 134 | still be used to access the current row. 135 | 136 | .. method:: queryMany(query, args) 137 | .. method:: executeMany(query, args) 138 | 139 | Execute a multi-row query. 140 | 141 | query - string, query to execute on server 142 | args - sequence of sequences or mappings, parameters to use with query. 143 | 144 | Returns the number of affected rows 145 | 146 | .. method:: queryMulti(queries) 147 | .. method:: executeMulti(queries) 148 | 149 | Executes a sequence of query strings 150 | 151 | Each sequence item and be a sequence or a string. If item is a sequence the 1st item but be the query. 152 | The 2nd must be the replacement sequence or mapping to use with the query. 153 | 154 | Returns the total number of affected rows 155 | 156 | .. method:: _GetConnection() 157 | 158 | Private method used to fetch a connection from the central pool of connections 159 | 160 | .. method:: _ReturnConnection() 161 | 162 | Private method used to return a connection to the central pool of connections 163 | 164 | .. method:: escape() 165 | 166 | Varius string escape methods as provided by MySQLdb. Each matchs a function of the same name in MySQLdb 167 | 168 | .. method:: escapeString() 169 | 170 | See :meth:`escape` 171 | 172 | .. method:: escape_string() 173 | 174 | See :meth:`escape` 175 | 176 | 177 | 178 | :mod:`PySQLPool.PySQLPool` 179 | =========================== 180 | 181 | .. class:: PySQLPool() 182 | 183 | .. attribute:: __pool 184 | 185 | .. attribute:: maxActiveConnections 186 | 187 | .. attribute:: maxActivePerConnection 188 | 189 | .. method:: Terminate() 190 | 191 | .. method:: Cleanup() 192 | 193 | .. method:: Commit() 194 | 195 | .. method:: GetConnection(PySQLConnectionObj) 196 | 197 | .. method:: returnConnection(connObj) 198 | 199 | 200 | 201 | :mod:`PySQLPool.PySQLConnection` 202 | ================================= 203 | 204 | .. attribute:: connection_timeout 205 | 206 | A `datetime.timedelta` representing your default MySQL connection_timeout. This is used 207 | to improve performance with checking to see if connections are valid and reconnecting if needed. Each 208 | connection instance maintains a timestamp of its last activity. That is updated for every query or test. 209 | The connection is auto tested for every new instance of a PySQLQuery created on its initial fetching 210 | of a connection. 211 | 212 | .. class:: PySQLConnection([host, [user, [passwd, [db, [port]]]]], **kargs) 213 | 214 | Command Pattern Object to store connection information for use in PySQLPool 215 | 216 | Supported kargs are: 217 | * **host** - string, host to connect 218 | * **user,username** - string, user to connect as 219 | * **passwd,password** - string, password to use 220 | * **db,schema** - string, database to use 221 | * **port** - integer, TCP/IP port to connect to 222 | * **unix_socket** - string, location of unix_socket to use 223 | * **conv** - conversion dictionary, see MySQLdb.converters 224 | * **connect_timeout** - number of seconds to wait before the connection attempt fails. 225 | * **compress** - if set, compression is enabled 226 | * **named_pipe** - if set, a named pipe is used to connect (Windows only) 227 | * **init_command** - command which is run once the connection is created 228 | * **read_default_file** - file from which default client values are read 229 | * **read_default_group** - configuration group to use from the default file 230 | * **cursorclass** - class object, used to create cursors (keyword only) 231 | * **use_unicode** - If True, text-like columns are returned as unicode objects using the 232 | connection's character set. Otherwise, text-like columns are returned as strings. 233 | columns are returned as normal strings. Unicode objects will always be encoded to 234 | the connection's character set regardless of this setting. 235 | * **charset** - If supplied, the connection character set will be changed to this character set (MySQL-4.1 and newer). 236 | This implies use_unicode=True 237 | * **sql_mode** - If supplied, the session SQL mode will be changed to this setting (MySQL-4.1 and newer). 238 | For more details and legal values, see the MySQL documentation. 239 | * **client_flag** - integer, flags to use or 0 (see MySQL docs or constants/CLIENTS.py) 240 | * **ssl** - dictionary or mapping, contains SSL connection parameters; see the MySQL documentation for more details (mysql_ssl_set()). 241 | If this is set, and the client does not support SSL, NotSupportedError will be raised. 242 | * **local_inifile** - integer, non-zero enables LOAD LOCAL INFILE; zero disables 243 | 244 | Note: There are a number of undocumented, non-standard methods. 245 | See the documentation for the MySQL C API for some hints on what they do. 246 | 247 | .. attribute:: info 248 | 249 | Dictionary containing the connection info to be passed off to the MySQLdb layer 250 | 251 | .. attribute:: key 252 | 253 | An auto generated md5 checksum to represent your connection in the pool. This is generated off of the 254 | username, password, host, and db/schema. 255 | 256 | .. method:: __getattr__(name) 257 | 258 | Accessor to :attr:`info` 259 | 260 | 261 | .. class:: PySQLConnectionManager 262 | 263 | .. method:: __init__(PySQLConnectionObj) 264 | 265 | .. method:: updateCheckTime() 266 | 267 | .. method:: Connect() 268 | 269 | .. method:: ReConnect() 270 | 271 | .. method:: TestConnection(forceCheck = False) 272 | 273 | .. method:: Commit() 274 | 275 | .. method:: Close() -------------------------------------------------------------------------------- /doc/_build/html/_sources/reference.txt: -------------------------------------------------------------------------------- 1 | .. "reference.rst" file 2 | .. moduleauthor:: NerdyNick 3 | .. sectionauthor:: NerdyNick 4 | .. sectionauthor:: NerdyNick 5 | .. module:: PySQLPool 6 | :synopsis: MySQL Connection Pooling 7 | 8 | =========================== 9 | PySQLPool Object Reference 10 | =========================== 11 | 12 | This is a standard object reference for PySQLPool. Being that PySQLPool is a connection pooling wrapper 13 | around MySQLdb many of the same methods and parameters are support. You can kind hints or further docs 14 | by reading the MySQLdb Documentation at http://mysql-python.sourceforge.net/MySQLdb-1.2.2/ 15 | 16 | :mod:`PySQLPool` 17 | ================== 18 | 19 | .. attribute:: __version__ 20 | 21 | PySQLPool Version Number 22 | 23 | .. attribute:: __author__ 24 | 25 | PySQLPool Author String 26 | 27 | .. function:: getNewConnection(*args, **kargs) 28 | 29 | Fast function to generate a new PySQLConnection instance. Arguments are those of :class:`PySQLConnection` 30 | 31 | .. function:: getNewQuery([connection[, commitOnEnd[, **kargs]]]) 32 | 33 | Fast method to generate a new PySQLQuery instance. 34 | 35 | If an instance of a PySQLConnection object is passes for the connection parameter. It will be used for the 36 | connection. Otherwise \**kargs will be used to generate a PySQLConnection instance via the :meth:`getNewConnection` method. 37 | 38 | .. function:: getNewPool() 39 | 40 | Returns a reference to the current PySQLPool object 41 | 42 | .. function:: terminatePool() 43 | 44 | Causes PySQLPool to commit and terminate all your current MySQL connections 45 | 46 | .. function:: commitPool() 47 | 48 | Causes PySQLPool to commit all your current MySQL connections 49 | 50 | .. function:: cleanupPool() 51 | 52 | Causes PySQLPool to analyse all current MySQL connections, and clean up an dead connections. 53 | 54 | 55 | 56 | :mod:`PySQLPool.PySQLQuery` 57 | ============================= 58 | 59 | The PySQLQuery class is by far one of the biggest work horses in the whole PySQLPool library, next to the PySQLPool class. 60 | It is responsable for handaling the execution of your query(s). Which in itself is a lot of work. PySQLQuery handles talking 61 | to the heart of PySQLPool, The PySQLPool class. To fetch a new connection or one that has been estabished. It then creates a 62 | MySQL cursor object to handle the execution of your sql statement against your MySQL database. 63 | 64 | .. class:: PySQLQuery(PySQLConnectionObj[, commitOnEnd]) 65 | 66 | .. attribute:: Pool 67 | 68 | Used to store a reference to the PySQLPool object 69 | 70 | .. attribute:: connInfo 71 | 72 | Used to store the connection information to be used for talking to the db. This is a PySQLConnection instance. 73 | 74 | .. attribute:: commitOnEnd 75 | 76 | A boolean flag used to tell the connection that it should auto commit your statement at the end of its execution. 77 | 78 | .. attribute:: record 79 | 80 | A storage reference to your results that where returned from your last select statement. 81 | 82 | .. attribute:: rowcount 83 | 84 | The number of rows returned by your last select statement. 85 | 86 | .. attribute:: affectedRows 87 | 88 | The number of affected rows that your last delete/insert/update statement affected. 89 | 90 | .. attribute:: conn 91 | 92 | An internaly used reference to the current locked connection as returned by the PySQLPool class. This is an 93 | instance of a PySQLConnectionManager object. 94 | 95 | .. attribute:: lastError 96 | 97 | A reference to the last MySQL error as returned by the under lying MySQLdb library. You can reference this if you need. 98 | But PySQLQuery will raise this error forward for you to catch yourself. 99 | 100 | .. attribute:: lastInsertID 101 | 102 | The last auto incrament ID that an insert statement create. 103 | 104 | .. method:: __del__() 105 | 106 | The destructor method used for freeing up any locked connections that may not have be release do to some reason. 107 | 108 | .. method:: Query(query[, args]) 109 | 110 | Depricated alias for :meth:`query` 111 | 112 | .. method:: query(query[, args]) 113 | 114 | Executes the given query. 115 | 116 | query - string, query to execute on server 117 | args - optional sequence or mapping, parameters to use with query 118 | 119 | Note: If args is a sequence, then %s must be used as the parameter placeholder in the query. 120 | If a mapping is used, %(key)s must be used as the placeholder. 121 | 122 | Returns the number of affected rows. 123 | 124 | .. method:: QueryOne(query[, args]) 125 | 126 | Depricated alias for :meth:`queryOne` 127 | 128 | .. method:: queryOne(query[, args]) 129 | 130 | A generator style version of :meth:`query`. 131 | 132 | Parameters are the same as :meth:`query`, but instead of fetching all the data from the server at once. 133 | It is returned one row at a time for every iteration. Each row will be returned as well as record can 134 | still be used to access the current row. 135 | 136 | .. method:: queryMany(query, args) 137 | .. method:: executeMany(query, args) 138 | 139 | Execute a multi-row query. 140 | 141 | query - string, query to execute on server 142 | args - sequence of sequences or mappings, parameters to use with query. 143 | 144 | Returns the number of affected rows 145 | 146 | .. method:: queryMulti(queries) 147 | .. method:: executeMulti(queries) 148 | 149 | Executes a sequence of query strings 150 | 151 | Each sequence item and be a sequence or a string. If item is a sequence the 1st item but be the query. 152 | The 2nd must be the replacement sequence or mapping to use with the query. 153 | 154 | Returns the total number of affected rows 155 | 156 | .. method:: _GetConnection() 157 | 158 | Private method used to fetch a connection from the central pool of connections 159 | 160 | .. method:: _ReturnConnection() 161 | 162 | Private method used to return a connection to the central pool of connections 163 | 164 | .. method:: escape() 165 | 166 | Varius string escape methods as provided by MySQLdb. Each matchs a function of the same name in MySQLdb 167 | 168 | .. method:: escapeString() 169 | 170 | See :meth:`escape` 171 | 172 | .. method:: escape_string() 173 | 174 | See :meth:`escape` 175 | 176 | 177 | 178 | :mod:`PySQLPool.PySQLPool` 179 | =========================== 180 | 181 | .. class:: PySQLPool() 182 | 183 | .. attribute:: __pool 184 | 185 | .. attribute:: maxActiveConnections 186 | 187 | .. attribute:: maxActivePerConnection 188 | 189 | .. method:: Terminate() 190 | 191 | .. method:: Cleanup() 192 | 193 | .. method:: Commit() 194 | 195 | .. method:: GetConnection(PySQLConnectionObj) 196 | 197 | .. method:: returnConnection(connObj) 198 | 199 | 200 | 201 | :mod:`PySQLPool.PySQLConnection` 202 | ================================= 203 | 204 | .. attribute:: connection_timeout 205 | 206 | A `datetime.timedelta` representing your default MySQL connection_timeout. This is used 207 | to improve performance with checking to see if connections are valid and reconnecting if needed. Each 208 | connection instance maintains a timestamp of its last activity. That is updated for every query or test. 209 | The connection is auto tested for every new instance of a PySQLQuery created on its initial fetching 210 | of a connection. 211 | 212 | .. class:: PySQLConnection([host, [user, [passwd, [db, [port]]]]], **kargs) 213 | 214 | Command Pattern Object to store connection information for use in PySQLPool 215 | 216 | Supported kargs are: 217 | * **host** - string, host to connect 218 | * **user,username** - string, user to connect as 219 | * **passwd,password** - string, password to use 220 | * **db,schema** - string, database to use 221 | * **port** - integer, TCP/IP port to connect to 222 | * **unix_socket** - string, location of unix_socket to use 223 | * **conv** - conversion dictionary, see MySQLdb.converters 224 | * **connect_timeout** - number of seconds to wait before the connection attempt fails. 225 | * **compress** - if set, compression is enabled 226 | * **named_pipe** - if set, a named pipe is used to connect (Windows only) 227 | * **init_command** - command which is run once the connection is created 228 | * **read_default_file** - file from which default client values are read 229 | * **read_default_group** - configuration group to use from the default file 230 | * **cursorclass** - class object, used to create cursors (keyword only) 231 | * **use_unicode** - If True, text-like columns are returned as unicode objects using the 232 | connection's character set. Otherwise, text-like columns are returned as strings. 233 | columns are returned as normal strings. Unicode objects will always be encoded to 234 | the connection's character set regardless of this setting. 235 | * **charset** - If supplied, the connection character set will be changed to this character set (MySQL-4.1 and newer). 236 | This implies use_unicode=True 237 | * **sql_mode** - If supplied, the session SQL mode will be changed to this setting (MySQL-4.1 and newer). 238 | For more details and legal values, see the MySQL documentation. 239 | * **client_flag** - integer, flags to use or 0 (see MySQL docs or constants/CLIENTS.py) 240 | * **ssl** - dictionary or mapping, contains SSL connection parameters; see the MySQL documentation for more details (mysql_ssl_set()). 241 | If this is set, and the client does not support SSL, NotSupportedError will be raised. 242 | * **local_inifile** - integer, non-zero enables LOAD LOCAL INFILE; zero disables 243 | 244 | Note: There are a number of undocumented, non-standard methods. 245 | See the documentation for the MySQL C API for some hints on what they do. 246 | 247 | .. attribute:: info 248 | 249 | Dictionary containing the connection info to be passed off to the MySQLdb layer 250 | 251 | .. attribute:: key 252 | 253 | An auto generated md5 checksum to represent your connection in the pool. This is generated off of the 254 | username, password, host, and db/schema. 255 | 256 | .. method:: __getattr__(name) 257 | 258 | Accessor to :attr:`info` 259 | 260 | 261 | .. class:: PySQLConnectionManager 262 | 263 | .. method:: __init__(PySQLConnectionObj) 264 | 265 | .. method:: updateCheckTime() 266 | 267 | .. method:: Connect() 268 | 269 | .. method:: ReConnect() 270 | 271 | .. method:: TestConnection(forceCheck = False) 272 | 273 | .. method:: Commit() 274 | 275 | .. method:: Close() -------------------------------------------------------------------------------- /doc/_build/html/genindex.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 7 | 8 | Index — PySQLPool v0.3.6 documentation 9 | 10 | 11 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 38 | 39 |
40 |
41 |
42 |
43 | 44 | 45 |

Index

46 | 47 | _ | A | C | E | G | I | K | L | M | P | Q | R | T | U 48 | 49 |
50 | 51 | 52 |

_

53 |
54 |
55 | 56 |
__author__ (in module PySQLPool)
57 |
__del__() (PySQLPool.PySQLQuery method)
58 |
__getattr__() (PySQLPool.PySQLConnection method)
59 |
__init__() (PySQLPool.PySQLConnectionManager method)
60 |
__pool (PySQLPool.PySQLPool attribute)
61 |
__version__ (in module PySQLPool)
62 |
_GetConnection() (PySQLPool.PySQLQuery method)
63 |
_ReturnConnection() (PySQLPool.PySQLQuery method)
64 |
65 | 66 |

A

67 |
68 |
69 | 70 |
affectedRows (PySQLPool.PySQLQuery attribute)
71 |
72 | 73 |

C

74 |
75 |
76 | 77 |
Cleanup() (PySQLPool.PySQLPool method)
78 |
cleanupPool() (in module PySQLPool)
79 |
Close() (PySQLPool.PySQLConnectionManager method)
80 |
Commit() (PySQLPool.PySQLConnectionManager method)
81 |
82 |
(PySQLPool.PySQLPool method)
83 |
84 |
commitOnEnd (PySQLPool.PySQLQuery attribute)
85 |
commitPool() (in module PySQLPool)
86 |
conn (PySQLPool.PySQLQuery attribute)
87 |
Connect() (PySQLPool.PySQLConnectionManager method)
88 |
connection_timeout (in module PySQLPool)
89 |
connInfo (PySQLPool.PySQLQuery attribute)
90 |
91 | 92 |

E

93 |
94 |
95 | 96 |
escape() (PySQLPool.PySQLQuery method)
97 |
escape_string() (PySQLPool.PySQLQuery method)
98 |
escapeString() (PySQLPool.PySQLQuery method)
99 |
executeMany() (PySQLPool.PySQLQuery method)
100 |
executeMulti() (PySQLPool.PySQLQuery method)
101 |
102 | 103 |

G

104 |
105 |
106 | 107 |
GetConnection() (PySQLPool.PySQLPool method)
108 |
getNewConnection() (in module PySQLPool)
109 |
getNewPool() (in module PySQLPool)
110 |
getNewQuery() (in module PySQLPool)
111 |
112 | 113 |

I

114 |
115 |
116 | 117 |
info (PySQLPool.PySQLConnection attribute)
118 |
119 | 120 |

K

121 |
122 |
123 | 124 |
key (PySQLPool.PySQLConnection attribute)
125 |
126 | 127 |

L

128 |
129 |
130 | 131 |
lastError (PySQLPool.PySQLQuery attribute)
132 |
lastInsertID (PySQLPool.PySQLQuery attribute)
133 |
134 | 135 |

M

136 |
137 |
138 | 139 |
maxActiveConnections (PySQLPool.PySQLPool attribute)
140 |
maxActivePerConnection (PySQLPool.PySQLPool attribute)
141 |
142 | 143 |

P

144 |
145 |
146 | 147 |
Pool (PySQLPool.PySQLQuery attribute)
148 |
PySQLConnection (class in PySQLPool)
149 |
PySQLConnectionManager (class in PySQLPool)
150 |
PySQLPool (class in PySQLPool)
151 |
152 |
(module)
153 |
154 |
PySQLQuery (class in PySQLPool)
155 |
156 | 157 |

Q

158 |
159 |
160 | 161 |
Query() (PySQLPool.PySQLQuery method)
162 |
query() (PySQLPool.PySQLQuery method)
163 |
queryMany() (PySQLPool.PySQLQuery method)
164 |
queryMulti() (PySQLPool.PySQLQuery method)
165 |
QueryOne() (PySQLPool.PySQLQuery method)
166 |
queryOne() (PySQLPool.PySQLQuery method)
167 |
168 | 169 |

R

170 |
171 |
172 | 173 |
ReConnect() (PySQLPool.PySQLConnectionManager method)
174 |
record (PySQLPool.PySQLQuery attribute)
175 |
returnConnection() (PySQLPool.PySQLPool method)
176 |
rowcount (PySQLPool.PySQLQuery attribute)
177 |
178 | 179 |

T

180 |
181 |
182 | 183 |
Terminate() (PySQLPool.PySQLPool method)
184 |
terminatePool() (in module PySQLPool)
185 |
TestConnection() (PySQLPool.PySQLConnectionManager method)
186 |
187 | 188 |

U

189 |
190 |
191 | 192 |
updateCheckTime() (PySQLPool.PySQLConnectionManager method)
193 |
194 | 195 | 196 | 197 |
198 |
199 |
200 |
201 |
202 | 203 | 204 | 205 | 217 | 218 |
219 |
220 |
221 |
222 | 234 | 239 | 240 | -------------------------------------------------------------------------------- /doc/_build/html/_static/searchtools.js: -------------------------------------------------------------------------------- 1 | /** 2 | * helper function to return a node containing the 3 | * search summary for a given text. keywords is a list 4 | * of stemmed words, hlwords is the list of normal, unstemmed 5 | * words. the first one is used to find the occurance, the 6 | * latter for highlighting it. 7 | */ 8 | 9 | jQuery.makeSearchSummary = function(text, keywords, hlwords) { 10 | var textLower = text.toLowerCase(); 11 | var start = 0; 12 | $.each(keywords, function() { 13 | var i = textLower.indexOf(this.toLowerCase()); 14 | if (i > -1) 15 | start = i; 16 | }); 17 | start = Math.max(start - 120, 0); 18 | var excerpt = ((start > 0) ? '...' : '') + 19 | $.trim(text.substr(start, 240)) + 20 | ((start + 240 - text.length) ? '...' : ''); 21 | var rv = $('
').text(excerpt); 22 | $.each(hlwords, function() { 23 | rv = rv.highlightText(this, 'highlight'); 24 | }); 25 | return rv; 26 | } 27 | 28 | /** 29 | * Porter Stemmer 30 | */ 31 | var PorterStemmer = function() { 32 | 33 | var step2list = { 34 | ational: 'ate', 35 | tional: 'tion', 36 | enci: 'ence', 37 | anci: 'ance', 38 | izer: 'ize', 39 | bli: 'ble', 40 | alli: 'al', 41 | entli: 'ent', 42 | eli: 'e', 43 | ousli: 'ous', 44 | ization: 'ize', 45 | ation: 'ate', 46 | ator: 'ate', 47 | alism: 'al', 48 | iveness: 'ive', 49 | fulness: 'ful', 50 | ousness: 'ous', 51 | aliti: 'al', 52 | iviti: 'ive', 53 | biliti: 'ble', 54 | logi: 'log' 55 | }; 56 | 57 | var step3list = { 58 | icate: 'ic', 59 | ative: '', 60 | alize: 'al', 61 | iciti: 'ic', 62 | ical: 'ic', 63 | ful: '', 64 | ness: '' 65 | }; 66 | 67 | var c = "[^aeiou]"; // consonant 68 | var v = "[aeiouy]"; // vowel 69 | var C = c + "[^aeiouy]*"; // consonant sequence 70 | var V = v + "[aeiou]*"; // vowel sequence 71 | 72 | var mgr0 = "^(" + C + ")?" + V + C; // [C]VC... is m>0 73 | var meq1 = "^(" + C + ")?" + V + C + "(" + V + ")?$"; // [C]VC[V] is m=1 74 | var mgr1 = "^(" + C + ")?" + V + C + V + C; // [C]VCVC... is m>1 75 | var s_v = "^(" + C + ")?" + v; // vowel in stem 76 | 77 | this.stemWord = function (w) { 78 | var stem; 79 | var suffix; 80 | var firstch; 81 | var origword = w; 82 | 83 | if (w.length < 3) 84 | return w; 85 | 86 | var re; 87 | var re2; 88 | var re3; 89 | var re4; 90 | 91 | firstch = w.substr(0,1); 92 | if (firstch == "y") 93 | w = firstch.toUpperCase() + w.substr(1); 94 | 95 | // Step 1a 96 | re = /^(.+?)(ss|i)es$/; 97 | re2 = /^(.+?)([^s])s$/; 98 | 99 | if (re.test(w)) 100 | w = w.replace(re,"$1$2"); 101 | else if (re2.test(w)) 102 | w = w.replace(re2,"$1$2"); 103 | 104 | // Step 1b 105 | re = /^(.+?)eed$/; 106 | re2 = /^(.+?)(ed|ing)$/; 107 | if (re.test(w)) { 108 | var fp = re.exec(w); 109 | re = new RegExp(mgr0); 110 | if (re.test(fp[1])) { 111 | re = /.$/; 112 | w = w.replace(re,""); 113 | } 114 | } 115 | else if (re2.test(w)) { 116 | var fp = re2.exec(w); 117 | stem = fp[1]; 118 | re2 = new RegExp(s_v); 119 | if (re2.test(stem)) { 120 | w = stem; 121 | re2 = /(at|bl|iz)$/; 122 | re3 = new RegExp("([^aeiouylsz])\\1$"); 123 | re4 = new RegExp("^" + C + v + "[^aeiouwxy]$"); 124 | if (re2.test(w)) 125 | w = w + "e"; 126 | else if (re3.test(w)) { 127 | re = /.$/; 128 | w = w.replace(re,""); 129 | } 130 | else if (re4.test(w)) 131 | w = w + "e"; 132 | } 133 | } 134 | 135 | // Step 1c 136 | re = /^(.+?)y$/; 137 | if (re.test(w)) { 138 | var fp = re.exec(w); 139 | stem = fp[1]; 140 | re = new RegExp(s_v); 141 | if (re.test(stem)) 142 | w = stem + "i"; 143 | } 144 | 145 | // Step 2 146 | re = /^(.+?)(ational|tional|enci|anci|izer|bli|alli|entli|eli|ousli|ization|ation|ator|alism|iveness|fulness|ousness|aliti|iviti|biliti|logi)$/; 147 | if (re.test(w)) { 148 | var fp = re.exec(w); 149 | stem = fp[1]; 150 | suffix = fp[2]; 151 | re = new RegExp(mgr0); 152 | if (re.test(stem)) 153 | w = stem + step2list[suffix]; 154 | } 155 | 156 | // Step 3 157 | re = /^(.+?)(icate|ative|alize|iciti|ical|ful|ness)$/; 158 | if (re.test(w)) { 159 | var fp = re.exec(w); 160 | stem = fp[1]; 161 | suffix = fp[2]; 162 | re = new RegExp(mgr0); 163 | if (re.test(stem)) 164 | w = stem + step3list[suffix]; 165 | } 166 | 167 | // Step 4 168 | re = /^(.+?)(al|ance|ence|er|ic|able|ible|ant|ement|ment|ent|ou|ism|ate|iti|ous|ive|ize)$/; 169 | re2 = /^(.+?)(s|t)(ion)$/; 170 | if (re.test(w)) { 171 | var fp = re.exec(w); 172 | stem = fp[1]; 173 | re = new RegExp(mgr1); 174 | if (re.test(stem)) 175 | w = stem; 176 | } 177 | else if (re2.test(w)) { 178 | var fp = re2.exec(w); 179 | stem = fp[1] + fp[2]; 180 | re2 = new RegExp(mgr1); 181 | if (re2.test(stem)) 182 | w = stem; 183 | } 184 | 185 | // Step 5 186 | re = /^(.+?)e$/; 187 | if (re.test(w)) { 188 | var fp = re.exec(w); 189 | stem = fp[1]; 190 | re = new RegExp(mgr1); 191 | re2 = new RegExp(meq1); 192 | re3 = new RegExp("^" + C + v + "[^aeiouwxy]$"); 193 | if (re.test(stem) || (re2.test(stem) && !(re3.test(stem)))) 194 | w = stem; 195 | } 196 | re = /ll$/; 197 | re2 = new RegExp(mgr1); 198 | if (re.test(w) && re2.test(w)) { 199 | re = /.$/; 200 | w = w.replace(re,""); 201 | } 202 | 203 | // and turn initial Y back to y 204 | if (firstch == "y") 205 | w = firstch.toLowerCase() + w.substr(1); 206 | return w; 207 | } 208 | } 209 | 210 | 211 | /** 212 | * Search Module 213 | */ 214 | var Search = { 215 | 216 | _index : null, 217 | _queued_query : null, 218 | _pulse_status : -1, 219 | 220 | init : function() { 221 | var params = $.getQueryParameters(); 222 | if (params.q) { 223 | var query = params.q[0]; 224 | $('input[name="q"]')[0].value = query; 225 | this.performSearch(query); 226 | } 227 | }, 228 | 229 | /** 230 | * Sets the index 231 | */ 232 | setIndex : function(index) { 233 | var q; 234 | this._index = index; 235 | if ((q = this._queued_query) !== null) { 236 | this._queued_query = null; 237 | Search.query(q); 238 | } 239 | }, 240 | 241 | hasIndex : function() { 242 | return this._index !== null; 243 | }, 244 | 245 | deferQuery : function(query) { 246 | this._queued_query = query; 247 | }, 248 | 249 | stopPulse : function() { 250 | this._pulse_status = 0; 251 | }, 252 | 253 | startPulse : function() { 254 | if (this._pulse_status >= 0) 255 | return; 256 | function pulse() { 257 | Search._pulse_status = (Search._pulse_status + 1) % 4; 258 | var dotString = ''; 259 | for (var i = 0; i < Search._pulse_status; i++) 260 | dotString += '.'; 261 | Search.dots.text(dotString); 262 | if (Search._pulse_status > -1) 263 | window.setTimeout(pulse, 500); 264 | }; 265 | pulse(); 266 | }, 267 | 268 | /** 269 | * perform a search for something 270 | */ 271 | performSearch : function(query) { 272 | // create the required interface elements 273 | this.out = $('#search-results'); 274 | this.title = $('

' + _('Searching') + '

').appendTo(this.out); 275 | this.dots = $('').appendTo(this.title); 276 | this.status = $('

').appendTo(this.out); 277 | this.output = $('