1
0
mirror of https://github.com/django/django.git synced 2025-07-05 18:29:11 +00:00

magic-removal: Fixed #1491 -- Added nice terminal colors to django-admin SQL output. Thanks, plmeister@gmail.com

git-svn-id: http://code.djangoproject.com/svn/django/branches/magic-removal@2585 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
Adrian Holovaty 2006-03-28 21:31:36 +00:00
parent 639fe6a87a
commit 493f8b9e5b
2 changed files with 194 additions and 63 deletions

View File

@ -5,6 +5,7 @@ import django
from django.core.exceptions import ImproperlyConfigured from django.core.exceptions import ImproperlyConfigured
import os, re, sys, textwrap import os, re, sys, textwrap
from optparse import OptionParser from optparse import OptionParser
from django.utils import termcolors
# For Python 2.3 # For Python 2.3
if not hasattr(__builtins__, 'set'): if not hasattr(__builtins__, 'set'):
@ -26,6 +27,28 @@ PROJECT_TEMPLATE_DIR = os.path.join(django.__path__[0], 'conf', '%s_template')
INVALID_PROJECT_NAMES = ('django', 'test') INVALID_PROJECT_NAMES = ('django', 'test')
# Set up the terminal color scheme.
class dummy: pass
style = dummy()
style.ERROR = termcolors.make_style(fg='red', opts=('bold',))
style.ERROR_OUTPUT = termcolors.make_style(fg='red', opts=('bold',))
style.SQL_FIELD = termcolors.make_style(fg='green', opts=('bold',))
style.SQL_COLTYPE = termcolors.make_style(fg='green')
style.SQL_KEYWORD = termcolors.make_style(fg='yellow')
style.SQL_TABLE = termcolors.make_style(opts=('bold',))
del dummy
def disable_termcolors():
class dummy:
def __getattr__(self, attr):
return lambda x: x
global style
style = dummy()
# Disable terminal coloring if somebody's piping the output.
if (not sys.stdout.isatty()) or (sys.platform == 'win32'):
disable_termcolors()
def _is_valid_dir_name(s): def _is_valid_dir_name(s):
return bool(re.search(r'^\w+$', s)) return bool(re.search(r'^\w+$', s))
@ -66,9 +89,9 @@ def get_sql_create(app):
if not data_types: if not data_types:
# This must be the "dummy" database backend, which means the user # This must be the "dummy" database backend, which means the user
# hasn't set DATABASE_ENGINE. # hasn't set DATABASE_ENGINE.
sys.stderr.write("Error: Django doesn't know which syntax to use for your SQL statements,\n" + sys.stderr.write(style.ERROR("Error: Django doesn't know which syntax to use for your SQL statements,\n" +
"because you haven't specified the DATABASE_ENGINE setting.\n" + "because you haven't specified the DATABASE_ENGINE setting.\n" +
"Edit your settings file and change DATABASE_ENGINE to something like 'postgresql' or 'mysql'.\n") "Edit your settings file and change DATABASE_ENGINE to something like 'postgresql' or 'mysql'.\n"))
sys.exit(1) sys.exit(1)
# Get installed models, so we generate REFERENCES right # Get installed models, so we generate REFERENCES right
@ -128,29 +151,33 @@ def _get_sql_model_create(klass, models_already_seen=set()):
col_type = data_types[data_type] col_type = data_types[data_type]
if col_type is not None: if col_type is not None:
# Make the definition (e.g. 'foo VARCHAR(30)') for this field. # Make the definition (e.g. 'foo VARCHAR(30)') for this field.
field_output = [backend.quote_name(f.column), col_type % rel_field.__dict__] field_output = [style.SQL_FIELD(backend.quote_name(f.column)),
field_output.append('%sNULL' % (not f.null and 'NOT ' or '')) style.SQL_COLTYPE(col_type % rel_field.__dict__)]
field_output.append(style.SQL_KEYWORD('%sNULL' % (not f.null and 'NOT ' or '')))
if f.unique: if f.unique:
field_output.append('UNIQUE') field_output.append(style.SQL_KEYWORD('UNIQUE'))
if f.primary_key: if f.primary_key:
field_output.append('PRIMARY KEY') field_output.append(style.SQL_KEYWORD('PRIMARY KEY'))
if f.rel: if f.rel:
if f.rel.to in models_already_seen: if f.rel.to in models_already_seen:
field_output.append('REFERENCES %s (%s)' % \ field_output.append(style.SQL_KEYWORD('REFERENCES') + ' ' + \
(backend.quote_name(f.rel.to._meta.db_table), style.SQL_TABLE(backend.quote_name(f.rel.to._meta.db_table)) + ' (' + \
backend.quote_name(f.rel.to._meta.get_field(f.rel.field_name).column))) style.SQL_FIELD(backend.quote_name(f.rel.to._meta.get_field(f.rel.field_name).column)) + ')'
)
else: else:
# We haven't yet created the table to which this field # We haven't yet created the table to which this field
# is related, so save it for later. # is related, so save it for later.
pr = pending_references.setdefault(f.rel.to, []).append((klass, f)) pr = pending_references.setdefault(f.rel.to, []).append((klass, f))
table_output.append(' '.join(field_output)) table_output.append(' '.join(field_output))
if opts.order_with_respect_to: if opts.order_with_respect_to:
table_output.append('%s %s NULL' % (backend.quote_name('_order'), data_types['IntegerField'])) table_output.append(style.SQL_FIELD(backend.quote_name('_order')) + ' ' + \
style.SQL_COLTYPE(data_types['IntegerField']) + ' ' + \
style.SQL_KEYWORD('NULL'))
for field_constraints in opts.unique_together: for field_constraints in opts.unique_together:
table_output.append('UNIQUE (%s)' % \ table_output.append(style.SQL_KEYWORD('UNIQUE') + ' (%s)' % \
", ".join([backend.quote_name(opts.get_field(f).column) for f in field_constraints])) ", ".join([backend.quote_name(style.SQL_FIELD(opts.get_field(f).column)) for f in field_constraints]))
full_statement = ['CREATE TABLE %s (' % backend.quote_name(opts.db_table)] full_statement = [style.SQL_KEYWORD('CREATE TABLE') + ' ' + style.SQL_TABLE(backend.quote_name(opts.db_table)) + ' (']
for i, line in enumerate(table_output): # Combine and add commas. for i, line in enumerate(table_output): # Combine and add commas.
full_statement.append(' %s%s' % (line, i < len(table_output)-1 and ',' or '')) full_statement.append(' %s%s' % (line, i < len(table_output)-1 and ',' or ''))
full_statement.append(');') full_statement.append(');')
@ -175,9 +202,9 @@ def _get_sql_for_pending_references(klass, pending_references):
r_col = f.column r_col = f.column
table = opts.db_table table = opts.db_table
col = opts.get_field(f.rel.field_name).column col = opts.get_field(f.rel.field_name).column
final_output.append('ALTER TABLE %s ADD CONSTRAINT %s FOREIGN KEY (%s) REFERENCES %s (%s);' % \ final_output.append(style.SQL_KEYWORD('ALTER TABLE') + ' %s ADD CONSTRAINT %s FOREIGN KEY (%s) REFERENCES %s (%s);' % \
(backend.quote_name(r_table), (backend.quote_name(r_table),
backend.quote_name("%s_referencing_%s_%s" % (r_col, table, col)), backend.quote_name('%s_referencing_%s_%s' % (r_col, table, col)),
backend.quote_name(r_col), backend.quote_name(table), backend.quote_name(col))) backend.quote_name(r_col), backend.quote_name(table), backend.quote_name(col)))
del pending_references[klass] del pending_references[klass]
return final_output return final_output
@ -189,21 +216,28 @@ def _get_many_to_many_sql_for_model(klass):
opts = klass._meta opts = klass._meta
final_output = [] final_output = []
for f in opts.many_to_many: for f in opts.many_to_many:
table_output = ['CREATE TABLE %s (' % backend.quote_name(f.m2m_db_table())] table_output = [style.SQL_KEYWORD('CREATE TABLE') + ' ' + \
table_output.append(' %s %s NOT NULL PRIMARY KEY,' % (backend.quote_name('id'), data_types['AutoField'])) style.SQL_TABLE(backend.quote_name(f.m2m_db_table())) + ' (']
table_output.append(' %s %s NOT NULL REFERENCES %s (%s),' % \ table_output.append(' %s %s %s,' % \
(backend.quote_name(f.m2m_column_name()), (style.SQL_FIELD(backend.quote_name('id')),
data_types[get_rel_data_type(opts.pk)] % opts.pk.__dict__, style.SQL_COLTYPE(data_types['AutoField']),
backend.quote_name(opts.db_table), style.SQL_KEYWORD('NOT NULL PRIMARY KEY')))
backend.quote_name(opts.pk.column))) table_output.append(' %s %s %s %s (%s),' % \
table_output.append(' %s %s NOT NULL REFERENCES %s (%s),' % \ (style.SQL_FIELD(backend.quote_name(f.m2m_column_name())),
(backend.quote_name(f.m2m_reverse_name()), style.SQL_COLTYPE(data_types[get_rel_data_type(opts.pk)] % opts.pk.__dict__),
data_types[get_rel_data_type(f.rel.to._meta.pk)] % f.rel.to._meta.pk.__dict__, style.SQL_KEYWORD('NOT NULL REFERENCES'),
backend.quote_name(f.rel.to._meta.db_table), style.SQL_TABLE(backend.quote_name(opts.db_table)),
backend.quote_name(f.rel.to._meta.pk.column))) style.SQL_FIELD(backend.quote_name(opts.pk.column))))
table_output.append(' UNIQUE (%s, %s)' % \ table_output.append(' %s %s %s %s (%s),' % \
(backend.quote_name(f.m2m_column_name()), (style.SQL_FIELD(backend.quote_name(f.m2m_reverse_name())),
backend.quote_name(f.m2m_reverse_name()))) style.SQL_COLTYPE(data_types[get_rel_data_type(f.rel.to._meta.pk)] % f.rel.to._meta.pk.__dict__),
style.SQL_KEYWORD('NOT NULL REFERENCES'),
style.SQL_TABLE(backend.quote_name(f.rel.to._meta.db_table)),
style.SQL_FIELD(backend.quote_name(f.rel.to._meta.pk.column))))
table_output.append(' %s (%s, %s)' % \
(style.SQL_KEYWORD('UNIQUE'),
style.SQL_FIELD(backend.quote_name(f.m2m_column_name())),
style.SQL_FIELD(backend.quote_name(f.m2m_reverse_name()))))
table_output.append(');') table_output.append(');')
final_output.append('\n'.join(table_output)) final_output.append('\n'.join(table_output))
return final_output return final_output
@ -244,17 +278,20 @@ def get_sql_delete(app):
for klass in app_models: for klass in app_models:
if cursor and klass._meta.db_table in table_names: if cursor and klass._meta.db_table in table_names:
# Drop the able now # Drop the table now
output.append("DROP TABLE %s;" % backend.quote_name(klass._meta.db_table)) output.append('%s %s;' % (style.SQL_KEYWORD('DROP TABLE'),
style.SQL_TABLE(backend.quote_name(klass._meta.db_table))))
if backend.supports_constraints and references_to_delete.has_key(klass): if backend.supports_constraints and references_to_delete.has_key(klass):
for rel_class, f in references_to_delete[klass]: for rel_class, f in references_to_delete[klass]:
table = rel_class._meta.db_table table = rel_class._meta.db_table
col = f.column col = f.column
r_table = klass._meta.db_table r_table = klass._meta.db_table
r_col = klass._meta.get_field(f.rel.field_name).column r_col = klass._meta.get_field(f.rel.field_name).column
output.append('ALTER TABLE %s DROP CONSTRAINT %s;' % \ output.append('%s %s %s %s;' % \
(backend.quote_name(table), (style.SQL_KEYWORD('ALTER TABLE'),
backend.quote_name("%s_referencing_%s_%s" % (col, r_table, r_col)))) style.SQL_TABLE(backend.quote_name(table)),
style.SQL_KEYWORD('DROP CONSTRAINT'),
style.SQL_FIELD(backend.quote_name("%s_referencing_%s_%s" % (col, r_table, r_col)))))
del references_to_delete[klass] del references_to_delete[klass]
# Output DROP TABLE statements for many-to-many tables. # Output DROP TABLE statements for many-to-many tables.
@ -262,10 +299,13 @@ def get_sql_delete(app):
opts = klass._meta opts = klass._meta
for f in opts.many_to_many: for f in opts.many_to_many:
if cursor and f.m2m_db_table() in table_names: if cursor and f.m2m_db_table() in table_names:
output.append("DROP TABLE %s;" % backend.quote_name(f.m2m_db_table())) output.append("%s %s;" % (style.SQL_KEYWORD('DROP TABLE'),
style.SQL_TABLE(backend.quote_name(f.m2m_db_table()))))
app_label = app_models[0]._meta.app_label app_label = app_models[0]._meta.app_label
# TODO: Remove the following section.
# Delete from django_package, auth_permission, django_content_type. # Delete from django_package, auth_permission, django_content_type.
if cursor and "django_content_type" in table_names: if cursor and "django_content_type" in table_names:
@ -346,12 +386,22 @@ def get_sql_sequence_reset(app):
for klass in models.get_models(app): for klass in models.get_models(app):
for f in klass._meta.fields: for f in klass._meta.fields:
if isinstance(f, models.AutoField): if isinstance(f, models.AutoField):
output.append("SELECT setval('%s_%s_seq', (SELECT max(%s) FROM %s));" % \ output.append("%s setval('%s', (%s max(%s) %s %s));" % \
(klass._meta.db_table, f.column, backend.quote_name(f.column), (style.SQL_KEYWORD('SELECT'),
backend.quote_name(klass._meta.db_table))) style.SQL_FIELD('%s_%s_seq' % (klass._meta.db_table, f.column)),
style.SQL_KEYWORD('SELECT'),
style.SQL_FIELD(backend.quote_name(f.column)),
style.SQL_KEYWORD('FROM'),
style.SQL_TABLE(backend.quote_name(klass._meta.db_table))))
break # Only one AutoField is allowed per model, so don't bother continuing.
for f in klass._meta.many_to_many: for f in klass._meta.many_to_many:
output.append("SELECT setval('%s_id_seq', (SELECT max(%s) FROM %s));" % \ output.append("%s setval('%s', (%s max(%s) %s %s));" % \
(f.m2m_db_table(), backend.quote_name('id'), f.m2m_db_table())) (style.SQL_KEYWORD('SELECT'),
style.SQL_FIELD('%s_id_seq' % f.m2m_db_table()),
style.SQL_KEYWORD('SELECT'),
style.SQL_FIELD(backend.quote_name('id')),
style.SQL_KEYWORD('FROM'),
style.SQL_TABLE(f.m2m_db_table())))
return output return output
get_sql_sequence_reset.help_doc = "Prints the SQL statements for resetting PostgreSQL sequences for the given app name(s)." get_sql_sequence_reset.help_doc = "Prints the SQL statements for resetting PostgreSQL sequences for the given app name(s)."
get_sql_sequence_reset.args = APP_ARGS get_sql_sequence_reset.args = APP_ARGS
@ -364,10 +414,14 @@ def get_sql_indexes(app):
for klass in models.get_models(app): for klass in models.get_models(app):
for f in klass._meta.fields: for f in klass._meta.fields:
if f.db_index: if f.db_index:
unique = f.unique and "UNIQUE " or "" unique = f.unique and 'UNIQUE ' or ''
output.append("CREATE %sINDEX %s_%s ON %s (%s);" % \ output.append(
(unique, klass._meta.db_table, f.column, style.SQL_KEYWORD('CREATE %sINDEX' % unique) + ' ' + \
backend.quote_name(klass._meta.db_table), backend.quote_name(f.column))) style.SQL_TABLE('%s_%s' % (klass._meta.db_table, f.column)) + ' ' + \
style.SQL_KEYWORD('ON') + ' ' + \
style.SQL_TABLE(backend.quote_name(klass._meta.db_table)) + ' ' + \
"(%s);" % style.SQL_FIELD(backend.quote_name(f.column))
)
return output return output
get_sql_indexes.help_doc = "Prints the CREATE INDEX SQL statements for the given model module name(s)." get_sql_indexes.help_doc = "Prints the CREATE INDEX SQL statements for the given model module name(s)."
get_sql_indexes.args = APP_ARGS get_sql_indexes.args = APP_ARGS
@ -385,7 +439,9 @@ def syncdb():
from django.conf import settings from django.conf import settings
from django.dispatch import dispatcher from django.dispatch import dispatcher
# Check that there are no validation errors before continuing disable_termcolors()
# First, try validating the models.
_check_for_validation_errors() _check_for_validation_errors()
# Import the 'management' module within each installed app, to register # Import the 'management' module within each installed app, to register
@ -489,6 +545,8 @@ def install(app):
app_name = app.__name__.split('.')[-2] app_name = app.__name__.split('.')[-2]
disable_termcolors()
# First, try validating the models. # First, try validating the models.
_check_for_validation_errors(app) _check_for_validation_errors(app)
@ -499,12 +557,12 @@ def install(app):
for sql in sql_list: for sql in sql_list:
cursor.execute(sql) cursor.execute(sql)
except Exception, e: except Exception, e:
sys.stderr.write("""Error: %s couldn't be installed. Possible reasons: sys.stderr.write(style.ERROR("""Error: %s couldn't be installed. Possible reasons:
* The database isn't running or isn't configured correctly. * The database isn't running or isn't configured correctly.
* At least one of the database tables already exists. * At least one of the database tables already exists.
* The SQL was invalid. * The SQL was invalid.
Hint: Look at the output of 'django-admin.py sqlall %s'. That's the SQL this command wasn't able to run. Hint: Look at the output of 'django-admin.py sqlall %s'. That's the SQL this command wasn't able to run.
The full error: %s\n""" % (app_name, app_name, e)) The full error: """ % (app_name, app_name)) + style.ERROR_OUTPUT(e) + '\n')
transaction.rollback_unless_managed() transaction.rollback_unless_managed()
sys.exit(1) sys.exit(1)
transaction.commit_unless_managed() transaction.commit_unless_managed()
@ -517,6 +575,8 @@ def reset(app):
from cStringIO import StringIO from cStringIO import StringIO
app_name = app.__name__.split('.')[-2] app_name = app.__name__.split('.')[-2]
disable_termcolors()
# First, try validating the models. # First, try validating the models.
_check_for_validation_errors(app) _check_for_validation_errors(app)
sql_list = get_sql_reset(app) sql_list = get_sql_reset(app)
@ -533,12 +593,12 @@ Type 'yes' to continue, or 'no' to cancel: """)
for sql in sql_list: for sql in sql_list:
cursor.execute(sql) cursor.execute(sql)
except Exception, e: except Exception, e:
sys.stderr.write("""Error: %s couldn't be installed. Possible reasons: sys.stderr.write(style.ERROR("""Error: %s couldn't be installed. Possible reasons:
* The database isn't running or isn't configured correctly. * The database isn't running or isn't configured correctly.
* At least one of the database tables already exists. * At least one of the database tables already exists.
* The SQL was invalid. * The SQL was invalid.
Hint: Look at the output of 'django-admin.py sqlreset %s'. That's the SQL this command wasn't able to run. Hint: Look at the output of 'django-admin.py sqlreset %s'. That's the SQL this command wasn't able to run.
The full error: %s\n""" % (app_name, app_name, e)) The full error: """ % (app_name, app_name)) + style.ERROR_OUTPUT(e) + '\n')
transaction.rollback_unless_managed() transaction.rollback_unless_managed()
sys.exit(1) sys.exit(1)
transaction.commit_unless_managed() transaction.commit_unless_managed()
@ -550,13 +610,13 @@ reset.args = APP_ARGS
def _start_helper(app_or_project, name, directory, other_name=''): def _start_helper(app_or_project, name, directory, other_name=''):
other = {'project': 'app', 'app': 'project'}[app_or_project] other = {'project': 'app', 'app': 'project'}[app_or_project]
if not _is_valid_dir_name(name): if not _is_valid_dir_name(name):
sys.stderr.write("Error: %r is not a valid %s name. Please use only numbers, letters and underscores.\n" % (name, app_or_project)) sys.stderr.write(style.ERROR("Error: %r is not a valid %s name. Please use only numbers, letters and underscores.\n" % (name, app_or_project)))
sys.exit(1) sys.exit(1)
top_dir = os.path.join(directory, name) top_dir = os.path.join(directory, name)
try: try:
os.mkdir(top_dir) os.mkdir(top_dir)
except OSError, e: except OSError, e:
sys.stderr.write("Error: %s\n" % e) sys.stderr.write(style.ERROR("Error: %s\n" % e))
sys.exit(1) sys.exit(1)
template_dir = PROJECT_TEMPLATE_DIR % app_or_project template_dir = PROJECT_TEMPLATE_DIR % app_or_project
for d, subdirs, files in os.walk(template_dir): for d, subdirs, files in os.walk(template_dir):
@ -579,7 +639,7 @@ def startproject(project_name, directory):
"Creates a Django project for the given project_name in the given directory." "Creates a Django project for the given project_name in the given directory."
from random import choice from random import choice
if project_name in INVALID_PROJECT_NAMES: if project_name in INVALID_PROJECT_NAMES:
sys.stderr.write("Error: %r isn't a valid project name. Please try another.\n" % project_name) sys.stderr.write(style.ERROR("Error: %r isn't a valid project name. Please try another.\n" % project_name))
sys.exit(1) sys.exit(1)
_start_helper('project', project_name, directory) _start_helper('project', project_name, directory)
# Create a random SECRET_KEY hash, and put it in the main settings. # Create a random SECRET_KEY hash, and put it in the main settings.
@ -714,7 +774,7 @@ class ModelErrorCollection:
def add(self, opts, error): def add(self, opts, error):
self.errors.append((opts, error)) self.errors.append((opts, error))
self.outfile.write("%s.%s: %s\n" % (opts.app_label, opts.module_name, error)) self.outfile.write(style.ERROR("%s.%s: %s\n" % (opts.app_label, opts.module_name, error)))
def get_validation_errors(outfile, app=None): def get_validation_errors(outfile, app=None):
""" """
@ -885,7 +945,7 @@ def _check_for_validation_errors(app=None):
s = StringIO() s = StringIO()
num_errors = get_validation_errors(s, app) num_errors = get_validation_errors(s, app)
if num_errors: if num_errors:
sys.stderr.write("Error: %s couldn't be installed, because there were errors in your model:\n" % app) sys.stderr.write(style.ERROR("Error: %s couldn't be installed, because there were errors in your model:\n" % app))
s.seek(0) s.seek(0)
sys.stderr.write(s.read()) sys.stderr.write(s.read())
sys.exit(1) sys.exit(1)
@ -897,7 +957,7 @@ def runserver(addr, port):
if not addr: if not addr:
addr = '127.0.0.1' addr = '127.0.0.1'
if not port.isdigit(): if not port.isdigit():
sys.stderr.write("Error: %r is not a valid port number.\n" % port) sys.stderr.write(style.ERROR("Error: %r is not a valid port number.\n" % port))
sys.exit(1) sys.exit(1)
def inner_run(): def inner_run():
from django.conf import settings from django.conf import settings
@ -919,7 +979,7 @@ def runserver(addr, port):
error_text = ERRORS[e.args[0].args[0]] error_text = ERRORS[e.args[0].args[0]]
except (AttributeError, KeyError): except (AttributeError, KeyError):
error_text = str(e) error_text = str(e)
sys.stderr.write("Error: %s\n" % error_text) sys.stderr.write(style.ERROR("Error: %s" % error_text) + '\n')
sys.exit(1) sys.exit(1)
except KeyboardInterrupt: except KeyboardInterrupt:
sys.exit(0) sys.exit(0)
@ -1005,7 +1065,8 @@ NO_SQL_TRANSACTION = (
'createcachetable', 'createcachetable',
'install', 'install',
'reset', 'reset',
'sqlindexes' 'sqlindexes',
'syncdb'
) )
class DjangoOptionParser(OptionParser): class DjangoOptionParser(OptionParser):
@ -1029,7 +1090,7 @@ def get_usage(action_mapping):
return '\n'.join(usage[:-1]) # Cut off last list element, an empty space. return '\n'.join(usage[:-1]) # Cut off last list element, an empty space.
def print_error(msg, cmd): def print_error(msg, cmd):
sys.stderr.write('Error: %s\nRun "%s --help" for help.\n' % (msg, cmd)) sys.stderr.write(style.ERROR('Error: %s' % msg) + '\nRun "%s --help" for help.\n' % cmd)
sys.exit(1) sys.exit(1)
def execute_from_command_line(action_mapping=DEFAULT_ACTION_MAPPING): def execute_from_command_line(action_mapping=DEFAULT_ACTION_MAPPING):
@ -1078,7 +1139,7 @@ def execute_from_command_line(action_mapping=DEFAULT_ACTION_MAPPING):
for line in action_mapping[action](param): for line in action_mapping[action](param):
print line print line
except NotImplementedError: except NotImplementedError:
sys.stderr.write("Error: %r isn't supported for the currently selected database backend.\n" % action) sys.stderr.write(style.ERROR("Error: %r isn't supported for the currently selected database backend.\n" % action))
sys.exit(1) sys.exit(1)
elif action == 'createcachetable': elif action == 'createcachetable':
try: try:
@ -1106,18 +1167,18 @@ def execute_from_command_line(action_mapping=DEFAULT_ACTION_MAPPING):
try: try:
mod_list = [models.get_app(app_label) for app_label in args[1:]] mod_list = [models.get_app(app_label) for app_label in args[1:]]
except ImportError, e: except ImportError, e:
sys.stderr.write("Error: %s. Are you sure your INSTALLED_APPS setting is correct?\n" % e) sys.stderr.write(style.ERROR("Error: %s. Are you sure your INSTALLED_APPS setting is correct?\n" % e))
sys.exit(1) sys.exit(1)
if not mod_list: if not mod_list:
parser.print_usage_and_exit() parser.print_usage_and_exit()
if action not in NO_SQL_TRANSACTION: if action not in NO_SQL_TRANSACTION:
print "BEGIN;" print style.SQL_KEYWORD("BEGIN;")
for mod in mod_list: for mod in mod_list:
output = action_mapping[action](mod) output = action_mapping[action](mod)
if output: if output:
print '\n'.join(output) print '\n'.join(output)
if action not in NO_SQL_TRANSACTION: if action not in NO_SQL_TRANSACTION:
print "COMMIT;" print style.SQL_KEYWORD("COMMIT;")
def execute_manager(settings_mod): def execute_manager(settings_mod):
# Add this project to sys.path so that it's importable in the conventional # Add this project to sys.path so that it's importable in the conventional

