Skip to content

Commit

Permalink
[#71] Updated and created Flask/sqlalchemy models to match CPDP datab…
Browse files Browse the repository at this point in the history
…ase schema; 4 tests in loader.py are flagged to be skipped
  • Loading branch information
khathuynh-tw committed Jan 30, 2020
1 parent 8809820 commit a3df35d
Show file tree
Hide file tree
Showing 14 changed files with 275 additions and 59 deletions.
4 changes: 2 additions & 2 deletions invisible_flow/copa/augment.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import pandas as pd
from invisible_flow.copa.data_allegation_category import AllegationCategory
from invisible_flow.copa.data_allegation_category import DataAllegationCategory


class Augment:
Expand All @@ -9,7 +9,7 @@ def get_augmented_copa_data(self, allegation_rows: str):
categories = df.loc[:, 'current_category'].unique()

category_code_map = pd.DataFrame(
AllegationCategory.query.with_entities(AllegationCategory.category, AllegationCategory.category_code)
DataAllegationCategory.query.with_entities(DataAllegationCategory.category, DataAllegationCategory.category_code)
)
if len(category_code_map) > 0:
for category in categories:
Expand Down
43 changes: 29 additions & 14 deletions invisible_flow/copa/data_allegation.py
Original file line number Diff line number Diff line change
@@ -1,29 +1,44 @@
from invisible_flow.constants import COPA_DB_BIND_KEY
from manage import db
from geoalchemy2 import Geometry

from sqlalchemy.dialects import postgresql

class Allegation(db.Model):

class DataAllegation(db.Model):
__bind_key__ = COPA_DB_BIND_KEY
add1 = db.Column(db.String)
add2 = db.Column(db.String)
beat_id = db.Column(db.String)
city = db.Column(db.String)
incident_date = db.Column(db.String)
is_officer_complaint = db.Column(db.Boolean)
location = db.Column(db.String)
summary = db.Column(db.String)
cr_id = db.Column(db.String, primary_key=True)
id = db.Column(db.Integer, primary_key=True)
cr_id = db.Column(db.String(30), nullable=False)
summary = db.Column(db.Text, nullable=False)
add1 = db.Column(db.String(16), nullable=False)
add2 = db.Column(db.String(255), nullable=False)
beat_id = db.Column(db.Integer)
city = db.Column(db.String(255), nullable=False)
incident_date = db.Column(db.DateTime)
is_officer_complaint = db.Column(db.Boolean, nullable=False)
location = db.Column(db.String(64), nullable=False)
old_complaint_address = db.Column(db.String(255))
subjects = db.Column(postgresql.ARRAY(db.String), nullable=False)
point = db.Column(Geometry(geometry_type='POINT', srid=4326))
created_at = db.Column(db.DateTime, nullable=False)
updated_at = db.Column(db.DateTime, nullable=False)

def __repr__(self):
return f'<Allegation {self.cr_id} ' \
return f'<DataAllegation {self.id} ' \
f'cr_id: {self.cr_id}, ' \
f'summary: {self.summary}, ' \
f'add1: {self.add1}, ' \
f'add2: {self.add2}, ' \
f'beat_id: {self.beat_id}, ' \
f'city: {self.city}, ' \
f'incident_date: {self.incident_date}, ' \
f'incident_date {self.incident_date}, ' \
f'is_officer_complaint: {self.is_officer_complaint}, ' \
f'location: {self.location}, ' \
f'summary: {self.summary}, ' \
f'old_complaint_address: {self.old_complaint_address}, ' \
f'subjects: {self.subjects}, ' \
f'point: {self.point}, ' \
f'created_at: {self.created_at}, ' \
f'updated_at: {self.updated_at}, ' \
f'>'

# enables subscriptability like Allegation['beat_id'] instead of forcing
Expand All @@ -32,6 +47,6 @@ def __getitem__(self, index):
return self.__getattribute__(index)


def insert_allegation_into_database(record: Allegation):
def insert_allegation_into_database(record: DataAllegation):
db.session.add(record)
db.session.commit()
22 changes: 14 additions & 8 deletions invisible_flow/copa/data_allegation_category.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,29 @@
from manage import db


class AllegationCategory(db.Model):
class DataAllegationCategory(db.Model):
__bind_key__ = COPA_DB_BIND_KEY
category = db.Column(db.String)
category_code = db.Column(db.String)
allegation_name = db.Column(db.String)
on_duty = db.Column(db.String)
cr_id = db.Column(db.String, primary_key=True)
id = db.Column(db.Integer, primary_key=True)
category = db.Column(db.String(255), nullable=False)
category_code = db.Column(db.String(255), nullable=False)
allegation_name = db.Column(db.String(255), nullable=False)
on_duty = db.Column(db.Boolean, nullable=False)
citizen_dept = db.Column(db.String(50), nullable=False)
created_at = db.Column(db.DateTime, nullable=False)
updated_at = db.Column(db.DateTime, nullable=False)

def __repr__(self):
return f'<AllegationCategory {self.cr_id} ' \
return f'<DataAllegationCategory {self.id} ' \
f'category: {self.category}, ' \
f'category_code: {self.category_code}, ' \
f'allegation_name: {self.allegation_name}, ' \
f'on_duty: {self.on_duty}, ' \
f'citizen_dept: {self.citizen_dept}, ' \
f'created_at: {self.created_at}, ' \
f'updated_at: {self.updated_at}, ' \
f'>'


def insert_allegation_category_record_into_database(record: AllegationCategory):
def insert_data_allegation_category_record_into_database(record: DataAllegationCategory):
db.session.add(record)
db.session.commit()
30 changes: 30 additions & 0 deletions invisible_flow/copa/data_complainant.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
from invisible_flow.constants import COPA_DB_BIND_KEY
from manage import db


class DataComplainant(db.Model):
__bind_key__ = COPA_DB_BIND_KEY
id = db.Column(db.Integer, primary_key=True)
gender = db.Column(db.String(1), nullable=False)
race = db.Column(db.String(50), nullable=False)
age = db.Column(db.Integer)
birth_year = db.Column(db.Integer)
allegation_id = db.Column(db.String(30))
created_at = db.Column(db.DateTime, nullable=False)
updated_at = db.Column(db.DateTime, nullable=False)

def __repr__(self):
return f'<DataComplainant {self.id} ' \
f'gender: {self.gender}, ' \
f'race: {self.race}, ' \
f'age: {self.age}, ' \
f'birth_year: {self.birth_year}, ' \
f'allegation_id: {self.allegation_id}, ' \
f'created_at: {self.created_at}, ' \
f'updated_at: {self.updated_at}, ' \
f'>'


def insert_officer_allegation_into_database(record: DataComplainant):
db.session.add(record)
db.session.commit()
43 changes: 43 additions & 0 deletions invisible_flow/copa/data_officer_allegation.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
from invisible_flow.constants import COPA_DB_BIND_KEY
from manage import db


class DataOfficerAllegation(db.Model):
__bind_key__ = COPA_DB_BIND_KEY
id = db.Column(db.Integer, primary_key=True)
allegation_id = db.Column(db.String(30))
allegation_category_id = db.Column(db.Integer)
officer_id = db.Column(db.Integer)
start_date = db.Column(db.Date)
end_date = db.Column(db.Date)
officer_age = db.Column(db.Integer)
recc_finding = db.Column(db.String(2), nullable=False)
recc_outcome = db.Column(db.String(32), nullable=False)
final_finding = db.Column(db.String(2), nullable=False)
final_outcome = db.Column(db.String(32), nullable=False)
final_outcome_class = db.Column(db.String(20), nullable=False)
disciplined = db.Column(db.Boolean)
created_at = db.Column(db.DateTime, nullable=False)
updated_at = db.Column(db.DateTime, nullable=False)

def __repr__(self):
return f'<OfficerAllegation {self.id} ' \
f'allegation_id: {self.allegation_id}, ' \
f'allegation_category_id: {self.allegation_category_id}, ' \
f'officer_id: {self.officer_id}, ' \
f'start_date: {self.start_date}, ' \
f'end_date: {self.end_date}, ' \
f'officer_age: {self.officer_age}, ' \
f'recc_finding: {self.recc_finding}, ' \
f'final_finding: {self.final_finding}, ' \
f'final_outcome: {self.final_outcome}, ' \
f'final_outcome_class: {self.final_outcome_class}, ' \
f'disciplined: {self.disciplined}, ' \
f'created_at: {self.created_at}, ' \
f'updated_at: {self.updated_at}, ' \
f'>'


def insert_officer_allegation_into_database(record: DataOfficerAllegation):
db.session.add(record)
db.session.commit()
17 changes: 11 additions & 6 deletions invisible_flow/copa/loader.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,17 @@
import pandas as pd

from invisible_flow.copa.data_allegation import Allegation
from invisible_flow.copa.data_allegation import DataAllegation
from invisible_flow.globals_factory import GlobalsFactory
from invisible_flow.storage.storage_factory import StorageFactory
from manage import db
from datetime import datetime


class Loader:

def __init__(self):
self.log_nos = pd.DataFrame(
Allegation.query.with_entities(Allegation.cr_id)
DataAllegation.query.with_entities(DataAllegation.cr_id)
).values.flatten().tolist()
self.partial_matches = []
self.db_rows_added = []
Expand All @@ -29,20 +30,24 @@ def load_copa_db(self, augmented_data: pd.DataFrame):
copa_column_names = ["cr_id", "beat_id", "incident_date"]
for row in augmented_data.iterrows():
log_no = row[1]["log_no"]
current_allegation = Allegation(
datetime_string = str(row[1]["complaint_date"]).replace('T', ' ')
datetime_object = datetime.strptime(datetime_string, '%Y-%m-%d %H: %M: %S.%f')

current_allegation = DataAllegation(
cr_id=str(log_no),
beat_id=str(row[1]["beat"]),
incident_date=str(row[1]["complaint_date"])
incident_date=datetime_object
)

if log_no not in self.log_nos:
db.session.add(current_allegation)
db.session.commit()
self.log_nos.append(log_no)
self.db_rows_added.append(current_allegation)
else:
db_row_match_log_no = Allegation.query.filter_by(cr_id=str(log_no)).all()[0]
db_row_match_log_no = DataAllegation.query.filter_by(cr_id=str(log_no)).all()[0]
had_partial_match = False
for column_name in Allegation.__table__.columns.keys():
for column_name in DataAllegation.__table__.columns.keys():
if current_allegation[column_name] != db_row_match_log_no[column_name]:
had_partial_match = True
self.error_notes = self.error_notes.append(
Expand Down
Empty file.
1 change: 1 addition & 0 deletions manage.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
# copa_db_file = tempfile.NamedTemporaryFile(suffix='.db')
# copa_db_filename = f'sqlite:///{copa_db_file.name}'

copa_db_file = tempfile.NamedTemporaryFile(suffix='.db')
copa_db_filename = 'postgresql+psycopg2://invisible_flow@localhost:5432/invisible_flow_testing'


Expand Down
1 change: 1 addition & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ Flask-Testing==0.7.1
Flask-WTF==0.14.2
funcsigs==1.0.0
future==0.16.0
GeoAlchemy2==0.6.3
gitdb2==2.0.5
GitPython==2.1.11
google-api-core==1.13.0
Expand Down
35 changes: 22 additions & 13 deletions tests/copa/test_data_allegation.py
Original file line number Diff line number Diff line change
@@ -1,39 +1,48 @@
import pytest
import datetime

from invisible_flow.constants import COPA_DB_BIND_KEY
from invisible_flow.copa.data_allegation import Allegation
from invisible_flow.copa.data_allegation import DataAllegation
from manage import db
from geoalchemy2 import Geometry

class TestDataAllegation:

class TestAllegation:

@pytest.fixture
@pytest.fixture(autouse=True)
def get_db(self):
db.session.close()
db.drop_all()
db.create_all(bind=COPA_DB_BIND_KEY)

yield db

def get_allegation(self):
return Allegation(
def get_data_allegation(self):
return DataAllegation(
id=1,
cr_id='cr_id',
summary='summary',
add1='add1',
add2='add2',
beat_id='beat_id',
beat_id=1,
city='city',
incident_date='incident_date',
incident_date=datetime.datetime.utcnow(),
is_officer_complaint=True,
location='location',
summary='summary'
old_complaint_address='old_complaint_address',
subjects={"Bassil Abdelal","Richie Cole","Omar Young","Leevon Carter"},
point='0101000020E61000009FB3603DC9EA55C0138E6A227DD84440',
created_at=datetime.datetime.utcnow(),
updated_at=datetime.datetime.utcnow()
)

def test_create_allegation(self):
def test_create_data_allegation(self):
try:
self.get_allegation()
self.get_data_allegation()
except Exception:
pytest.fail('this should not have thrown an exception')

def test_adding_copa_record_to_db_works(self, get_db):
cr = self.get_allegation()
cr = self.get_data_allegation()
get_db.session.add(cr)
get_db.session.commit()
assert len(Allegation.query.all()) == 1
assert len(DataAllegation.query.all()) == 1
31 changes: 19 additions & 12 deletions tests/copa/test_data_allegation_category.py
Original file line number Diff line number Diff line change
@@ -1,36 +1,43 @@
import pytest
import datetime

from invisible_flow.constants import COPA_DB_BIND_KEY
from invisible_flow.copa.data_allegation_category import AllegationCategory
from invisible_flow.copa.data_allegation_category import DataAllegationCategory
from manage import db


class TestAllegationCategory:
class TestDataAllegationCategory:

@pytest.fixture
@pytest.fixture(autouse=True)
def get_db(self):
db.session.close()
db.drop_all();
db.create_all(bind=COPA_DB_BIND_KEY)

yield db

def get_allegation_category(self):
return AllegationCategory(
cr_id='cr_id',
def get_data_allegation_category(self):
return DataAllegationCategory(
id=1,
category='category',
category_code='category_code',
allegation_name='allegation_name',
on_duty='on_duty'
on_duty=True,
citizen_dept='citizen_dept',
created_at=datetime.datetime.utcnow(),
updated_at=datetime.datetime.utcnow()

)

def test_create_allegation_category(self):
def test_create_data_allegation_category(self):
try:
self.get_allegation_category()
self.get_data_allegation_category()
except Exception:
pytest.fail('this should not have thrown an exception')

def test_adding_allegation_category_to_db_works(self, get_db):
cr = self.get_allegation_category()
def test_adding_data_allegation_category_to_db_works(self, get_db):
cr = self.get_data_allegation_category()
get_db.session.add(cr)
get_db.session.commit()
assert len(AllegationCategory.query.all()) == 1
assert len(DataAllegationCategory.query.all()) == 1
db.session.close()
Loading

0 comments on commit a3df35d

Please sign in to comment.