Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/schettino72/sqla_yaml_fixtures

Load YAML data fixtures for SQLAlchemy
https://github.com/schettino72/sqla_yaml_fixtures

database fixtures python sql sqlalchemy yaml

Last synced: about 1 month ago
JSON representation

Load YAML data fixtures for SQLAlchemy

Awesome Lists containing this project

README

        

sqla\_yaml\_fixtures
====================

Load YAML data fixtures for SQLAlchemy

.. image:: https://img.shields.io/pypi/v/sqla_yaml_fixtures.svg
:target: https://pypi.python.org/pypi/sqla_yaml_fixtures

.. image:: https://img.shields.io/pypi/l/sqla_yaml_fixtures.svg
:target: https://pypi.python.org/pypi/sqla_yaml_fixtures

.. image:: https://img.shields.io/pypi/pyversions/sqla_yaml_fixtures.svg
:target: https://pypi.python.org/pypi/sqla_yaml_fixtures

.. image:: https://github.com/schettino72/sqla_yaml_fixtures/workflows/test/badge.svg
:target: https://github.com/schettino72/sqla_yaml_fixtures/actions?query=workflow%3Atest

.. image:: https://ko-fi.com/img/githubbutton_sm.svg
:target: https://ko-fi.com/A0A23ZL4A

This package allows you to define some data in YAML and load them into a
DB. The yaml data should correspond to SQLAlchemy declarative mappers.

Example:

.. code:: yaml

- User:
- __key__: joey
username: joey
email: [email protected]
profile:
name: Jeffrey

- __key__: dee
username: deedee
email: [email protected]

- Profile:
- user: dee
name: Douglas

- Group:
- name: Ramones
members: [joey.profile, dee.profile]

- The root of YAML contains a *sequence* of ``mapper names`` e.g. ``- User``, ``- Profile`` etc
- The order of these names should follow relationship dependencies
- Every name should contain a *sequence* of instances
- Each instance is a *mapping* of *attribute* -> *value*
- the attributes are taken from the mapper ``__init__()`` (usually an
attributes maps to a column)
- The special field ``__key__`` can be used to identify this instnace
in a relationship reference e.g. The ``Profile.user``
- Note that any ``__key__`` MUST be globally **unique**
- In a *to-one* relationship the data can be directly nested in the
parent data definition
- References can access attributes using a *dot* notation, e.g.
``joey.profile``
- *to-many* relationships can be added as a list of references

The mapper definition for this example is in the `test file`_.

Installation
------------

``pip install sqla-yaml-fixtures``

API
---

This module expose a single function
``load(ModelBase, session, fixture_text, loader=None)``

Where:

- ``ModelBase`` is SQLAlchemy declarative base
- ``session`` is SQLAlchemy session
- ``fixture_text`` is a string containg the YAML fixtures

.. code:: python

from sqlalchemy import create_engine
from sqlalchemy import Column, Integer, String
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import Session

import sqla_yaml_fixtures

BaseModel = declarative_base()

class User(BaseModel):
__tablename__ = 'user'
id = Column(Integer, primary_key=True)
username = Column(String(150), nullable=False, unique=True)
email = Column(String(254), unique=True)

def main():
engine = create_engine('sqlite://')
BaseModel.metadata.create_all(engine)
connection = engine.connect()
session = Session(bind=connection)

fixture = """
- User:
- username: deedee
email: [email protected]
- username: joey
email: [email protected]
"""
sqla_yaml_fixtures.load(BaseModel, session, fixture)

print('\n'.join(u.username for u in session.query(User).all()))

if __name__ == '__main__':
main()

Note: the `load()` function performs a `session.commit()`.

`load()` returns an instance of `Store`. Using this object `get()` method you can passing a `key` as argument you get a reference to the object added into the database. This is useful to easily get attributes that are generated by the database.

.. code:: python

store = sqla_yaml_fixtures.load(BaseModel, session, fixture)
my_obj = store.get('dee')
print('Created object id: {}'.format(my_obj.id))

.. warning::

By default YAML is loaded using `yaml.FullLoader`, this is insecure when
loading unstrusted input. It is possible to overwrite the loaded by setting
`loader` param in the `load()` function.

Command Line
------------

For basic usage there is also command line. Example::

$ python -m sqla_yaml_fixtures --db-url sqlite:///dev.db --db-base mypkg.models:Base --reset-db --alembic-stamp fixture.yaml

All available options::

$ python -m sqla_yaml_fixtures --help
usage: sqla_yaml_fixtures [-h] --db-base DB_BASE --db-url DB_URL [--yes]
[--reset-db] [--alembic-stamp] [--jinja2]
FILE [FILE ...]

load fixtures from yaml file into DB

positional arguments:
FILE YAML file with DB fixtures

optional arguments:
-h, --help show this help message and exit
--db-base DB_BASE SQLAlchemy Base class with schema metadata in the format
my_package.my_module:MyClass
--db-url DB_URL Database URL in the format
dialect+driver://username:password@host:port/database
--yes Do NOT ask for confirmation before applying fixtures
--reset-db Drop DB schema and data and re-create schema before
loading fixtures
--alembic-stamp Perform `alembic stamp head`
--jinja2 load fixture files as jinja2 templates

.. _test file: https://github.com/schettino72/sqla_yaml_fixtures/blob/master/tests/test_sqla_yaml_fixtures.py