3
0
Fork 0

Add wutta make-appdir subcommand

This commit is contained in:
Lance Edgar 2023-11-22 00:01:46 -06:00
parent 5e971e4b0c
commit 13472a5ab5
9 changed files with 180 additions and 2 deletions

View file

@ -0,0 +1,6 @@
``wuttjamaican.commands.make_appdir``
=====================================
.. automodule:: wuttjamaican.commands.make_appdir
:members:

View file

@ -10,6 +10,7 @@
app
commands
commands.base
commands.make_appdir
commands.setup
conf
db

View file

@ -15,6 +15,11 @@ Glossary
just one database (for simple apps) which uses PostgreSQL for the
backend.
app dir
Folder containing app-specific config files, log files, etc.
Usually this is named ``app`` and is located at the root of the
virtual environment.
app handler
Python object representing the core of the :term:`app`. There is
normally just one "global" app handler, which is an instance of

View file

@ -51,4 +51,5 @@ console_scripts =
wutta = wuttjamaican.commands.base:main
wutta.subcommands =
make-appdir = wuttjamaican.commands.make_appdir:MakeAppDir
setup = wuttjamaican.commands.setup:Setup

View file

@ -24,6 +24,8 @@
WuttJamaican - app handler
"""
import os
from wuttjamaican.util import load_entry_points, load_object, parse_bool
@ -47,6 +49,35 @@ class AppHandler:
self.config = config
self.handlers = {}
def make_appdir(self, path, subfolders=None, **kwargs):
"""
Establish an :term:`app dir` at the given path.
Default logic only creates a few subfolders, meant to help
steer the admin toward a convention for sake of where to put
things. But custom app handlers are free to do whatever.
:param path: Path to the desired app dir. If the path does
not yet exist then it will be created. But regardless it
should be "refreshed" (e.g. missing subfolders created)
when this method is called.
:param subfolders: Optional list of subfolder names to create
within the app dir. If not specified, defaults will be:
``['data', 'log', 'work']``.
"""
appdir = path
if not os.path.exists(appdir):
os.makedirs(appdir)
if not subfolders:
subfolders = ['data', 'log', 'work']
for name in subfolders:
path = os.path.join(appdir, name)
if not os.path.exists(path):
os.mkdir(path)
def make_engine_from_config(
self,
config_dict,

View file

@ -0,0 +1,62 @@
# -*- coding: utf-8; -*-
################################################################################
#
# WuttJamaican -- Base package for Wutta Framework
# Copyright © 2023 Lance Edgar
#
# This file is part of Wutta Framework.
#
# Wutta Framework is free software: you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the Free
# Software Foundation, either version 3 of the License, or (at your option) any
# later version.
#
# Wutta Framework is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
# more details.
#
# You should have received a copy of the GNU General Public License along with
# Wutta Framework. If not, see <http://www.gnu.org/licenses/>.
#
################################################################################
"""
WuttJamaican - subcommand: make-appdir
"""
import os
import sys
from .base import Subcommand
class MakeAppDir(Subcommand):
"""
Make or refresh the "app dir" for virtual environment
"""
name = 'make-appdir'
description = __doc__.strip()
def add_args(self):
""" """
self.parser.add_argument('--path', metavar='APPDIR',
help="Optional path to desired app dir. If not specified "
"it will be named ``app`` and placed in the root of the "
"virtual environment.")
def run(self, args):
"""
This may be used during setup to establish the :term:`app dir`
for a virtual environment. This folder will contain config
files, log files etc. used by the app.
Calls :meth:`~wuttjamaican.app.AppHandler.make_appdir()` to do
the heavy lifting.
"""
if args.path:
appdir = os.path.abspath(args.path)
else:
appdir = os.path.join(sys.prefix, 'app')
self.app.make_appdir(appdir)
self.stdout.write(f"established appdir: {appdir}\n")

View file

@ -29,7 +29,7 @@ from .base import Subcommand
class Setup(Subcommand):
"""
Install and configure misc. software
Install and configure various software
"""
name = 'setup'
description = __doc__.strip()

View file

@ -0,0 +1,49 @@
# -*- coding: utf-8; -*-
import os
import shutil
import tempfile
from unittest import TestCase
from unittest.mock import patch
from wuttjamaican.conf import WuttaConfig
from wuttjamaican.commands import Command, make_appdir
class TestMakeAppDir(TestCase):
def setUp(self):
self.config = WuttaConfig(appname='wuttatest')
self.command = Command(self.config, subcommands={
'make-appdir': make_appdir.MakeAppDir,
})
def test_run(self):
# appdir is created, and 3 subfolders added by default
tempdir = tempfile.mkdtemp()
appdir = os.path.join(tempdir, 'app')
self.assertFalse(os.path.exists(appdir))
self.command.run('make-appdir', '--path', appdir)
self.assertTrue(os.path.exists(appdir))
self.assertEqual(len(os.listdir(appdir)), 3)
shutil.rmtree(tempdir)
# subfolders still added if appdir already exists
tempdir = tempfile.mkdtemp()
self.assertTrue(os.path.exists(tempdir))
self.assertEqual(len(os.listdir(tempdir)), 0)
self.command.run('make-appdir', '--path', tempdir)
self.assertEqual(len(os.listdir(tempdir)), 3)
shutil.rmtree(tempdir)
# mock out sys.prefix to get coverage
with patch('wuttjamaican.commands.make_appdir.sys') as sys:
tempdir = tempfile.mkdtemp()
appdir = os.path.join(tempdir, 'app')
sys.prefix = tempdir
self.assertFalse(os.path.exists(appdir))
self.command.run('make-appdir')
self.assertTrue(os.path.exists(appdir))
self.assertEqual(len(os.listdir(appdir)), 3)
shutil.rmtree(tempdir)

View file

@ -1,5 +1,8 @@
# -*- coding: utf-8; -*-
import os
import shutil
import tempfile
from unittest import TestCase
from unittest.mock import patch, MagicMock
@ -9,18 +12,38 @@ from sqlalchemy.engine import Engine
from sqlalchemy.pool import NullPool
from wuttjamaican import app, db
from wuttjamaican.conf import WuttaConfig
class TestAppHandler(TestCase):
def setUp(self):
self.config = MagicMock()
self.config = WuttaConfig(appname='wuttatest')
self.app = app.AppHandler(self.config)
def test_init(self):
self.assertIs(self.app.config, self.config)
self.assertEqual(self.app.handlers, {})
def test_make_appdir(self):
# appdir is created, and 3 subfolders added by default
tempdir = tempfile.mkdtemp()
appdir = os.path.join(tempdir, 'app')
self.assertFalse(os.path.exists(appdir))
self.app.make_appdir(appdir)
self.assertTrue(os.path.exists(appdir))
self.assertEqual(len(os.listdir(appdir)), 3)
shutil.rmtree(tempdir)
# subfolders still added if appdir already exists
tempdir = tempfile.mkdtemp()
self.assertTrue(os.path.exists(tempdir))
self.assertEqual(len(os.listdir(tempdir)), 0)
self.app.make_appdir(tempdir)
self.assertEqual(len(os.listdir(tempdir)), 3)
shutil.rmtree(tempdir)
def test_make_engine_from_config_basic(self):
engine = self.app.make_engine_from_config({
'sqlalchemy.url': 'sqlite://',