Coverage for /var/srv/projects/api.amasfac.comuna18.com/tmp/venv/lib/python3.9/site-packages/factory/alchemy.py: 1%
59 statements
« prev ^ index » next coverage.py v6.4.4, created at 2023-07-17 14:22 -0600
« prev ^ index » next coverage.py v6.4.4, created at 2023-07-17 14:22 -0600
1# Copyright: See the LICENSE file.
3from sqlalchemy.exc import IntegrityError
4from sqlalchemy.orm.exc import NoResultFound
6from . import base, errors
8SESSION_PERSISTENCE_COMMIT = 'commit'
9SESSION_PERSISTENCE_FLUSH = 'flush'
10VALID_SESSION_PERSISTENCE_TYPES = [
11 None,
12 SESSION_PERSISTENCE_COMMIT,
13 SESSION_PERSISTENCE_FLUSH,
14]
17class SQLAlchemyOptions(base.FactoryOptions):
18 def _check_sqlalchemy_session_persistence(self, meta, value):
19 if value not in VALID_SESSION_PERSISTENCE_TYPES:
20 raise TypeError(
21 "%s.sqlalchemy_session_persistence must be one of %s, got %r" %
22 (meta, VALID_SESSION_PERSISTENCE_TYPES, value)
23 )
25 def _build_default_options(self):
26 return super()._build_default_options() + [
27 base.OptionDefault('sqlalchemy_get_or_create', (), inherit=True),
28 base.OptionDefault('sqlalchemy_session', None, inherit=True),
29 base.OptionDefault(
30 'sqlalchemy_session_persistence',
31 None,
32 inherit=True,
33 checker=self._check_sqlalchemy_session_persistence,
34 ),
35 ]
38class SQLAlchemyModelFactory(base.Factory):
39 """Factory for SQLAlchemy models. """
41 _options_class = SQLAlchemyOptions
43 class Meta:
44 abstract = True
46 @classmethod
47 def _generate(cls, strategy, params):
48 # Original params are used in _get_or_create if it cannot build an
49 # object initially due to an IntegrityError being raised
50 cls._original_params = params
51 return super()._generate(strategy, params)
53 @classmethod
54 def _get_or_create(cls, model_class, session, args, kwargs):
55 key_fields = {}
56 for field in cls._meta.sqlalchemy_get_or_create:
57 if field not in kwargs:
58 raise errors.FactoryError(
59 "sqlalchemy_get_or_create - "
60 "Unable to find initialization value for '%s' in factory %s" %
61 (field, cls.__name__))
62 key_fields[field] = kwargs.pop(field)
64 obj = session.query(model_class).filter_by(
65 *args, **key_fields).one_or_none()
67 if not obj:
68 try:
69 obj = cls._save(model_class, session, args, {**key_fields, **kwargs})
70 except IntegrityError as e:
71 session.rollback()
72 get_or_create_params = {
73 lookup: value
74 for lookup, value in cls._original_params.items()
75 if lookup in cls._meta.sqlalchemy_get_or_create
76 }
77 if get_or_create_params:
78 try:
79 obj = session.query(model_class).filter_by(
80 **get_or_create_params).one()
81 except NoResultFound:
82 # Original params are not a valid lookup and triggered a create(),
83 # that resulted in an IntegrityError.
84 raise e
85 else:
86 raise e
88 return obj
90 @classmethod
91 def _create(cls, model_class, *args, **kwargs):
92 """Create an instance of the model, and save it to the database."""
93 session = cls._meta.sqlalchemy_session
95 if session is None:
96 raise RuntimeError("No session provided.")
97 if cls._meta.sqlalchemy_get_or_create:
98 return cls._get_or_create(model_class, session, args, kwargs)
99 return cls._save(model_class, session, args, kwargs)
101 @classmethod
102 def _save(cls, model_class, session, args, kwargs):
103 session_persistence = cls._meta.sqlalchemy_session_persistence
105 obj = model_class(*args, **kwargs)
106 session.add(obj)
107 if session_persistence == SESSION_PERSISTENCE_FLUSH:
108 session.flush()
109 elif session_persistence == SESSION_PERSISTENCE_COMMIT:
110 session.commit()
111 return obj