예제 #1
0
파일: manage.py 프로젝트: ilyatoka/elite
def cli(ctx, debug):
    if ctx.obj is None:
        ctx.obj = {}
    ctx.obj['backend'] = PostgresqlBackend(parse_uri(settings.POSTGRES_DSN), migration_table="yoyo_migrations")
    if debug:
        loglevel = logging.DEBUG
    else:
        loglevel = logging.INFO
    logging.basicConfig(level=loglevel, format='%(message)s')
예제 #2
0
def _parse_uri(uri):
    """Patch original yoyo's parse_uri() function.

    This patch adds the client_flag CLIENT_MULTI_STATEMENTS for mysql backends
    powered by the pymysql driver. This is used to execute multiple queries in
    a single migration step instead of going through the hassle of breaking up
    some steps that don't make sense to break up in the first place.
    """
    result = parse_uri(uri)
    if result.scheme == "mysql":
        result.args["client_flag"] = CLIENT.MULTI_STATEMENTS
    return result
예제 #3
0
 def test_it_parses_all_fields(self):
     parsed = parse_uri("protocol://*****:*****@server:666/db?k=1")
     assert tuple(parsed) == (
         "protocol",
         "scott",
         "tiger",
         "server",
         666,
         "db",
         {
             "k": "1"
         },
     )
예제 #4
0
def test_connections(get_dbapi_module):

    from yoyo import backends

    u = parse_uri("odbc://*****:*****@db.example.org:42/northwind?foo=bar")
    cases = [
        (
            backends.ODBCBackend,
            "pyodbc",
            call("UID=scott;PWD=tiger;ServerName=db.example.org;"
                 "Port=42;Database=northwind;foo=bar"),
        ),
        (
            backends.MySQLBackend,
            "pymysql",
            call(
                user="******",
                passwd="tiger",
                host="db.example.org",
                port=42,
                db="northwind",
                foo="bar",
            ),
        ),
        (
            backends.SQLiteBackend,
            "sqlite3",
            call(
                "northwind",
                detect_types=get_dbapi_module("sqlite3").PARSE_DECLTYPES,
            ),
        ),
        (
            backends.PostgresqlBackend,
            "psycopg2",
            call(
                user="******",
                password="******",
                port=42,
                host="db.example.org",
                dbname="northwind",
                foo="bar",
            ),
        ),
    ]
    for cls, driver_module, connect_args in cases:
        cls(u, "_yoyo_migration")
        assert get_dbapi_module.call_args == call(driver_module)
        assert get_dbapi_module().connect.call_args == connect_args
예제 #5
0
파일: conftest.py 프로젝트: lekha/jeopardy
def _get_backend(uri, migration_table=default_migration_table):
    """Patch of yoyo's original get_backend() function.

    Original implementation is here:
    https://hg.sr.ht/~olly/yoyo/browse/yoyo/connections.py?rev=387b00ee5596b63cb93bf79fa3d4112576679bc0#L82

    Patching is needed for the same reason documented elsewhere in this
    codebase:
    https://github.com/lekha/jeopardy/commit/76e8b7ebd8abb0e2ad6ff7547ad74ae7b60d1690
    """
    if uri.startswith("mysql://"):
        parsed_uri = parse_uri(uri)
        parsed_uri.args["client_flag"] = CLIENT.MULTI_STATEMENTS
        backend = MySQLBackend(parsed_uri, migration_table)
    else:
        backend = get_backend(uri, migration_table)

    return backend
예제 #6
0
def get_backend(args, config):
    try:
        dburi = args.database
    except AttributeError:
        dburi = config.get("DEFAULT", "database")

    try:
        migration_table = args.migration_table
    except AttributeError:
        migration_table = config.get("DEFAULT", "migration_table")

    if dburi is None:
        raise InvalidArgument("Please specify a database uri")

    try:
        if args.prompt_password:
            password = getpass("Password for %s: " % dburi)
            parsed = connections.parse_uri(dburi)
            dburi = parsed._replace(password=password).uri
    except AttributeError:
        pass

    return connections.get_backend(dburi, migration_table)
