Skip to content

Commit

Permalink
Merge pull request #145 from sofide/improve_init_configs
Browse files Browse the repository at this point in the history
Improve init configs
  • Loading branch information
facundobatista authored Jun 22, 2024
2 parents f1ad1fc + 4c46481 commit a8b88bd
Show file tree
Hide file tree
Showing 8 changed files with 99 additions and 65 deletions.
3 changes: 1 addition & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,8 +67,7 @@ cd kilink
git clone https://github.com/facundobatista/kilink.git
source bin/activate
pip install -r requirements.txt
./test
python2 kilink/kilink.py
PYTHONPATH=. python kilink/main.py
```

Or if you prefer to use Docker
Expand Down
27 changes: 4 additions & 23 deletions kilink.wsgi
Original file line number Diff line number Diff line change
@@ -1,32 +1,13 @@
import os
import sys

sys.path.insert(0, '/home/kilink/.virtualenvs/kilink/lib/python3.8/site-packages')
sys.path.insert(0, "/home/kilink/project/production/")

from kilink import backend, main, loghelper
from sqlalchemy import create_engine
from kilink.config import config

config.load_file("/home/kilink/project/production/configs/production.yaml")
from kilink import main, loghelper
from kilink.config import config

# get config data
auth_config = config["db_auth_config"]
auth_file = os.path.abspath(os.path.join(os.path.dirname(__file__), auth_config))
with open(auth_file) as fh:
vals = [x.strip() for x in fh.readlines()]
auth_data = dict(zip(("user", "pass"), vals))
engine_data = config["db_engine"].format(**auth_data)

# log setup
handlers = loghelper.setup_logging(config['log_directory'])
for h in handlers:
main.app.logger.addHandler(h)

# set up the backend
engine = create_engine(engine_data)
main.kilinkbackend = backend.KilinkBackend(engine)

config.load_config()
loghelper.setup_logging(main.app.logger)
application = main.app


20 changes: 15 additions & 5 deletions kilink/backend.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker, scoped_session

from kilink.config import config
from kilink.config import config, DB_ENGINE_INSTANCE_KEY

# what we use for plain text
PLAIN_TEXT = 'plain text'
Expand Down Expand Up @@ -111,11 +111,19 @@ def new_func(self, *a, **k):
class KilinkBackend(object):
"""Backend for Kilink."""

def __init__(self, db_engine):
Base.metadata.create_all(db_engine)
Session = scoped_session(sessionmaker(autocommit=True))
self.session = Session(bind=db_engine)
def __init__(self):
self._cached_version = None
self._session = None

@property
def session(self):
if self._session is None:
db_engine = config[DB_ENGINE_INSTANCE_KEY]
Base.metadata.create_all(db_engine)
Session = scoped_session(sessionmaker(autocommit=True))
self._session = Session(bind=db_engine)

return self._session

def get_version(self):
"""Return the version, reading it from a file (cached)."""
Expand Down Expand Up @@ -216,3 +224,5 @@ def build_tree(self, linkode_id):
fringe.extend(children)

return root_node, len(nodes)

kilinkbackend = KilinkBackend()
42 changes: 42 additions & 0 deletions kilink/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,17 @@

"""Config management."""

import os
import yaml

from sqlalchemy import create_engine

ENVIRONMENT_KEY = "environment"
PROD_ENVIRONMENT_VALUE = "prod"
UNITTESTING_ENVIRONMENT_VALUE = "unittesting"

DB_ENGINE_INSTANCE_KEY = "db_engine_instance"


class Config(dict):
"""Configuration helper class.
Expand All @@ -17,6 +26,39 @@ def load_file(self, filename):
cfg = yaml.safe_load(fh)
self.update(cfg)

def load_config(self, environment=PROD_ENVIRONMENT_VALUE):

if environment == PROD_ENVIRONMENT_VALUE:
self.load_file("/home/kilink/project/production/configs/production.yaml")
db_engine = self._prod_database_engine()

elif environment == UNITTESTING_ENVIRONMENT_VALUE:
self.load_file("configs/development.yaml")
db_engine = self._unittesting_database_engine()

else:
# defaults to dev environment
self.load_file("configs/development.yaml")
db_engine = self._dev_database_engine()

self.update({ENVIRONMENT_KEY: environment, DB_ENGINE_INSTANCE_KEY: db_engine})

def _prod_database_engine(self):
auth_config = self.get("db_auth_config")
auth_file = os.path.abspath(os.path.join(os.path.dirname(__file__), auth_config))
with open(auth_file) as fh:
vals = [x.strip() for x in fh.readlines()]
auth_data = dict(zip(("user", "pass"), vals))
engine_data = self.get("db_engine").format(**auth_data)

return create_engine(engine_data)

def _dev_database_engine(self):
return create_engine(self.get("db_engine"), echo=True)

def _unittesting_database_engine(self):
return create_engine("sqlite://")


config = Config()

Expand Down
19 changes: 15 additions & 4 deletions kilink/loghelper.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@

from logging.handlers import TimedRotatingFileHandler as TRFHandler

from kilink.config import config, ENVIRONMENT_KEY, PROD_ENVIRONMENT_VALUE

log_setup_lock = threading.Lock()


Expand Down Expand Up @@ -46,14 +48,23 @@ def _setup(logdir, verbose):
sys.excepthook = exception_handler


def setup_logging(logdir, verbose=False):
def setup_logging(_logger, verbose=False):
"""Set up the logging.
This is thread-safe; it will only call the setup if logger doesn't have
handlers already set.
"""
logdir = config['log_directory']

with log_setup_lock:
logger = logging.getLogger('kilink')
if not logger.handlers:
kilink_logger = logging.getLogger('kilink')
if not kilink_logger.handlers:
_setup(logdir, verbose)
return logger.handlers

for h in kilink_logger.handlers:
if config[ENVIRONMENT_KEY] != PROD_ENVIRONMENT_VALUE:
h.setLevel(logging.DEBUG)
_logger.addHandler(h)

if config[ENVIRONMENT_KEY] != PROD_ENVIRONMENT_VALUE:
_logger.setLevel(logging.DEBUG)
27 changes: 10 additions & 17 deletions kilink/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ def tools():
@app.route('/version')
def version():
"""Show the project version, very very simple, just for developers/admin help."""
return kilinkbackend.get_version()
return backend.kilinkbackend.get_version()


# --- API
Expand All @@ -83,7 +83,7 @@ def api_create():
text_type = request.form.get('text_type', "")
logger.debug("API create start; type=%r size=%d", text_type, len(content))
try:
klnk = kilinkbackend.create_kilink(content, text_type)
klnk = backend.kilinkbackend.create_kilink(content, text_type)
except backend.KilinkDataTooBigError:
logger.debug("Content data too big; on creation")
response = make_response()
Expand All @@ -104,7 +104,7 @@ def api_update(linkode_id):
logger.debug("API update start; linkode_id=%r parent=%r type=%r size=%d",
linkode_id, parent, text_type, len(content))
try:
klnk = kilinkbackend.update_kilink(parent, content, text_type)
klnk = backend.kilinkbackend.update_kilink(parent, content, text_type)
except backend.KilinkNotFoundError:
logger.debug("API update done; linkode_id %r not found", linkode_id)
response = make_response()
Expand All @@ -130,10 +130,10 @@ def api_get(linkode_id, revno=None):
# the linkode_id to get the info from is the second token
linkode_id = revno

klnk = kilinkbackend.get_kilink(linkode_id)
klnk = backend.kilinkbackend.get_kilink(linkode_id)

# get the tree
tree, nodeq = kilinkbackend.build_tree(linkode_id)
tree, nodeq = backend.kilinkbackend.build_tree(linkode_id)

logger.debug("API get done; type=%r size=%d len_tree=%d",
klnk.text_type, len(klnk.content), nodeq)
Expand All @@ -144,16 +144,9 @@ def api_get(linkode_id, revno=None):

if __name__ == "__main__":
# load config
config.load_file("configs/development.yaml")

# log setup
handlers = loghelper.setup_logging(config['log_directory'], verbose=True)
for h in handlers:
app.logger.addHandler(h)
h.setLevel(logging.DEBUG)
app.logger.setLevel(logging.DEBUG)

# set up the backend
engine = create_engine(config["db_engine"], echo=True)
kilinkbackend = backend.KilinkBackend(engine)
config.load_config(environment="dev")

# logging setup
loghelper.setup_logging(app.logger, verbose=True)

app.run(debug=True, host='0.0.0.0')
18 changes: 8 additions & 10 deletions tests/test_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
from sqlalchemy import create_engine

from kilink import main, backend
from kilink.config import config
from kilink.config import config, UNITTESTING_ENVIRONMENT_VALUE


class _ANY(object):
Expand All @@ -38,9 +38,7 @@ class BaseTestCase(TestCase):
def setUp(self):
"""Set up."""
super(BaseTestCase, self).setUp()
config.load_file("configs/development.yaml")
engine = create_engine("sqlite://")
self.backend = main.kilinkbackend = backend.KilinkBackend(engine)
config.load_config(UNITTESTING_ENVIRONMENT_VALUE)
self.app = main.app.test_client()

def api_create(self, data, code=201):
Expand Down Expand Up @@ -79,7 +77,7 @@ def test_create_simple(self):

resp = self.api_create(data=datos)

klnk = self.backend.get_kilink(resp["linkode_id"])
klnk = backend.kilinkbackend.get_kilink(resp["linkode_id"])
self.assertEqual(klnk.content, content)
self.assertEqual(klnk.text_type, text_type)
self.assertLess(klnk.timestamp, datetime.datetime.utcnow())
Expand All @@ -92,7 +90,7 @@ def test_create_error(self):

# make it fail!

with patch.object(self.backend, 'create_kilink') as mock:
with patch.object(backend.kilinkbackend, 'create_kilink') as mock:
mock.side_effect = ValueError("foo")
self.api_create(data=datos, code=500)

Expand All @@ -102,7 +100,7 @@ def test_create_no_text_type(self):
datos = {'content': content}
resp = self.api_create(data=datos)

klnk = self.backend.get_kilink(resp["linkode_id"])
klnk = backend.kilinkbackend.get_kilink(resp["linkode_id"])
self.assertEqual(klnk.content, content)
self.assertEqual(klnk.text_type, backend.PLAIN_TEXT)
self.assertLess(klnk.timestamp, datetime.datetime.utcnow())
Expand All @@ -113,7 +111,7 @@ def test_create_empty_text_type(self):
datos = {'content': content, 'text_type': ""}
resp = self.api_create(data=datos)

klnk = self.backend.get_kilink(resp["linkode_id"])
klnk = backend.kilinkbackend.get_kilink(resp["linkode_id"])
self.assertEqual(klnk.content, content)
self.assertEqual(klnk.text_type, backend.PLAIN_TEXT)
self.assertLess(klnk.timestamp, datetime.datetime.utcnow())
Expand All @@ -133,7 +131,7 @@ def test_update_simple(self):
resp = self.api_update(linkode_id, data=child_content)
revno1 = resp["revno"]

klnk = self.backend.get_kilink(revno1)
klnk = backend.kilinkbackend.get_kilink(revno1)
self.assertEqual(klnk.content, u"Moñito")
self.assertEqual(klnk.text_type, u"type2")
self.assertLess(klnk.timestamp, datetime.datetime.utcnow())
Expand All @@ -146,7 +144,7 @@ def test_update_simple(self):
resp = self.api_update(linkode_id, data=child_content2)
revno2 = resp["revno"]

klnk = self.backend.get_kilink(revno2)
klnk = backend.kilinkbackend.get_kilink(revno2)
self.assertEqual(klnk.content, u"Moñito2")
self.assertEqual(klnk.text_type, u"type3")
self.assertLess(klnk.timestamp, datetime.datetime.utcnow())
Expand Down
8 changes: 4 additions & 4 deletions tests/test_backend.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
PLAIN_TEXT,
_get_unique_id,
)
from kilink.config import config
from kilink.config import config, UNITTESTING_ENVIRONMENT_VALUE, DB_ENGINE_INSTANCE_KEY


class BaseTestCase(TestCase):
Expand All @@ -28,9 +28,9 @@ class BaseTestCase(TestCase):
def setUp(self):
"""Set up."""
super(BaseTestCase, self).setUp()
config.load_file("configs/development.yaml")
self.db_engine = create_engine("sqlite://")
self.bkend = KilinkBackend(self.db_engine)
config.load_config(environment=UNITTESTING_ENVIRONMENT_VALUE)
self.db_engine = config[DB_ENGINE_INSTANCE_KEY]
self.bkend = KilinkBackend()


class ContentTestCase(BaseTestCase):
Expand Down

0 comments on commit a8b88bd

Please sign in to comment.