/sqlautocode/config.py

https://code.google.com/p/sqlautocode/ · Python · 189 lines · 142 code · 39 blank · 8 comment · 25 complexity · a012232eaa45ab8b0024c8d35504cd04 MD5 · raw file

  1. #!python
  2. #-*- coding: UTF-8 -*-
  3. import optparse
  4. import os
  5. import sys
  6. import re
  7. options = None
  8. out = sys.stdout
  9. err = sys.stderr
  10. dburl = None
  11. engine = None
  12. # TODO: encoding (default utf-8)
  13. def create_parser():
  14. parser = optparse.OptionParser(
  15. """autocode.py <database_url> [options, ]
  16. Generates Python source code for a given database schema.
  17. Example: ./autocode.py postgres://user:password@myhost/database -o out.py""")
  18. parser.add_option(
  19. "-o", "--output",
  20. help="Write to file (default is stdout)",
  21. action="store", dest="output")
  22. parser.add_option(
  23. "--force",
  24. help="Overwrite Write to file (default is stdout)",
  25. action="store_true", dest="force")
  26. parser.add_option(
  27. "-s", "--schema",
  28. help="Optional, reflect a non-default schema",
  29. action="callback", callback=_prep_schema, type="string", dest="schema")
  30. parser.add_option(
  31. "-t", "--tables",
  32. help=("Optional, only reflect this comma-separated list of tables. "
  33. "Wildcarding with '*' is supported, e.g: --tables account_*,"
  34. "orders,order_items,*_audit"),
  35. action="callback", callback=_prep_tables, type="string", dest="tables")
  36. parser.add_option(
  37. "-b", "--table-prefix",
  38. help="Prefix for generated SQLAlchemy Table object names",
  39. action="store", dest="table_prefix")
  40. parser.add_option(
  41. "-a", "--table-suffix",
  42. help="Suffix for generated SQLAlchemy Table object names",
  43. action="store", dest="table_suffix")
  44. parser.add_option(
  45. "-i", "--noindexes", "--noindex",
  46. help="Do not emit index information",
  47. action="store_true", dest="noindex")
  48. parser.add_option(
  49. "-g", "--generic-types",
  50. help="Emit generic ANSI column types instead of database-specific.",
  51. action="store_true", dest="generictypes")
  52. parser.add_option(
  53. "--encoding",
  54. help="Encoding for output, default utf8",
  55. action="store", dest="encoding")
  56. parser.add_option(
  57. "-e", "--example",
  58. help="Generate code with examples how to access data",
  59. action="store_true", dest="example")
  60. parser.add_option(
  61. "-3", "--z3c",
  62. help="Generate code for use with z3c.sqlalchemy",
  63. action="store_true", dest="z3c")
  64. parser.add_option(
  65. "-d", "--declarative",
  66. help="Generate declarative SA code",
  67. action="store_true", dest="declarative")
  68. parser.add_option(
  69. "-n", "--interactive",
  70. help="Generate Interactive example in your code.",
  71. action="store_true", dest="interactive")
  72. parser.set_defaults(tables=[],
  73. encoding='utf-8',
  74. table_prefix='',
  75. table_suffix='')
  76. return parser
  77. def _prep_tables(option, opt_str, value, parser):
  78. if not value:
  79. parser.values.tables = []
  80. else:
  81. parser.values.tables = [x.strip()
  82. for x in value.split(',')
  83. if x.strip() != '']
  84. def _prep_schema(option, opt_str, value, parser):
  85. #handle multiple schemas on the command line
  86. value = [x.strip()
  87. for x in value.split(',')
  88. if x.strip() != '']
  89. if len(value) == 1:
  90. parser.values.schema = value[0]
  91. return
  92. parser.values.schema = value
  93. def _version_check(parser):
  94. try:
  95. import sqlalchemy
  96. except ImportError, ex:
  97. parser.error("SQLAlchemy version 0.4.0 or higher is required. (%s)" %
  98. (ex))
  99. version = getattr(sqlalchemy, '__version__', None)
  100. if version is None:
  101. parser.error("SQLAlchemy version 0.4.0 or higher is required.")
  102. elif version == 'svn':
  103. pass
  104. else:
  105. non_numeric = re.compile('[^0-9]*')
  106. version_info = tuple([int(i) for i in non_numeric.split(version)])
  107. if version_info < (0, 4):
  108. parser.error("SQLAlchemy version 0.4.0 or higher is required.")
  109. def _setup_engine(parser, url):
  110. global engine
  111. import sqlalchemy
  112. try:
  113. engine = sqlalchemy.create_engine(url)
  114. test = engine.connect()
  115. test.close()
  116. except sqlalchemy.exceptions.SQLAlchemyError, ex:
  117. parser.error('Could not connect to "%s": %s' % (url, ex))
  118. def _instrument():
  119. # monkeypatch SQLAlchemy __repr__ methods
  120. import formatter
  121. import loader
  122. def _set_output(path, overwrite=False):
  123. if os.path.exists(path) and not overwrite:
  124. print >>err, 'File "%s" exists and will be overwritten.' % path
  125. resp = raw_input('Overwrite (y/[n]): ')
  126. if not resp.strip().lower().startswith('y'):
  127. print >>err, "Aborted."
  128. sys.exit(-1)
  129. global out
  130. try:
  131. out = open(path, 'w')
  132. except IOError, e:
  133. print >>err, 'Could not open "%s" for writing: %s' % (path, e)
  134. sys.exit(-1)
  135. def configure(argv=sys.argv):
  136. global options, dburl
  137. parser = create_parser()
  138. options, args = parser.parse_args(argv)
  139. if len(args) < 2:
  140. parser.error("A database URL is required.")
  141. elif len(args) > 2:
  142. parser.error("Unknown arguments: %s" % (' '.join(args[2:])))
  143. else:
  144. dburl = args[1]
  145. _version_check(parser)
  146. _setup_engine(parser, dburl)
  147. _instrument()
  148. if options.output is not None:
  149. _set_output(options.output, options.force)