View File

@ -0,0 +1,70 @@
"""
termcolors.py
"""
import types
color_names = ('black', 'red', 'green', 'yellow', 'blue', 'magenta', 'cyan', 'white')
foreground = dict([(color_names[x], '3%s' % x) for x in range(8)])
background = dict([(color_names[x], '4%s' % x) for x in range(8)])
del color_names
RESET = '0'
opt_dict = {'bold': '1', 'underscore': '4', 'blink': '5', 'reverse': '7', 'conceal': '8'}
def colorize(text='', opts=(), **kwargs):
"""
Returns your text, enclosed in ANSI graphics codes.
Depends on the keyword arguments 'fg' and 'bg', and the contents of
the opts tuple/list.
Returns the RESET code if no parameters are given.
Valid colors:
'black', 'red', 'green', 'yellow', 'blue', 'magenta', 'cyan', 'white'
Valid options:
'bold'
'underscore'
'blink'
'reverse'
'conceal'
'noreset' - string will not be auto-terminated with the RESET code
Examples:
colorize('hello', fg='red', bg='blue', opts=('blink',))
colorize()
colorize('goodbye', opts=('underscore',))
print colorize('first line', fg='red', opts=('noreset',))
print 'this should be red too'
print colorize('and so should this')
print 'this should not be red'
"""
text = str(text)
code_list = []
if text == '' and len(opts) == 1 and opts[0] == 'reset':
return '\x1b[%sm' % RESET
for k, v in kwargs.iteritems():
if k == 'fg':
code_list.append(foreground[v])
elif k == 'bg':
code_list.append(background[v])
for o in opts:
if o in opt_dict:
code_list.append(opt_dict[o])
if 'noreset' not in opts:
text = text + '\x1b[%sm' % RESET
return ('\x1b[%sm' % ';'.join(code_list)) + text
def make_style(opts=(), **kwargs):
"""
Returns a function with default parameters for colorize()
Example:
bold_red = make_style(opts=('bold',), fg='red')
print bold_red('hello')
KEYWORD = make_style(fg='yellow')
COMMENT = make_style(fg='blue', opts=('bold',))
"""
return lambda text: colorize(text, opts, **kwargs)