Skip to content

Commit

Permalink
I think it works, just need access to the couchdb
Browse files Browse the repository at this point in the history
  • Loading branch information
PlethoraChutney committed Feb 18, 2023
1 parent 438bc51 commit 4bf8233
Show file tree
Hide file tree
Showing 9 changed files with 126 additions and 152 deletions.
5 changes: 2 additions & 3 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

setuptools.setup(
name = 'appia',
version = '7.1.2',
version = '7.2.0',
author = 'Rich Posert',
author_email = '[email protected]',
description = 'Chromatography processing made easy',
Expand All @@ -16,14 +16,13 @@
'License :: OSI Approved :: MIT License'
],
package_dir = {'': 'src'},
package_data={'appia': ['processors/flow_rates.json', 'plotters/manual_plot_FPLC.R', 'plotters/manual_plot_HPLC.R']},
package_data={'appia': ['plotters/manual_plot_FPLC.R', 'plotters/manual_plot_HPLC.R']},
include_package_data=True,
packages = setuptools.find_packages(where = 'src'),
python_requires = ">=3.6",
install_requires = [
'couchdb',
'pandas',
'slack',
'plotly',
'kaleido'
],
Expand Down
1 change: 0 additions & 1 deletion src/appia/appia.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
#!/usr/bin/env python3
import argparse
import logging
import sys

from appia.parsers.process_parser import parser as process_parser
from appia.parsers.database_parser import parser as db_parser
Expand Down
12 changes: 2 additions & 10 deletions src/appia/parsers/database_parser.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,10 @@
import argparse
import os
from appia.processors.database import Database, Config
from appia.processors.core import three_column_print

def main(args):
if args.config == 'env':
db = Database(Config())
else:
db = Database(Config(args.config))

from appia.processors.database import db

if args.list or args.check_versions:
list = db.update_experiment_list()
Expand Down Expand Up @@ -50,11 +47,6 @@ def main(args):
add_help=False
)
parser.set_defaults(func = main)
parser.add_argument(
'config',
help = 'Config JSON file',
type = str
)
parser.add_argument(
'-l', '--list',
help = 'Print list of all experiments in database',
Expand Down
37 changes: 4 additions & 33 deletions src/appia/parsers/process_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@
import logging
import shutil
from appia.processors import hplc, fplc, experiment, core
from appia.processors.database import Database, Config
from appia.plotters import auto_plot
from appia.processors.gui import user_input

def main(args):
from appia.processors.database import db
file_list = core.get_files(args.files)
logging.debug(file_list)

Expand Down Expand Up @@ -146,31 +146,10 @@ def main(args):
os.path.join(out_dir, f'{exp.id}_manual-plot-FPLC.R')
)

if args.config:
if args.config == 'env':
db = Database(Config())
else:
db = Database(Config(args.config))

if args.database:
exp.reduce_hplc(args.reduce)
db.upload_experiment(exp, args.overwrite)

if args.post_to_slack:
config = Config(args.post_to_slack)

if config.slack:
from processors import slackbot

client = slackbot.get_client(config)

if client is not None:
slackbot.send_graphs(
config,
client,
os.path.join(out_dir, 'fsec_traces.pdf')
)


parser = argparse.ArgumentParser(
description = 'Process chromatography data',
add_help = False
Expand Down Expand Up @@ -205,12 +184,6 @@ def main(args):
nargs = '?',
const = 'plotters'
)
file_io.add_argument(
'-s', '--post-to-slack',
help = "Send completed plots to Slack. Need a config JSON with slack token and channel.",
nargs = '?',
const = os.path.join(os.path.dirname(os.path.realpath(__file__)), '..', 'config.json')
)

