Source code for watson.framework.support.console.commands.project

# -*- coding: utf-8 -*-
import os
import stat
import sys
from wsgiref import util
from string import Template
from watson.common.contextmanagers import suppress
from watson.console import ConsoleError, colors, command
from watson.console.decorators import arg
from watson.di import ContainerAware
from watson.http.messages import Request


[docs]class Project(command.Base, ContainerAware): """Creating and maintaining Watson projects. Example: .. code-block:: ./console.py dev runserver """ __ioc_definition__ = { 'property': { 'router': 'router' } } @arg('override', action='store_const', const=1, optional=True) @arg('dir', optional=True)
[docs] def new(self, name, app_name, dir, override): """Creates a new project, defaults to the current working directory. Args: name: The name of the project app_name: The name of the application to create dir: The directory to create the project in override: Override any existing project in the path """ if dir: root = os.path.abspath(dir) if not os.path.exists(root): raise ConsoleError('Directory {} not found'.format(root)) else: root = os.getcwd() basepath = os.path.join(root, name) paths = [ basepath, os.path.join(basepath, app_name), os.path.join(basepath, app_name, 'config'), os.path.join(basepath, app_name, 'controllers'), os.path.join(basepath, app_name, 'views'), os.path.join(basepath, app_name, 'views', 'index'), os.path.join(basepath, 'data'), os.path.join(basepath, 'data', 'cache'), os.path.join(basepath, 'data', 'logs'), os.path.join(basepath, 'data', 'uploads'), os.path.join(basepath, 'public'), os.path.join(basepath, 'public', 'css'), os.path.join(basepath, 'public', 'img'), os.path.join(basepath, 'public', 'js'), os.path.join(basepath, 'tests'), os.path.join(basepath, 'tests', app_name), os.path.join(basepath, 'tests', app_name, 'controllers'), ] files = [ (os.path.join(basepath, app_name, '__init__.py'), BLANK_PY_TEMPLATE), (os.path.join(basepath, app_name, 'app.py'), APP_PY_TEMPLATE), (os.path.join(basepath, app_name, 'config', '__init__.py'), BLANK_PY_TEMPLATE), (os.path.join(basepath, app_name, 'config', 'prod.py.dist'), PROD_CONFIG_PY_TEMPLATE), (os.path.join(basepath, app_name, 'config', 'dev.py.dist'), DEV_CONFIG_PY_TEMPLATE), (os.path.join(basepath, app_name, 'config', 'config.py'), DEV_CONFIG_PY_TEMPLATE), (os.path.join(basepath, app_name, 'config', 'routes.py'), ROUTES_PY_TEMPLATE), (os.path.join(basepath, app_name, 'controllers', '__init__.py'), SAMPLE_CONTROLLER_INIT_TEMPLATE), (os.path.join(basepath, app_name, 'controllers', 'index.py'), SAMPLE_CONTROLLER_TEMPLATE), (os.path.join(basepath, app_name, 'views', 'index', 'get.html'), SAMPLE_VIEW_TEMPLATE), (os.path.join(basepath, 'tests', '__init__.py'), BLANK_PY_TEMPLATE), (os.path.join(basepath, 'tests', app_name, '__init__.py'), BLANK_PY_TEMPLATE), (os.path.join(basepath, 'tests', app_name, 'controllers', '__init__.py'), BLANK_PY_TEMPLATE), (os.path.join(basepath, 'tests', app_name, 'controllers', 'test_index.py'), SAMPLE_TEST_SUITE), (os.path.join(basepath, 'console.py'), CONSOLE_TEMPLATE), ] for path in paths: try: os.mkdir(path) except: if not override: raise ConsoleError( 'Project already exists at {0}'.format(basepath)) for filename, contents in files: try: with open(filename, 'w', encoding='utf-8') as file: file.write( Template( contents).safe_substitute(app_name=app_name)) except: if not override: raise ConsoleError( 'File {0} already exists.'.format(filename)) st = os.stat(files[-1][0]) os.chmod(files[-1][0], st.st_mode | stat.S_IEXEC) self.write('Project {} created at {}'.format(name, root))
@arg()
[docs] def test(self): """Runs the unit tests for the project. """ try: app_module = os.environ['APP_MODULE'] test_runner = None cli_args = '' sys.argv = [sys.argv.pop(0)] try: import pytest test_runner = 'pytest' cli_args = '--cov {0}'.format(app_module) except: with suppress(ImportError): import nose test_runner = 'nose' cli_args = '--cover-package={0}'.format(app_module) if test_runner: sys.modules[test_runner].main(cli_args.split(' ')) else: raise ConsoleError( "You must install either 'nose' or 'py.test' to run the unit tests.") except: _no_application_error()
@arg('path', optional=True) @arg('method', optional=True) @arg('format', optional=True) @arg('server', optional=True)
[docs] def routes(self, path, method, format, server): """Aids in the debugging of routes associated. Args: path: Validate the specified path against the router method: The http request method format: The http request format server: The hostname of the request """ try: router = self.router if not router.routes: raise ConsoleError( 'There are no routes associated with the application.') if path: environ = {} util.setup_testing_defaults(environ) server = server or '127.0.0.1' environ.update({ 'REQUEST_METHOD': method or 'GET', 'HTTP_ACCEPT': format or 'text/html', 'PATH_INFO': path, 'SERVER_NAME': server, 'HTTP_HOST': server }) request = Request.from_environ(environ) matches = [match for match in router.matches(request)] if matches: longest_route = max([match.route.name for match in matches], key=len) self.write( colors.header('Displaying {} matching routes for {}:\n'.format( len(matches), request.url))) for match in matches: route = match.route self.write('{0}\t{1}\n'.format( route.name.rjust(len(longest_route)), route.path)) else: raise ConsoleError('There are no matching routes.') else: self.write(colors.header('Displaying {0} routes for the application:\n'.format(len(router)))) longest_route = max(router, key=len) for name, route in router: self.write('{0}\t{1}\n'.format( name.rjust(len(longest_route[0])), route.path)) except ConsoleError: raise except Exception as e: raise e _no_application_error()
def _no_application_error(): raise ConsoleError( 'No watson application can be found, are you sure you\'re in the correct directory?') BLANK_PY_TEMPLATE = """# -*- coding: utf-8 -*- """ APP_PY_TEMPLATE = """# -*- coding: utf-8 -*- from watson.framework import applications from ${app_name}.config import config application = applications.Http(config) """ ROUTES_PY_TEMPLATE = """# -*- coding: utf-8 -*- routes = { 'index': { 'path': '/', 'options': {'controller': '${app_name}.controllers.Index'} } } """ PROD_CONFIG_PY_TEMPLATE = """# -*- coding: utf-8 -*- from ${app_name}.config.routes import routes debug = { 'enabled': False } """ DEV_CONFIG_PY_TEMPLATE = """# -*- coding: utf-8 -*- from ${app_name}.config.routes import routes debug = { 'enabled': True } """ SAMPLE_CONTROLLER_INIT_TEMPLATE = """# -*- coding: utf-8 -*- from ${app_name}.controllers.index import Index __all__ = ['Index'] """ SAMPLE_CONTROLLER_TEMPLATE = """# -*- coding: utf-8 -*- from watson import framework from watson.framework import controllers class Index(controllers.Rest): def GET(self): return 'Welcome to Watson v{0}!'.format(framework.__version__) """ SAMPLE_VIEW_TEMPLATE = """<!DOCTYPE html> <html> <head> <title>Welcome to Watson!</title> </head> <body> <h1>{{ content }}</h1> <p>You are now on your way to creating your first application using Watson.</p> <p>Read more about Watson in <a href="http://watson-framework.readthedocs.org/">the documentation.</a> </body> </html> """ SAMPLE_TEST_SUITE = """# -*- coding: utf-8 -*- from watson import framework from ${app_name}.controllers.index import Index class TestSuiteIndex(object): def test_get(self): index = Index() assert index.GET() == 'Welcome to Watson v{0}!'.format(framework.__version__) """ CONSOLE_TEMPLATE = """#!/usr/bin/env python import os import sys import os import sys SCRIPT_DIR, SCRIPT_FILE = os.path.split(os.path.abspath(__file__)) os.environ.update({ 'APP_MODULE': '${app_name}', 'APP_DIR': os.path.join(SCRIPT_DIR, '${app_name}'), 'PUBLIC_DIR': os.path.join(SCRIPT_DIR, 'public'), 'SCRIPT_DIR': SCRIPT_DIR }) try: import watson except: sys.stdout.write('You must have Watson installed, please run `pip install watson-framework`\\n') sys.exit(1) from watson.framework import applications from ${app_name}.config import config if __name__ == '__main__': os.chdir(os.environ['APP_DIR']) application = applications.Console(config) application() """