Source code for sanskrit.context

# -*- coding: utf-8 -*-
"""
    sanskrit.context
    ~~~~~~~~~~~~~~~~

    Manages the package context. For details, see
    :class:`~sanskrit.context.Context`.

    :license: MIT
"""
import imp
import os

from sqlalchemy import create_engine
from sqlalchemy.orm import scoped_session, sessionmaker

from .schema import Base, EnumBase, GenderGroup


[docs]class Context(object): """The package context. In addition to storing basic config information, such as the database URI or paths to various data files, a :class:`Context` also constructs a :class:`~sqlalchemy.orm.session.Session` class for connecting to the database. You can populate a context in several ways. For example, you can pass a :class:`dict`:: context = Context({'DATABASE_URI': 'sqlite:///data.sqlite'}) or a path to a Python module:: context = Context('project/config.py') If you initialize a context from a module, note that only uppercase variables will be stored in the context. This lets you use lowercase variables as temporary values. Config values are stored internally as a :class:`dict`, so you can always just use ordinary :class:`dict` methods:: context.config['FOO'] = 'baz' :param config: an object to read from. If this is a string, treat `config` as a module path and load values from that module. Otherwise, treat `config` as a dictionary. """ def __init__(self, config=None, connect=True): #: A :class:`dict` of various settings. By convention, all keys are #: uppercase. These are used to create :attr:`engine` and #: :attr:`session`. self.config = {} #: The :class:`~sqlalchemy.engine.Engine` that underlies #: the :attr:`session`. self.engine = None #: A :class:`~sqlalchemy.orm.session.Session` class. self.session = None if isinstance(config, basestring): filepath = config config = imp.new_module('config') config.__file__ = filepath try: execfile(filepath, config.__dict__) except IOError, e: e.strerror = 'Cannot load config file: %s' % e.strerror raise try: config = config or {} for key in config: if key.isupper(): self.config[key] = config[key] except TypeError: for key in dir(config): if key.isupper(): self.config[key] = getattr(config, key) def default(name, *args): path = os.path.join(self.config['DATA_PATH'], *args) self.config.setdefault(name, path) default('COMPOUNDED_NOMINAL_ENDINGS', 'nominal-endings-compounded.csv') default('ENUMS', 'enums.csv') default('GERUNDS', 'gerunds.csv') default('INDECLINABLES', 'indeclinables.csv') default('INFINITIVES', 'infinitives.csv') default('INFLECTED_NOMINAL_ENDINGS', 'nominal-endings-inflected.csv') default('IRREGULAR_ADJECTIVES', 'irregular-adjectives.csv') default('IRREGULAR_NOUNS', 'irregular-nouns.csv') default('MODIFIED_ROOTS', 'modified-roots.csv') default('NOMINAL_STEMS', 'nominal-stems.csv') default('PARTICIPLE_STEMS', 'participle-stems.csv') default('PREFIXED_ROOTS', 'prefixed-roots.csv') default('PREFIX_GROUPS', 'prefix-groups.csv') default('PRONOUNS', 'pronouns.csv') default('SANDHI_RULES', 'sandhi-rules.csv') default('UNPREFIXED_ROOTS', 'unprefixed-roots.csv') default('VERBAL_INDECLINABLES', 'verbal-indeclinables.csv') default('VERBS', 'verbs.csv') default('VERB_ENDINGS', 'verb-endings.csv') default('VERB_PREFIXES', 'verb-prefixes.csv') default('VERB_STEMS', 'verb-stems.csv') if connect and 'DATABASE_URI' in self.config: self.connect()
[docs] def build(self): """Build all data.""" from sanskrit import setup setup.run(self)
[docs] def connect(self): """Connect to the database.""" self.engine = create_engine(self.config['DATABASE_URI']) self.session = scoped_session(sessionmaker(autocommit=False, autoflush=False, bind=self.engine))
[docs] def create_all(self): """Create tables for every model in `sanskrit.schema`.""" metadata = Base.metadata extant = { t.name for t in metadata.tables.values() if t.exists(self.engine)} metadata.create_all(self.engine) for name in metadata.sorted_tables: if name not in extant: print ' [ c ] {0}'.format(name)
[docs] def drop_all(self): """Drop all tables defined in `sanskrit.schema`.""" Base.metadata.drop_all(self.engine)
def _build_enums(self): """Fetch and store enumerated data.""" self._enum_id = {} self._enum_abbr = {} self._gender_set = {} session = self.session for cls in EnumBase.__subclasses__(): key = cls.__tablename__ self._enum_id[key] = enum_id = {} self._enum_abbr[key] = enum_abbr = {} for item in session.query(cls).all(): enum_id[item.name] = enum_id[item.abbr] = item.id enum_abbr[item.id] = enum_abbr[item.name] = item.abbr for group in session.query(GenderGroup): member_ids = set([x.id for x in group.members]) self._gender_set[group.id] = member_ids session.remove() @property def enum_id(self): """Maps a name or abbreviation to an ID.""" try: return self._enum_id except AttributeError: self._build_enums() return self._enum_id @property def enum_abbr(self): """Maps an ID or name to an abbreviation.""" try: return self._enum_abbr except AttributeError: self._build_enums() return self._enum_abbr @property def gender_set(self): try: return self._gender_set except AttributeError: self._build_enums() return self._gender_set