| 1 | #!/usr/bin/env python |
|---|
| 2 | # -*- coding: utf-8 -*- |
|---|
| 3 | |
|---|
| 4 | import warnings |
|---|
| 5 | from decorator import decorator |
|---|
| 6 | from pkg_resources import EntryPoint |
|---|
| 7 | |
|---|
| 8 | from sqlalchemy import create_engine |
|---|
| 9 | |
|---|
| 10 | from migrate.versioning import exceptions |
|---|
| 11 | from migrate.versioning.util.keyedinstance import KeyedInstance |
|---|
| 12 | from migrate.versioning.util.importpath import import_path |
|---|
| 13 | |
|---|
| 14 | |
|---|
| 15 | def load_model(dotted_name): |
|---|
| 16 | """Import module and use module-level variable". |
|---|
| 17 | |
|---|
| 18 | :param dotted_name: path to model in form of string: ``some.python.module:Class`` |
|---|
| 19 | |
|---|
| 20 | .. versionchanged:: 0.5.4 |
|---|
| 21 | |
|---|
| 22 | """ |
|---|
| 23 | if isinstance(dotted_name, basestring): |
|---|
| 24 | if ':' not in dotted_name: |
|---|
| 25 | # backwards compatibility |
|---|
| 26 | warnings.warn('model should be in form of module.model:User ' |
|---|
| 27 | 'and not module.model.User', DeprecationWarning) |
|---|
| 28 | dotted_name = ':'.join(dotted_name.rsplit('.', 1)) |
|---|
| 29 | return EntryPoint.parse('x=%s' % dotted_name).load(False) |
|---|
| 30 | else: |
|---|
| 31 | # Assume it's already loaded. |
|---|
| 32 | return dotted_name |
|---|
| 33 | |
|---|
| 34 | def asbool(obj): |
|---|
| 35 | """Do everything to use object as bool""" |
|---|
| 36 | if isinstance(obj, (str, unicode)): |
|---|
| 37 | obj = obj.strip().lower() |
|---|
| 38 | if obj in ['true', 'yes', 'on', 'y', 't', '1']: |
|---|
| 39 | return True |
|---|
| 40 | elif obj in ['false', 'no', 'off', 'n', 'f', '0']: |
|---|
| 41 | return False |
|---|
| 42 | else: |
|---|
| 43 | raise ValueError("String is not true/false: %r" % obj) |
|---|
| 44 | if obj in (True, False): |
|---|
| 45 | return bool(obj) |
|---|
| 46 | else: |
|---|
| 47 | raise ValueError("String is not true/false: %r" % obj) |
|---|
| 48 | |
|---|
| 49 | def guess_obj_type(obj): |
|---|
| 50 | """Do everything to guess object type from string |
|---|
| 51 | |
|---|
| 52 | Tries to convert to `int`, `bool` and finally returns if not succeded. |
|---|
| 53 | |
|---|
| 54 | .. versionadded: 0.5.4 |
|---|
| 55 | """ |
|---|
| 56 | |
|---|
| 57 | result = None |
|---|
| 58 | |
|---|
| 59 | try: |
|---|
| 60 | result = int(obj) |
|---|
| 61 | except: |
|---|
| 62 | pass |
|---|
| 63 | |
|---|
| 64 | if result is None: |
|---|
| 65 | try: |
|---|
| 66 | result = asbool(obj) |
|---|
| 67 | except: |
|---|
| 68 | pass |
|---|
| 69 | |
|---|
| 70 | if result is not None: |
|---|
| 71 | return result |
|---|
| 72 | else: |
|---|
| 73 | return obj |
|---|
| 74 | |
|---|
| 75 | @decorator |
|---|
| 76 | def catch_known_errors(f, *a, **kw): |
|---|
| 77 | """Decorator that catches known api errors |
|---|
| 78 | |
|---|
| 79 | .. versionadded: 0.5.4 |
|---|
| 80 | """ |
|---|
| 81 | |
|---|
| 82 | try: |
|---|
| 83 | f(*a, **kw) |
|---|
| 84 | except exceptions.PathFoundError, e: |
|---|
| 85 | raise exceptions.KnownError("The path %s already exists" % e.args[0]) |
|---|
| 86 | |
|---|
| 87 | def construct_engine(url, **opts): |
|---|
| 88 | """.. versionadded:: 0.5.4 |
|---|
| 89 | |
|---|
| 90 | Constructs and returns SQLAlchemy engine. |
|---|
| 91 | |
|---|
| 92 | Currently, there are 2 ways to pass create_engine options to :mod:`migrate.versioning.api` functions: |
|---|
| 93 | |
|---|
| 94 | :param engine_dict: python dictionary of options to pass to `create_engine` |
|---|
| 95 | :param engine_arg_*: keyword parameters to pass to `create_engine` (evaluated with :func:`migrate.versioning.util.guess_obj_type`) |
|---|
| 96 | |
|---|
| 97 | .. note:: |
|---|
| 98 | |
|---|
| 99 | keyword parameters override ``engine_dict`` values. |
|---|
| 100 | |
|---|
| 101 | """ |
|---|
| 102 | |
|---|
| 103 | # get options for create_engine |
|---|
| 104 | if opts.get('engine_dict') and isinstance(opts['engine_dict'], dict): |
|---|
| 105 | kwargs = opts['engine_dict'] |
|---|
| 106 | else: |
|---|
| 107 | kwargs = dict() |
|---|
| 108 | |
|---|
| 109 | # DEPRECATED: handle echo the old way |
|---|
| 110 | echo = asbool(opts.get('echo', False)) |
|---|
| 111 | if echo: |
|---|
| 112 | warnings.warn('echo=True parameter is deprecated, pass ' |
|---|
| 113 | 'engine_arg_echo=True or engine_dict={"echo": True}', |
|---|
| 114 | DeprecationWarning) |
|---|
| 115 | kwargs['echo'] = echo |
|---|
| 116 | |
|---|
| 117 | # parse keyword arguments |
|---|
| 118 | for key, value in opts.iteritems(): |
|---|
| 119 | if key.startswith('engine_arg_'): |
|---|
| 120 | kwargs[key[11:]] = guess_obj_type(value) |
|---|
| 121 | |
|---|
| 122 | return create_engine(url, **kwargs) |
|---|