Skip to content

Commit

Permalink
Merge pull request #117 from hover2pi/anomoly_db
Browse files Browse the repository at this point in the history
`jwqldb` interface
  • Loading branch information
bourque authored Aug 23, 2018
2 parents 384af98 + 9f7ad27 commit 9799304
Show file tree
Hide file tree
Showing 6 changed files with 537 additions and 0 deletions.
7 changes: 7 additions & 0 deletions docs/source/database.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
********
database
********

.. automodule:: jwql.database.database_interface
:members:
:undoc-members:
1 change: 1 addition & 0 deletions docs/source/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ API documentation
:maxdepth: 1
:caption: Contents:

database.rst
logging.rst
monitor_filesystem.rst
monitor_mast.rst
Expand Down
1 change: 1 addition & 0 deletions environment.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ dependencies:
- numpy=1.14.0
- numpydoc=0.8.0
- postgresql=9.6.6
- psycopg2=2.7.5
- python=3.6.4
- python-dateutil=2.6.1
- pytest=3.4.2
Expand Down
Empty file added jwql/database/__init__.py
Empty file.
158 changes: 158 additions & 0 deletions jwql/database/database_interface.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
"""
A module to interact with the JWQL postgresql database ``jwqldb``
The ``load_connection()`` function within this module allows the user
to connect to the ``jwqldb`` database via the ``session``, ``base``,
and ``engine`` objects (described below). The classes within serve as
ORMs (Object-relational mappings) that define the individual tables of
the relational database.
The ``engine`` object serves as the low-level database API and perhaps
most importantly contains dialects which allows the ``sqlalchemy``
module to communicate with the database.
The ``base`` object serves as a base class for class definitions. It
produces ``Table`` objects and constructs ORMs.
The ``session`` object manages operations on ORM-mapped objects, as
construced by the base. These operations include querying, for
example.
Authors
-------
Joe Filippazzo, Johannes Sahlmann, Matthew Bourque
"""

from datetime import datetime

import pandas as pd
from sqlalchemy import Boolean
from sqlalchemy import Column
from sqlalchemy import create_engine
from sqlalchemy import DateTime
from sqlalchemy import Integer
from sqlalchemy import MetaData
from sqlalchemy import String
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker
from sqlalchemy.orm.query import Query

from ..utils import utils


SETTINGS = utils.get_config()


# Monkey patch Query with data_frame method
@property
def data_frame(self):
"""Method to return a pandas.DataFrame of the results"""
return pd.read_sql(self.statement, self.session.bind)


Query.data_frame = data_frame


def load_connection(connection_string):
"""Return ``session``, ``base``, ``engine``, and ``metadata``
objects for connecting to the ``jwqldb`` database.
Create an ``engine`` using an given ``connection_string``. Create
a ``base`` class and ``session`` class from the ``engine``. Create
an instance of the ``session`` class. Return the ``session``,
``base``, and ``engine`` instances. This was stolen from the
`ascql` repository.
Parameters
----------
connection_string : str
A postgresql database connection string. The
connection string should take the form:
``dialect+driver://username:password@host:port/database``
Returns
-------
session : sesson object
Provides a holding zone for all objects loaded or associated
with the database.
base : base object
Provides a base class for declarative class definitions.
engine : engine object
Provides a source of database connectivity and behavior.
meta: metadata object
The connection metadata
References
----------
``ascql``:
https://github.com/spacetelescope/acsql/blob/master/acsql/database/database_interface.py
"""
engine = create_engine(connection_string, echo=False)
base = declarative_base(engine)
Session = sessionmaker(bind=engine)
session = Session()
meta = MetaData()

return session, base, engine, meta


session, base, engine, meta = load_connection(SETTINGS['connection_string'])


class Anomaly(base):
"""ORM for the anomalies table"""
# Name the table
__tablename__ = 'anomalies'

# Define the columns
id = Column(Integer, primary_key=True, nullable=False)
filename = Column(String, nullable=False)
flag_date = Column(DateTime, nullable=False, default=datetime.now())
bowtie = Column(Boolean, nullable=False, default=False)
snowball = Column(Boolean, nullable=False, default=False)
cosmic_ray_shower = Column(Boolean, nullable=False, default=False)
crosstalk = Column(Boolean, nullable=False, default=False)
cte_correction_error = Column(Boolean, nullable=False, default=False)
data_transfer_error = Column(Boolean, nullable=False, default=False)
detector_ghost = Column(Boolean, nullable=False, default=False)
diamond = Column(Boolean, nullable=False, default=False)
diffraction_spike = Column(Boolean, nullable=False, default=False)
dragon_breath = Column(Boolean, nullable=False, default=False)
earth_limb = Column(Boolean, nullable=False, default=False)
excessive_saturation = Column(Boolean, nullable=False, default=False)
figure8_ghost = Column(Boolean, nullable=False, default=False)
filter_ghost = Column(Boolean, nullable=False, default=False)
fringing = Column(Boolean, nullable=False, default=False)
guidestar_failure = Column(Boolean, nullable=False, default=False)
banding = Column(Boolean, nullable=False, default=False)
persistence = Column(Boolean, nullable=False, default=False)
prominent_blobs = Column(Boolean, nullable=False, default=False)
trail = Column(Boolean, nullable=False, default=False)
scattered_light = Column(Boolean, nullable=False, default=False)
other = Column(Boolean, nullable=False, default=False)

def __repr__(self):
"""Return the canonical string representation of the object"""
# Get the columns that are True
a_list = [col for col, val in self.__dict__.items()
if val is True and isinstance(val, bool)]

txt = ('Anomaly {0.id}: {0.filename} flagged at '
'{0.flag_date} for {1}').format(self, a_list)

return txt

@property
def colnames(self):
"""A list of all the column names in this table"""
# Get the columns
a_list = [col for col, val in self.__dict__.items()
if isinstance(val, bool)]

return a_list


if __name__ == '__main__':

base.metadata.create_all(engine)
Loading

0 comments on commit 9799304

Please sign in to comment.