예제 #7
0
 def test_it_returns_absolute_paths_for_sqlite(self):
     assert parse_uri("sqlite:////foo/bar.db").database == "/foo/bar.db"
예제 #8
0
 def test_it_requires_scheme(self):
     with pytest.raises(BadConnectionURI):
         parse_uri("//scott:tiger@localhost/db")
예제 #9
0
 def test_it_parses_escaped_username(self):
     parsed = parse_uri("protocol://scott%40example.org:tiger@localhost/db")
     assert parsed.username == "*****@*****.**"
예제 #10
0
def _test_parse_uri(connection_string, expected_uri_tuple):
    uri_tuple = parse_uri(connection_string)
    assert isinstance(uri_tuple, tuple)
    assert (uri_tuple == expected_uri_tuple)
예제 #11
0
def _test_parse_uri(connection_string, expected_uri_tuple):
    uri_tuple = parse_uri(connection_string)
    assert isinstance(uri_tuple, tuple)
    assert (uri_tuple == expected_uri_tuple)
예제 #12
0
def main(argv=None):

    argparser = make_argparser()
    args = argparser.parse_args(argv)

    if args.verbosity_level:
        verbosity_level = args.verbosity_level
    else:
        verbosity_level = args.verbose
    verbosity_level = min(verbosity_level, max(verbosity_levels))
    verbosity_level = max(verbosity_level, min(verbosity_levels))
    configure_logging(verbosity_level)

    command = args.command
    migrations_dir = os.path.normpath(os.path.abspath(args.migrations_dir))
    dburi = args.database

    config_path = os.path.join(migrations_dir, '.yoyo-migrate')
    config = readconfig(config_path)

    if dburi is None and args.cache:
        try:
            logger.debug("Looking up connection string for %r", migrations_dir)
            dburi = config.get('DEFAULT', 'dburi')
        except (ValueError, NoSectionError, NoOptionError):
            pass

    if args.migration_table:
        migration_table = args.migration_table
    else:
        try:
            migration_table = config.get('DEFAULT', 'migration_table')
        except (ValueError, NoSectionError, NoOptionError):
            migration_table = None

    # Earlier versions had a bug where the migration_table could be set to the
    # string 'None'.
    if migration_table in (None, 'None'):
        migration_table = default_migration_table

    config.set('DEFAULT', 'migration_table', migration_table)

    if dburi is None:
        argparser.error("Please specify command, migrations directory and "
                        "database connection string arguments")

    if args.prompt_password:
        password = getpass('Password for %s: ' % dburi)
        scheme, username, _, host, port, database, db_params = parse_uri(dburi)
        dburi = unparse_uri(
            (scheme, username, password, host, port, database, db_params))

    # Cache the database this migration set is applied to so that subsequent
    # runs don't need the dburi argument. Don't cache anything in batch mode -
    # we can't prompt to find the user's preference.
    if args.cache and not args.batch:
        if not config.has_option('DEFAULT', 'dburi'):
            response = prompt(
                "Save connection string to %s for future migrations?\n"
                "This is saved in plain text and "
                "contains your database password." % (config_path, ), "yn")
            if response == 'y':
                config.set('DEFAULT', 'dburi', dburi)

        elif config.get('DEFAULT', 'dburi') != dburi:
            response = prompt(
                "Specified connection string differs from that saved in %s. "
                "Update saved connection string?" % (config_path, ), "yn")
            if response == 'y':
                config.set('DEFAULT', 'dburi', dburi)

        config.set('DEFAULT', 'migration_table', migration_table)
        saveconfig(config, config_path)

    conn, paramstyle = connect(dburi)

    migrations = read_migrations(conn,
                                 paramstyle,
                                 migrations_dir,
                                 migration_table=migration_table)

    if args.match:
        migrations = migrations.filter(
            lambda m: re.search(args.match, m.id) is not None)

    if not args.all:
        if command in ['apply']:
            migrations = migrations.to_apply()

        elif command in ['reapply', 'rollback']:
            migrations = migrations.to_rollback()

    if not args.batch:
        migrations = prompt_migrations(conn, paramstyle, migrations, command)

    if not args.batch and migrations:
        if prompt(
                command.title() +
                plural(len(migrations), " %d migration", " %d migrations") +
                " to %s?" % dburi, "Yn") != 'y':
            return 0

    if command == 'reapply':
        migrations.rollback(args.force)
        migrations.apply(args.force)

    elif command == 'apply':
        migrations.apply(args.force)

    elif command == 'rollback':
        migrations.rollback(args.force)