process_args = parser.add_argument_group('Processing Options')
process_args.add_argument(
Expand Down Expand Up @@ -260,10 +233,8 @@ def main(args):
)
web_up.add_argument(
'-d', '--database',
help = '''Upload experiment to couchdb. Optionally, provide config file location. Default config location is "config.json" in appia directory. Enter "env" to use environment variables instead.''',
dest = 'config',
nargs = '?',
const = os.path.join(os.path.dirname(os.path.realpath(__file__)), '..', 'config.json')
help = '''Upload experiment to couchdb. Must have set your parameters using `appia database`.''',
action = 'store_true'
)
web_up.add_argument(
'--overwrite',
Expand Down
66 changes: 60 additions & 6 deletions src/appia/parsers/user_settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,19 +19,24 @@ def save_settings(self):
with open(self.settings_path, 'w') as f:
json.dump(self._user_settings, f)

@property
def flow_rates(self) -> dict:
def access_private_property(self, propname:str, not_found = None):
try:
return self._user_settings['flow_rates']
return self._user_settings[propname]
except KeyError:
return {}
return not_found

# Flow rates --------------------------------------------------------

@property
def flow_rates(self) -> dict:
return self.access_private_property('flow_rates', {})

@flow_rates.setter
def flow_rates(self, new_flow_rates:dict):
if isinstance(new_flow_rates, dict):
self._user_settings['flow_rates'] = new_flow_rates
else:
raise TypeError
raise TypeError(f'Flow rates must be a dict, not a {type(new_flow_rates)}')

def delete_flow_rate(self, method_name):
del self._user_settings['flow_rates'][method_name]
Expand All @@ -49,4 +54,53 @@ def check_flow_rate(self, method_name:str):
elif len(matches) > 1:
logging.warning(f'More than one match for {method_name}')

return None
return None

# Database -------------------------------------------------------------

@property
def database_host(self):
return self.access_private_property('database_host')

@database_host.setter
def database_host(self, hostname:str):
if isinstance(hostname, str):
self._user_settings['database_host'] = hostname
else:
raise TypeError(f'Hostname must be a string, not a {type(hostname)}')

@property
def database_port(self):
return self.access_private_property('database_port', '5984')

@database_port.setter
def database_port(self, port:int):
if isinstance(port, int):
self._user_settings['database_port'] = str(port)
else:
raise TypeError(f'Port must be an integer, not a {type(port)}')

@property
def database_user(self):
return self.access_private_property('database_username')

@database_user.setter
def database_user(self, username:str):
if isinstance(username, str):
self._user_settings['database_username'] = username
else:
raise TypeError(f'Username must be a strong, not a {type(username)}')

@property
def database_password(self):
return self.access_private_property('database_password')

@database_password.setter
def database_password(self, password:str):
if isinstance(password, str):
self._user_settings['database_password'] = password
else:
raise TypeError(f'Password must be a string, not a {type(password)}')


appia_settings = AppiaSettings()
47 changes: 39 additions & 8 deletions src/appia/parsers/utilities_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,9 @@
import os
import shutil
import logging
import json
from appia.parsers.user_settings import AppiaSettings
from appia.parsers.user_settings import appia_settings

def main(args):
user_settings = AppiaSettings()

if args.copy_manual is not None:
script_location = os.path.normpath(os.path.join(os.path.dirname(os.path.realpath(__file__)), '..'))
Expand All @@ -30,19 +28,42 @@ def main(args):
logging.error('Bad flow rate. Give as --flow-rate {name} {mL/min number}')
raise TypeError

user_settings.update_flow_rates(new_flow_rates)
user_settings.save_settings()
appia_settings.update_flow_rates(new_flow_rates)
appia_settings.save_settings()

if args.list_flow_rates:
print('User specified flow rates:')
for method, fr in user_settings.flow_rates.items():
for method, fr in appia_settings.flow_rates.items():
print(f' {method + ":":>20} {fr}')

if args.delete_flow_rate:
for fr_key in args.delete_flow_rate:
user_settings.delete_flow_rate(fr_key)
appia_settings.delete_flow_rate(fr_key)

user_settings.save_settings()
appia_settings.save_settings()

if args.database_setup:
print("Setting up database. To leave any of these settings unchanged, leave them blank.")

new_settings = {}
new_settings['database_host'] = input('Database host (something like blah.domain.edu): ')
new_settings['database_user'] = input('Database username. (You set this during the docker installation): ')
new_settings['database_password'] = input('Database password. (You set this during the docker installation): ')
port = input("Database port number. (If you don't know, it's the default so leave it blank): ")
new_settings['database_port'] = port if len(port) == 0 else int(port)

for setting, value in new_settings.items():
logging.debug(f'Setting {setting} is {value}')
if isinstance(value, int) or len(value) > 0:
setattr(appia_settings, setting, value)

appia_settings.save_settings()

if args.check_database_login:
print('Host:', appia_settings.database_host)
print('Username:', appia_settings.database_user)
print('Password:', appia_settings.database_password)
print('Port:', appia_settings.database_port)


parser = argparse.ArgumentParser(
Expand Down Expand Up @@ -72,4 +93,14 @@ def main(args):
'--delete-flow-rate',
help = 'Remove a flow rate from user settings. Give the method names. Can give multiple method names.',
nargs='+'
)
parser.add_argument(
'--database-setup',
help = 'Set database access parameters',
action = 'store_true'
)
parser.add_argument(
'--check-database-login',
help = 'Print login info to the terminal',
action = 'store_true'
)
58 changes: 16 additions & 42 deletions src/appia/processors/database.py
Original file line number Diff line number Diff line change
@@ -1,51 +1,23 @@
import couchdb
import logging
import pandas as pd
import os
import sys
from appia.processors.experiment import Experiment
import json

class Config:
def __init__(self, config_file = None) -> None:

if config_file is None:
try:
self.cuser = os.environ['COUCHDB_USERNAME']
self.cpass = os.environ['COUCHDB_PASSWORD']
self.chost = os.environ['COUCHDB_HOST']
except KeyError:
logging.error('Provide a config file or set $COUCHDB_USERNAME, $COUCHDB_PASSWORD, $COUCHDB_HOST')
sys.exit(1)
else:
with open(config_file) as conf:
config = json.load(conf)

try:
self.cuser = config['user']
self.cpass = config['password']
self.chost = config['host']
self.couch = True
except KeyError:
logging.warning('Config missing information to connect to CouchDB')
self.couch = False

try:
self.slack_token = config['token']
self.slack_channel = config['chromatography_channel']
self.slack = True
except KeyError:
logging.warning('Config missing information for Slack bot')
self.slack = False

def __repr__(self) -> str:
return f'config object for host {self.chost}'
from appia.parsers.user_settings import appia_settings

class Database:
def __init__(self, config) -> None:
self.config = config
def __init__(self) -> None:
self.version = 4
couchserver = couchdb.Server(f'http://{config.cuser}:{config.cpass}@{config.chost}:5984')
username = appia_settings.database_user
password = appia_settings.database_password
hostname = appia_settings.database_host
port = appia_settings.database_port

if any([x is None for x in [username, password, hostname, port]]):
logging.error('You have not set your database login information. Please run `appia utils --database-setup`')
sys.exit(10)

couchserver = couchdb.Server(f'http://{username}:{password}@{hostname}:{port}')

dbname = 'traces'
if dbname in couchserver:
Expand All @@ -54,7 +26,7 @@ def __init__(self, config) -> None:
self.db = couchserver.create(dbname)

def __repr__(self) -> str:
return f'CouchDB at {self.config.chost}'
return f'CouchDB at {appia_settings.database_host}'

def update_experiment_list(self):
return [x['id'] for x in self.db.view('_all_docs')]
Expand Down Expand Up @@ -146,9 +118,11 @@ def upload_experiment(self, exp, overwrite = False):
self.db.save(doc)

def migrate(self):
if input(f'To migrate database hosted at {self.config.chost}, type: I have backed up my db\n').lower() == 'i have backed up my db':
if input(f'To migrate database hosted at {appia_settings.database_host}, type: I have backed up my db\n').lower() == 'i have backed up my db':
for exp_name in self.update_experiment_list():
exp = self.pull_experiment(exp_name)
self.upload_experiment(exp, overwrite=True)
else:
logging.warning('Back up your database before migrating it.')

db = Database()
Loading

0 comments on commit 4bf8233

Please sign in to comment.