Add wutta make-appdir
subcommand
This commit is contained in:
parent
5e971e4b0c
commit
13472a5ab5
6
docs/api/wuttjamaican/commands.make_appdir.rst
Normal file
6
docs/api/wuttjamaican/commands.make_appdir.rst
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
|
||||||
|
``wuttjamaican.commands.make_appdir``
|
||||||
|
=====================================
|
||||||
|
|
||||||
|
.. automodule:: wuttjamaican.commands.make_appdir
|
||||||
|
:members:
|
|
@ -10,6 +10,7 @@
|
||||||
app
|
app
|
||||||
commands
|
commands
|
||||||
commands.base
|
commands.base
|
||||||
|
commands.make_appdir
|
||||||
commands.setup
|
commands.setup
|
||||||
conf
|
conf
|
||||||
db
|
db
|
||||||
|
|
|
@ -15,6 +15,11 @@ Glossary
|
||||||
just one database (for simple apps) which uses PostgreSQL for the
|
just one database (for simple apps) which uses PostgreSQL for the
|
||||||
backend.
|
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
|
app handler
|
||||||
Python object representing the core of the :term:`app`. There is
|
Python object representing the core of the :term:`app`. There is
|
||||||
normally just one "global" app handler, which is an instance of
|
normally just one "global" app handler, which is an instance of
|
||||||
|
|
|
@ -51,4 +51,5 @@ console_scripts =
|
||||||
wutta = wuttjamaican.commands.base:main
|
wutta = wuttjamaican.commands.base:main
|
||||||
|
|
||||||
wutta.subcommands =
|
wutta.subcommands =
|
||||||
|
make-appdir = wuttjamaican.commands.make_appdir:MakeAppDir
|
||||||
setup = wuttjamaican.commands.setup:Setup
|
setup = wuttjamaican.commands.setup:Setup
|
||||||
|
|
|
@ -24,6 +24,8 @@
|
||||||
WuttJamaican - app handler
|
WuttJamaican - app handler
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
import os
|
||||||
|
|
||||||
from wuttjamaican.util import load_entry_points, load_object, parse_bool
|
from wuttjamaican.util import load_entry_points, load_object, parse_bool
|
||||||
|
|
||||||
|
|
||||||
|
@ -47,6 +49,35 @@ class AppHandler:
|
||||||
self.config = config
|
self.config = config
|
||||||
self.handlers = {}
|
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(
|
def make_engine_from_config(
|
||||||
self,
|
self,
|
||||||
config_dict,
|
config_dict,
|
||||||
|
|
62
src/wuttjamaican/commands/make_appdir.py
Normal file
62
src/wuttjamaican/commands/make_appdir.py
Normal 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")
|
|
@ -29,7 +29,7 @@ from .base import Subcommand
|
||||||
|
|
||||||
class Setup(Subcommand):
|
class Setup(Subcommand):
|
||||||
"""
|
"""
|
||||||
Install and configure misc. software
|
Install and configure various software
|
||||||
"""
|
"""
|
||||||
name = 'setup'
|
name = 'setup'
|
||||||
description = __doc__.strip()
|
description = __doc__.strip()
|
||||||
|
|
49
tests/commands/test_make_appdir.py
Normal file
49
tests/commands/test_make_appdir.py
Normal 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)
|
|
@ -1,5 +1,8 @@
|
||||||
# -*- coding: utf-8; -*-
|
# -*- coding: utf-8; -*-
|
||||||
|
|
||||||
|
import os
|
||||||
|
import shutil
|
||||||
|
import tempfile
|
||||||
from unittest import TestCase
|
from unittest import TestCase
|
||||||
from unittest.mock import patch, MagicMock
|
from unittest.mock import patch, MagicMock
|
||||||
|
|
||||||
|
@ -9,18 +12,38 @@ from sqlalchemy.engine import Engine
|
||||||
from sqlalchemy.pool import NullPool
|
from sqlalchemy.pool import NullPool
|
||||||
|
|
||||||
from wuttjamaican import app, db
|
from wuttjamaican import app, db
|
||||||
|
from wuttjamaican.conf import WuttaConfig
|
||||||
|
|
||||||
|
|
||||||
class TestAppHandler(TestCase):
|
class TestAppHandler(TestCase):
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
self.config = MagicMock()
|
self.config = WuttaConfig(appname='wuttatest')
|
||||||
self.app = app.AppHandler(self.config)
|
self.app = app.AppHandler(self.config)
|
||||||
|
|
||||||
def test_init(self):
|
def test_init(self):
|
||||||
self.assertIs(self.app.config, self.config)
|
self.assertIs(self.app.config, self.config)
|
||||||
self.assertEqual(self.app.handlers, {})
|
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):
|
def test_make_engine_from_config_basic(self):
|
||||||
engine = self.app.make_engine_from_config({
|
engine = self.app.make_engine_from_config({
|
||||||
'sqlalchemy.url': 'sqlite://',
|
'sqlalchemy.url': 'sqlite://',
|
||||||
|
|
Loading…
Reference in a new issue