예제 #13
0
def main(argv=None):

    argparser = make_argparser()
    args = argparser.parse_args(argv)

    if args.verbosity_level:
        verbosity_level = args.verbosity_level
    else:
        verbosity_level = args.verbose
    verbosity_level = min(verbosity_level, max(verbosity_levels))
    verbosity_level = max(verbosity_level, min(verbosity_levels))
    configure_logging(verbosity_level)

    command = args.command
    migrations_dir = os.path.normpath(os.path.abspath(args.migrations_dir))
    dburi = args.database

    config_path = os.path.join(migrations_dir, '.yoyo-migrate')
    config = readconfig(config_path)

    if dburi is None and args.cache:
        try:
            logger.debug("Looking up connection string for %r", migrations_dir)
            dburi = config.get('DEFAULT', 'dburi')
        except (ValueError, NoSectionError, NoOptionError):
            pass

    if args.migration_table:
        migration_table = args.migration_table
    else:
        try:
            migration_table = config.get('DEFAULT', 'migration_table')
        except (ValueError, NoSectionError, NoOptionError):
            migration_table = None

    # Earlier versions had a bug where the migration_table could be set to the
    # string 'None'.
    if migration_table in (None, 'None'):
        migration_table = default_migration_table

    config.set('DEFAULT', 'migration_table', migration_table)

    if dburi is None:
        argparser.error(
            "Please specify command, migrations directory and "
            "database connection string arguments"
        )

    if args.prompt_password:
        password = getpass('Password for %s: ' % dburi)
        scheme, username, _, host, port, database, db_params = parse_uri(dburi)
        dburi = unparse_uri((scheme, username, password, host, port, database, db_params))

    # Cache the database this migration set is applied to so that subsequent
    # runs don't need the dburi argument. Don't cache anything in batch mode -
    # we can't prompt to find the user's preference.
    if args.cache and not args.batch:
        if not config.has_option('DEFAULT', 'dburi'):
            response = prompt(
                "Save connection string to %s for future migrations?\n"
                "This is saved in plain text and "
                "contains your database password." % (config_path,),
                "yn"
            )
            if response == 'y':
                config.set('DEFAULT', 'dburi', dburi)

        elif config.get('DEFAULT', 'dburi') != dburi:
            response = prompt(
                "Specified connection string differs from that saved in %s. "
                "Update saved connection string?" % (config_path,),
                "yn"
            )
            if response == 'y':
                config.set('DEFAULT', 'dburi', dburi)

        config.set('DEFAULT', 'migration_table', migration_table)
        saveconfig(config, config_path)

    conn, paramstyle = connect(dburi)

    migrations = read_migrations(conn, paramstyle, migrations_dir,
                                 migration_table=migration_table)

    if args.match:
        migrations = migrations.filter(
            lambda m: re.search(args.match, m.id) is not None)

    if not args.all:
        if command in ['apply']:
            migrations = migrations.to_apply()

        elif command in ['reapply', 'rollback']:
            migrations = migrations.to_rollback()

    if not args.batch:
        migrations = prompt_migrations(conn, paramstyle, migrations, command)

    if not args.batch and migrations:
        if prompt(command.title() +
                  plural(len(migrations), " %d migration", " %d migrations") +
                  " to %s?" % dburi, "Yn") != 'y':
            return 0

    if command == 'reapply':
        migrations.rollback(args.force)
        migrations.apply(args.force)

    elif command == 'apply':
        migrations.apply(args.force)

    elif command == 'rollback':
        migrations.rollback(args.force)