Remove tornado.database, which is now distributed separately.
This commit is contained in:
parent
4044f96c96
commit
186e947112
|
@ -21,7 +21,7 @@ matrix:
|
|||
install:
|
||||
- if [[ $TRAVIS_PYTHON_VERSION == '2.5' ]]; then pip install --use-mirrors simplejson unittest2; fi
|
||||
- if [[ $TRAVIS_PYTHON_VERSION == '2.6' ]]; then pip install --use-mirrors unittest2; fi
|
||||
- if [[ $FULL == 'true' ]]; then sudo apt-get install librtmp-dev; pip install --use-mirrors MySQL-python pycurl; fi
|
||||
- if [[ $FULL == 'true' ]]; then sudo apt-get install librtmp-dev; pip install --use-mirrors pycurl; fi
|
||||
- if [[ $FULL == 'true' && $TRAVIS_PYTHON_VERSION == '2.5' ]]; then pip install --use-mirrors twisted==11.0.0 'zope.interface<4.0'; fi
|
||||
- if [[ $FULL == 'true' && $TRAVIS_PYTHON_VERSION == '2.6' ]]; then pip install --use-mirrors twisted==11.0.0; fi
|
||||
- if [[ $FULL == 'true' && $TRAVIS_PYTHON_VERSION == '2.7' ]]; then pip install --use-mirrors twisted==12.0.0; fi
|
||||
|
|
|
@ -16,6 +16,10 @@ need to set up MySQL and the database schema for the demo to run.
|
|||
can run "apt-get install mysql". Under OS X you can download the
|
||||
MySQL PKG file from http://dev.mysql.com/downloads/mysql/
|
||||
|
||||
3. Install Python prerequisites
|
||||
|
||||
Install the packages MySQL-python and torndb (e.g. using pip or easy_install)
|
||||
|
||||
3. Connect to MySQL and create a database and user for the blog.
|
||||
|
||||
Connect to MySQL as a user that can create databases and users:
|
||||
|
@ -51,7 +55,7 @@ need to set up MySQL and the database schema for the demo to run.
|
|||
authentication.
|
||||
|
||||
Currently the first user to connect will automatically be given the
|
||||
ability to create and edit posts.
|
||||
ability to create and edit posts.
|
||||
|
||||
Once you've created one blog post, subsequent users will not be
|
||||
prompted to sign in.
|
||||
|
|
|
@ -17,8 +17,8 @@
|
|||
import markdown
|
||||
import os.path
|
||||
import re
|
||||
import torndb
|
||||
import tornado.auth
|
||||
import tornado.database
|
||||
import tornado.httpserver
|
||||
import tornado.ioloop
|
||||
import tornado.options
|
||||
|
@ -58,7 +58,7 @@ class Application(tornado.web.Application):
|
|||
tornado.web.Application.__init__(self, handlers, **settings)
|
||||
|
||||
# Have one global connection to the blog DB across all handlers
|
||||
self.db = tornado.database.Connection(
|
||||
self.db = torndb.Connection(
|
||||
host=options.mysql_host, database=options.mysql_database,
|
||||
user=options.mysql_user, password=options.mysql_password)
|
||||
|
||||
|
@ -152,7 +152,7 @@ class AuthLoginHandler(BaseHandler, tornado.auth.GoogleMixin):
|
|||
self.get_authenticated_user(self.async_callback(self._on_auth))
|
||||
return
|
||||
self.authenticate_redirect()
|
||||
|
||||
|
||||
def _on_auth(self, user):
|
||||
if not user:
|
||||
raise tornado.web.HTTPError(500, "Google auth failed")
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
# Frozen pip requirements for tools used in the development of tornado
|
||||
|
||||
# Tornado's optional dependencies
|
||||
MySQL-python==1.2.3
|
||||
Twisted==12.1.0
|
||||
pycurl==7.19.0
|
||||
|
||||
|
|
|
@ -33,7 +33,6 @@ def import_everything():
|
|||
# import tornado.auth
|
||||
# import tornado.autoreload
|
||||
# import tornado.curl_httpclient # depends on pycurl
|
||||
# import tornado.database # depends on MySQLdb
|
||||
import tornado.escape
|
||||
# import tornado.httpclient
|
||||
# import tornado.httpserver
|
||||
|
@ -53,7 +52,7 @@ def import_everything():
|
|||
import tornado.web
|
||||
# import tornado.websocket
|
||||
import tornado.wsgi
|
||||
|
||||
|
||||
def all():
|
||||
return unittest.defaultTestLoader.loadTestsFromNames(TEST_MODULES)
|
||||
|
||||
|
@ -72,4 +71,3 @@ def main():
|
|||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
||||
|
|
|
@ -12,7 +12,6 @@ apt-get update
|
|||
APT_PACKAGES="
|
||||
python-pip
|
||||
python-dev
|
||||
libmysqlclient-dev
|
||||
libcurl4-openssl-dev
|
||||
python-software-properties
|
||||
"
|
||||
|
@ -40,7 +39,6 @@ apt-get -y install $DEADSNAKES_PACKAGES
|
|||
PIP_PACKAGES="
|
||||
virtualenv
|
||||
tox
|
||||
MySQL-python
|
||||
pycurl
|
||||
twisted
|
||||
"
|
||||
|
|
|
@ -15,7 +15,6 @@ deps =
|
|||
[testenv:py25-full]
|
||||
basepython = python2.5
|
||||
deps =
|
||||
MySQL-python
|
||||
pycurl
|
||||
simplejson
|
||||
twisted==11.0.0
|
||||
|
@ -27,7 +26,6 @@ deps = unittest2
|
|||
|
||||
[testenv:py26-full]
|
||||
deps =
|
||||
MySQL-python
|
||||
pycurl
|
||||
twisted==11.0.0
|
||||
unittest2
|
||||
|
@ -35,6 +33,5 @@ deps =
|
|||
[testenv:py27-full]
|
||||
basepython = python2.7
|
||||
deps =
|
||||
MySQL-python
|
||||
pycurl
|
||||
twisted==11.0.0
|
||||
|
|
|
@ -12,7 +12,6 @@ apt-get update
|
|||
APT_PACKAGES="
|
||||
python-pip
|
||||
python-dev
|
||||
libmysqlclient-dev
|
||||
libcurl4-openssl-dev
|
||||
python-software-properties
|
||||
"
|
||||
|
@ -38,7 +37,6 @@ apt-get -y install $DEADSNAKES_PACKAGES
|
|||
PIP_PACKAGES="
|
||||
virtualenv
|
||||
tox
|
||||
MySQL-python
|
||||
pycurl
|
||||
twisted
|
||||
"
|
||||
|
|
|
@ -15,7 +15,6 @@ deps =
|
|||
[testenv:py25-full]
|
||||
basepython = python2.5
|
||||
deps =
|
||||
MySQL-python
|
||||
pycurl
|
||||
simplejson
|
||||
twisted==11.0.0
|
||||
|
@ -29,6 +28,5 @@ deps = unittest2
|
|||
[testenv:py27-full]
|
||||
basepython = python2.7
|
||||
deps =
|
||||
MySQL-python
|
||||
pycurl
|
||||
twisted==11.0.0
|
|
@ -1,239 +0,0 @@
|
|||
#!/usr/bin/env python
|
||||
#
|
||||
# Copyright 2009 Facebook
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
"""A lightweight wrapper around MySQLdb."""
|
||||
|
||||
from __future__ import absolute_import, division, with_statement
|
||||
|
||||
import copy
|
||||
import itertools
|
||||
import time
|
||||
|
||||
from tornado.log import gen_log
|
||||
|
||||
try:
|
||||
import MySQLdb.constants
|
||||
import MySQLdb.converters
|
||||
import MySQLdb.cursors
|
||||
except ImportError:
|
||||
# If MySQLdb isn't available this module won't actually be useable,
|
||||
# but we want it to at least be importable (mainly for readthedocs.org,
|
||||
# which has limitations on third-party modules)
|
||||
MySQLdb = None
|
||||
|
||||
|
||||
class Connection(object):
|
||||
"""A lightweight wrapper around MySQLdb DB-API connections.
|
||||
|
||||
The main value we provide is wrapping rows in a dict/object so that
|
||||
columns can be accessed by name. Typical usage::
|
||||
|
||||
db = database.Connection("localhost", "mydatabase")
|
||||
for article in db.query("SELECT * FROM articles"):
|
||||
print article.title
|
||||
|
||||
Cursors are hidden by the implementation, but other than that, the methods
|
||||
are very similar to the DB-API.
|
||||
|
||||
We explicitly set the timezone to UTC and the character encoding to
|
||||
UTF-8 on all connections to avoid time zone and encoding errors.
|
||||
"""
|
||||
def __init__(self, host, database, user=None, password=None,
|
||||
max_idle_time=7 * 3600):
|
||||
self.host = host
|
||||
self.database = database
|
||||
self.max_idle_time = max_idle_time
|
||||
|
||||
args = dict(conv=CONVERSIONS, use_unicode=True, charset="utf8",
|
||||
db=database, init_command='SET time_zone = "+0:00"',
|
||||
sql_mode="TRADITIONAL")
|
||||
if user is not None:
|
||||
args["user"] = user
|
||||
if password is not None:
|
||||
args["passwd"] = password
|
||||
|
||||
# We accept a path to a MySQL socket file or a host(:port) string
|
||||
if "/" in host:
|
||||
args["unix_socket"] = host
|
||||
else:
|
||||
self.socket = None
|
||||
pair = host.split(":")
|
||||
if len(pair) == 2:
|
||||
args["host"] = pair[0]
|
||||
args["port"] = int(pair[1])
|
||||
else:
|
||||
args["host"] = host
|
||||
args["port"] = 3306
|
||||
|
||||
self._db = None
|
||||
self._db_args = args
|
||||
self._last_use_time = time.time()
|
||||
try:
|
||||
self.reconnect()
|
||||
except Exception:
|
||||
gen_log.error("Cannot connect to MySQL on %s", self.host,
|
||||
exc_info=True)
|
||||
|
||||
def __del__(self):
|
||||
self.close()
|
||||
|
||||
def close(self):
|
||||
"""Closes this database connection."""
|
||||
if getattr(self, "_db", None) is not None:
|
||||
self._db.close()
|
||||
self._db = None
|
||||
|
||||
def reconnect(self):
|
||||
"""Closes the existing database connection and re-opens it."""
|
||||
self.close()
|
||||
self._db = MySQLdb.connect(**self._db_args)
|
||||
self._db.autocommit(True)
|
||||
|
||||
def iter(self, query, *parameters):
|
||||
"""Returns an iterator for the given query and parameters."""
|
||||
self._ensure_connected()
|
||||
cursor = MySQLdb.cursors.SSCursor(self._db)
|
||||
try:
|
||||
self._execute(cursor, query, parameters)
|
||||
column_names = [d[0] for d in cursor.description]
|
||||
for row in cursor:
|
||||
yield Row(zip(column_names, row))
|
||||
finally:
|
||||
cursor.close()
|
||||
|
||||
def query(self, query, *parameters):
|
||||
"""Returns a row list for the given query and parameters."""
|
||||
cursor = self._cursor()
|
||||
try:
|
||||
self._execute(cursor, query, parameters)
|
||||
column_names = [d[0] for d in cursor.description]
|
||||
return [Row(itertools.izip(column_names, row)) for row in cursor]
|
||||
finally:
|
||||
cursor.close()
|
||||
|
||||
def get(self, query, *parameters):
|
||||
"""Returns the first row returned for the given query."""
|
||||
rows = self.query(query, *parameters)
|
||||
if not rows:
|
||||
return None
|
||||
elif len(rows) > 1:
|
||||
raise Exception("Multiple rows returned for Database.get() query")
|
||||
else:
|
||||
return rows[0]
|
||||
|
||||
# rowcount is a more reasonable default return value than lastrowid,
|
||||
# but for historical compatibility execute() must return lastrowid.
|
||||
def execute(self, query, *parameters):
|
||||
"""Executes the given query, returning the lastrowid from the query."""
|
||||
return self.execute_lastrowid(query, *parameters)
|
||||
|
||||
def execute_lastrowid(self, query, *parameters):
|
||||
"""Executes the given query, returning the lastrowid from the query."""
|
||||
cursor = self._cursor()
|
||||
try:
|
||||
self._execute(cursor, query, parameters)
|
||||
return cursor.lastrowid
|
||||
finally:
|
||||
cursor.close()
|
||||
|
||||
def execute_rowcount(self, query, *parameters):
|
||||
"""Executes the given query, returning the rowcount from the query."""
|
||||
cursor = self._cursor()
|
||||
try:
|
||||
self._execute(cursor, query, parameters)
|
||||
return cursor.rowcount
|
||||
finally:
|
||||
cursor.close()
|
||||
|
||||
def executemany(self, query, parameters):
|
||||
"""Executes the given query against all the given param sequences.
|
||||
|
||||
We return the lastrowid from the query.
|
||||
"""
|
||||
return self.executemany_lastrowid(query, parameters)
|
||||
|
||||
def executemany_lastrowid(self, query, parameters):
|
||||
"""Executes the given query against all the given param sequences.
|
||||
|
||||
We return the lastrowid from the query.
|
||||
"""
|
||||
cursor = self._cursor()
|
||||
try:
|
||||
cursor.executemany(query, parameters)
|
||||
return cursor.lastrowid
|
||||
finally:
|
||||
cursor.close()
|
||||
|
||||
def executemany_rowcount(self, query, parameters):
|
||||
"""Executes the given query against all the given param sequences.
|
||||
|
||||
We return the rowcount from the query.
|
||||
"""
|
||||
cursor = self._cursor()
|
||||
try:
|
||||
cursor.executemany(query, parameters)
|
||||
return cursor.rowcount
|
||||
finally:
|
||||
cursor.close()
|
||||
|
||||
def _ensure_connected(self):
|
||||
# Mysql by default closes client connections that are idle for
|
||||
# 8 hours, but the client library does not report this fact until
|
||||
# you try to perform a query and it fails. Protect against this
|
||||
# case by preemptively closing and reopening the connection
|
||||
# if it has been idle for too long (7 hours by default).
|
||||
if (self._db is None or
|
||||
(time.time() - self._last_use_time > self.max_idle_time)):
|
||||
self.reconnect()
|
||||
self._last_use_time = time.time()
|
||||
|
||||
def _cursor(self):
|
||||
self._ensure_connected()
|
||||
return self._db.cursor()
|
||||
|
||||
def _execute(self, cursor, query, parameters):
|
||||
try:
|
||||
return cursor.execute(query, parameters)
|
||||
except OperationalError:
|
||||
gen_log.error("Error connecting to MySQL on %s", self.host)
|
||||
self.close()
|
||||
raise
|
||||
|
||||
|
||||
class Row(dict):
|
||||
"""A dict that allows for object-like property access syntax."""
|
||||
def __getattr__(self, name):
|
||||
try:
|
||||
return self[name]
|
||||
except KeyError:
|
||||
raise AttributeError(name)
|
||||
|
||||
if MySQLdb is not None:
|
||||
# Fix the access conversions to properly recognize unicode/binary
|
||||
FIELD_TYPE = MySQLdb.constants.FIELD_TYPE
|
||||
FLAG = MySQLdb.constants.FLAG
|
||||
CONVERSIONS = copy.copy(MySQLdb.converters.conversions)
|
||||
|
||||
field_types = [FIELD_TYPE.BLOB, FIELD_TYPE.STRING, FIELD_TYPE.VAR_STRING]
|
||||
if 'VARCHAR' in vars(FIELD_TYPE):
|
||||
field_types.append(FIELD_TYPE.VARCHAR)
|
||||
|
||||
for field_type in field_types:
|
||||
CONVERSIONS[field_type] = [(FLAG.BINARY, str)] + CONVERSIONS[field_type]
|
||||
|
||||
# Alias some common MySQL exceptions
|
||||
IntegrityError = MySQLdb.IntegrityError
|
||||
OperationalError = MySQLdb.OperationalError
|
|
@ -10,7 +10,6 @@ class ImportTest(unittest.TestCase):
|
|||
import tornado.auth
|
||||
import tornado.autoreload
|
||||
# import tornado.curl_httpclient # depends on pycurl
|
||||
# import tornado.database # depends on MySQLdb
|
||||
import tornado.escape
|
||||
import tornado.httpclient
|
||||
import tornado.httpserver
|
||||
|
@ -42,14 +41,6 @@ class ImportTest(unittest.TestCase):
|
|||
else:
|
||||
import tornado.curl_httpclient
|
||||
|
||||
def test_import_mysqldb(self):
|
||||
try:
|
||||
import MySQLdb
|
||||
except ImportError:
|
||||
pass
|
||||
else:
|
||||
import tornado.database
|
||||
|
||||
def test_import_twisted(self):
|
||||
try:
|
||||
import twisted
|
||||
|
|
10
tox.ini
10
tox.ini
|
@ -7,9 +7,7 @@
|
|||
# less thorough.
|
||||
#
|
||||
# On my macports-based setup, the environment variable
|
||||
# ARCHFLAGS='-arch x86_64' must be set when building pycurl, and a
|
||||
# symlink from mysql_config to mysql_config5 must exist when building
|
||||
# MySQL-python.
|
||||
# ARCHFLAGS='-arch x86_64' must be set when building pycurl.
|
||||
[tox]
|
||||
# "-full" variants include optional dependencies, to ensure
|
||||
# that things work both in a bare install and with all the extras.
|
||||
|
@ -35,7 +33,6 @@ deps =
|
|||
[testenv:py25-full]
|
||||
basepython = python2.5
|
||||
deps =
|
||||
MySQL-python
|
||||
pycurl
|
||||
simplejson
|
||||
# twisted is dropping python 2.5 support in 12.2.0
|
||||
|
@ -53,7 +50,6 @@ deps = unittest2
|
|||
[testenv:py26-full]
|
||||
basepython = python2.6
|
||||
deps =
|
||||
MySQL-python
|
||||
pycurl
|
||||
twisted==11.0.0
|
||||
unittest2
|
||||
|
@ -61,7 +57,6 @@ deps =
|
|||
[testenv:py27-full]
|
||||
basepython = python2.7
|
||||
deps =
|
||||
MySQL-python
|
||||
pycurl
|
||||
twisted>=12.0.0
|
||||
|
||||
|
@ -71,7 +66,6 @@ deps =
|
|||
# this flag controls which client all the other tests use.
|
||||
basepython = python2.7
|
||||
deps =
|
||||
MySQL-python
|
||||
pycurl
|
||||
twisted>=11.1.0
|
||||
commands = python -m tornado.test.runtests --httpclient=tornado.curl_httpclient.CurlAsyncHTTPClient {posargs:}
|
||||
|
@ -83,7 +77,6 @@ commands = python -m tornado.test.runtests --httpclient=tornado.curl_httpclient.
|
|||
# run this configuration there.
|
||||
basepython = pypy
|
||||
deps =
|
||||
MySQL-python
|
||||
twisted>=12.1.0
|
||||
|
||||
# In python 3, opening files in text mode uses a system-dependent encoding by
|
||||
|
@ -113,7 +106,6 @@ basepython = python3.3
|
|||
[testenv:py27-opt]
|
||||
basepython = python2.7
|
||||
deps =
|
||||
MySQL-python
|
||||
pycurl
|
||||
twisted>=12.0.0
|
||||
commands = python -O -m tornado.test.runtests {posargs:}
|
||||
|
|
|
@ -1,5 +0,0 @@
|
|||
``tornado.database`` --- Simple MySQL client wrapper
|
||||
====================================================
|
||||
|
||||
.. automodule:: tornado.database
|
||||
:members:
|
|
@ -4,7 +4,6 @@ Integration with other services
|
|||
.. toctree::
|
||||
|
||||
auth
|
||||
database
|
||||
twisted
|
||||
websocket
|
||||
wsgi
|
||||
|
|
|
@ -33,3 +33,5 @@ In progress
|
|||
* New function `tornado.testing.bind_unused_port` both chooses a port
|
||||
and binds a socket to it, so there is no risk of another process
|
||||
using the same port. ``get_unused_port`` is now deprecated.
|
||||
* The `tornado.database` module has been removed. It is now available
|
||||
as a separate package, `torndb <https://github.com/bdarnell/torndb>`_
|
||||
|
|
Loading…
Reference in New Issue