Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP

Loading…

customized output dir of pcreate scaffolding. #892

Closed
wants to merge 9 commits into from

3 participants

@chhsiao1981

scaffolding in pcreate is a very powerful feature in setting up dev structure very efficiently.
Currently the output dir is based on the module name because of the nature of python programming. However, when developing module A, sometimes we may want to have some simple files within module A, but still with some basic scaffolding template. This patch intends to provide customized output dir of pcreate.

@mmerickel
Owner

This idea is fine, but the options.output_dir needs to be sanitized properly (what if it's an absolute path or contains a ~). Also os.path.join should be used for cross-platform purposes.

@tseaver
Owner

Thanks for the follow-up: the tests look good. Can I ask one more thing? Please add your name to CONTRIBUTORS.txt and re-push.

@tseaver
Owner

Still need's CONTRIBUTORS.txt.

pyramid/scripts/pcreate.py
((11 lines not shown))
+ pkg_full_name = re.sub('\/', '.', pkg_full_path)
+ return pkg_full_name
+
+ def _set_output_dir(self, dir_path):
+ if dir_path[0] == '~':
+ dir_path = os.path.expanduser(dir_path)
+ if dir_path[0] == '~':
+ raise Exception('invalid user dir')
+
+ if dir_path[0] == '/':
@mmerickel Owner

os.path.abspath will automatically norm the path and make it absolute via the CWD if it is not already, so the else here should be unnecessary.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
pyramid/scripts/pcreate.py
@@ -48,6 +48,10 @@ class PCreateCommand(object):
dest='overwrite',
action='store_true',
help='Always overwrite')
+ parser.add_option('-d', '--dir',
+ dest='output_dir',
+ action='store',
+ help='customized output dir. If the dir starting with "~", then the corresponding home dir will be provided. If the leading character of dir is "/", the dir will be treated as absolute path. Otherwise, the dir will be the relative path from current dir (os.getcwd())')
@mmerickel Owner

79-character line width

help=(
    'customized output dir. '
    'If the dir starting..'
))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
pyramid/scripts/pcreate.py
((11 lines not shown))
+ pkg_full_name = re.sub('\/', '.', pkg_full_path)
+ return pkg_full_name
+
+ def _set_output_dir(self, dir_path):
+ if dir_path[0] == '~':
@mmerickel Owner

I would call os.path.expanduser regardless of the presence of the ~ because it will not affect the path if the ~ is not there. The Exception also seems unnecessary to me because we should not be creating parent directories for the output_dir, so somewhere else there will be a failure when it fails to create the ~baduser/project folder.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
pyramid/scripts/pcreate.py
@@ -123,4 +131,25 @@ def out(self, msg): # pragma: no cover
if not self.quiet:
print(msg)
+ def _set_pkg_full_name(self, pkg_path):
@mmerickel Owner

my feeble brain is having trouble with all of this path munging, can we get a comment here about what all this is for? I'm not clear what pkg_full_name is versus pkg_name.

Hi mmerickel,

Thank you very much for the comments.
I will make the path-related code cleaner/clearer.

The original goal of this patch is to be able to have pcreate -s dummy -d a/b/c/ Distro
and generate Distro as a.b.c.Distro.

pkg_name was used as Distro. So I added pkg_full_name to indicate a.b.c.Distro
I'll add comments and maybe change the name to make it clearer.
(This code needs revise too.)

(Revised comments)
Currently when doing

pcreate -s starter p/q/r/s/t

pcreate would create p/q/r/s/t as dir, and name t as pkg name, and put content of starter inside t.

What I intend to do is to have module (or package) t inside package r.s, where r is inside directory p/q, when initializing p/q/r/s/t.py
and I also would like to have p/q/test_r/test_s/test_t.py as corresponding test file (or other corresponding files).

To achieve this, we need the following information for templates:
1. output_dir (p/q/r/s)
1. module/base pkg name (s).
2. full module/pkg name (r.s.t).
3. root pkg name (r)
4. parent pkg name (r.s)

3 and 4 can be derived from 2 within re, and they are not clear if full name is 't'.

I want to have the following command:
pcreate -s simple_module -d p/q r/s/t (or pcreate -s simple_module -d p/q r.s.t)
(I would prefer the first one to be compatible with current usage)

because basename(args[0]) can be treated as module or as pkg,
I would like to have the following variables (pcreate -s simple_module -d p/q r/s/t as example):
pkg_name as basename(args[0]) (t) (as before)
pkg_full_name as full pkg name (r.s.t)

I'll leave root pkg name and parent pkg name to be derived within customized templates.

Suggestions are welcome.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
chhsiao1981 added some commits
@chhsiao1981 chhsiao1981 1. Merge branch 'master' of https://github.com/Pylons/pyramid
2. makes output_dir and pkg_full_name more clear with -d.

3. provide simple_module and simple_pkg template
8e30232
@chhsiao1981 chhsiao1981 add test on scaffolds and pass 5ae00ad
@chhsiao1981

This pull-request may be off the original purpose of pcreate too much.
I'll retract this pull-request and restart another one.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Mar 7, 2013
  1. @chhsiao1981
Commits on Mar 14, 2013
  1. @chhsiao1981
Commits on Mar 23, 2013
  1. @chhsiao1981
Commits on Aug 21, 2013
  1. @chhsiao1981

    add to CONTRIBUTORS

    chhsiao1981 authored
Commits on Aug 22, 2013
  1. @chhsiao1981
Commits on Sep 1, 2013
  1. @chhsiao1981

    1. pass test

    chhsiao1981 authored
  2. @chhsiao1981
Commits on Mar 9, 2014
  1. @chhsiao1981

    1. Merge branch 'master' of https://github.com/Pylons/pyramid

    chhsiao1981 authored
    2. makes output_dir and pkg_full_name more clear with -d.
    
    3. provide simple_module and simple_pkg template
  2. @chhsiao1981
This page is out of date. Refresh to see the latest.
View
7 CHANGES.txt
@@ -10,6 +10,13 @@ Unreleased
``reissue_time=None`` would cause an exception when modifying the session.
See https://github.com/Pylons/pyramid/issues/1247
+- The ``pcreate`` command now takes ``-d`` (or ``--dir``) flag to specify customized dir.
+ For example::
+
+ pcreate -s simple_module -d a/b/c d/e
+
+ will create d.e with simple_module template in path a/b/c/d/e.py
+
1.5b1 (2014-02-08)
==================
View
2  CONTRIBUTORS.txt
@@ -230,3 +230,5 @@ Contributors
- Antti Haapala, 2013/11/15
- Amit Mane, 2014/01/23
+
+- Chuan-Heng Hsiao, 2014/03/08
View
27 pyramid/scaffolds/__init__.py
@@ -1,5 +1,6 @@
import binascii
import os
+import re
from textwrap import dedent
from pyramid.compat import native_
@@ -17,6 +18,18 @@ def pre(self, command, output_dir, vars):
``random_string``, and ``package_logger``). It also prevents common
misnamings (such as naming a package "site" or naming a package
logger "root".
+
+ package_full_path as the full path of the package/module
+ package_parent_path as the parent dir path of the package/module
+
+ If we do pcreate -s {template} -d a/b c/d/e:
+ package: e
+ package_full_name: c.d.e
+ package_logger: e
+ package_full_path: c/d/e
+ package_parent_path: c/d (dirname of package_full_path)
+ package_parent_name: c.d
+ package_root_name: c (first in the list of package_full_name separated by .)
"""
if vars['package'] == 'site':
raise ValueError('Sorry, you may not name your package "site". '
@@ -28,6 +41,12 @@ def pre(self, command, output_dir, vars):
# Rename the app logger in the rare case a project is named 'root'
package_logger = 'app'
vars['package_logger'] = package_logger
+
+ vars['package_full_path'] = vars['package_full_name'].replace('.', os.path.sep)
+ vars['package_parent_path'] = os.path.dirname(vars['package_full_path'])
+ vars['package_parent_name'] = vars['package_parent_path'].replace(os.path.sep, '.')
+ vars['package_root_name'] = vars['package_full_name'].split('.')[0]
+
return Template.pre(self, command, output_dir, vars)
def post(self, command, output_dir, vars): # pragma: no cover
@@ -66,3 +85,11 @@ class ZODBProjectTemplate(PyramidTemplate):
class AlchemyProjectTemplate(PyramidTemplate):
_template_dir = 'alchemy'
summary = 'Pyramid SQLAlchemy project using url dispatch'
+
+class SimpleModuleTemplate(PyramidTemplate):
+ _template_dir = 'simple_module'
+ summary = 'Pyramid simple module'
+
+class SimplePkgTemplate(PyramidTemplate):
+ _template_dir = 'simple_pkg'
+ summary = 'Pyramid simple pkg'
View
53 pyramid/scripts/pcreate.py
@@ -16,6 +16,13 @@ def main(argv=sys.argv, quiet=False):
return command.run()
class PCreateCommand(object):
+ '''
+ 1. pcreate -s starter a/b
+ initialize project/package b with starter template in directory a/b
+
+ 2. pcreate -s simple_module -d c/d e/f
+ initialize module e.f in c/d/e/f.py with simple_module template
+ '''
verbosity = 1 # required
description = "Render Pyramid scaffolding to an output directory"
usage = "usage: %prog [options] output_directory"
@@ -48,6 +55,10 @@ class PCreateCommand(object):
dest='overwrite',
action='store_true',
help='Always overwrite')
+ parser.add_option('-d', '--dir',
+ dest='output_dir',
+ action='store',
+ help='customized output dir. ')
parser.add_option('--interactive',
dest='interactive',
action='store_true',
@@ -75,18 +86,36 @@ def run(self):
return self.render_scaffolds()
def render_scaffolds(self):
+ '''
+ output_dir: the dir to render the templates
+ project_name: the name of the project to render,
+ as the basename of args[0]
+ pkg_name: the package to render, as the basename of args[0]
+ pkg_full_name: the full package name,
+ as args[0] with path separators replaced as dots.
+ safe_name: safe name of project_name for pkg_resources.
+ egg_name: egg name for pkg_resources.
+ '''
options = self.options
args = self.args
+ args[0] = self._set_args0(args[0])
output_dir = os.path.abspath(os.path.normpath(args[0]))
project_name = os.path.basename(os.path.split(output_dir)[1])
pkg_name = _bad_chars_re.sub('', project_name.lower())
+ pkg_full_name = self._set_pkg_full_name(args[0])
safe_name = pkg_resources.safe_name(project_name)
egg_name = pkg_resources.to_filename(safe_name)
+
+ if options.output_dir != None:
+ output_dir = self._set_output_dir(options.output_dir, args[0])
+
vars = {
'project': project_name,
'package': pkg_name,
+ 'package_full_name': pkg_full_name,
'egg': egg_name,
}
+
for scaffold_name in options.scaffold_name:
for scaffold in self.scaffolds:
if scaffold.name == scaffold_name:
@@ -123,5 +152,29 @@ def out(self, msg): # pragma: no cover
if not self.quiet:
print(msg)
+ def _set_args0(self, args0):
+ return args0.replace('.', os.path.sep)
+
+ def _set_pkg_full_name(self, pkg_path):
+ '''
+ 1. replace os.path.sep to dot.
+ 2. check there is no heading/trailing dot.
+ '''
+
+ pkg_full_name = pkg_path.replace(os.path.sep, '.')
+ pkg_full_name = pkg_full_name.strip('.')
+ return pkg_full_name
+
+ def _set_output_dir(self, dir_path, pkg_path):
+ dir_path = os.path.expanduser(dir_path)
+ if dir_path[0] == '~':
+ raise Exception('invalid user dir')
+
+ pkg_path = pkg_path.strip(os.path.sep)
+ full_path = os.path.join(dir_path, pkg_path)
+ output_path = os.path.abspath(os.path.normpath(full_path))
+ output_dir = os.path.dirname(output_path)
+ return output_dir
+
if __name__ == '__main__': # pragma: no cover
sys.exit(main() or 0)
View
13 pyramid/tests/test_scaffolds/test_init.py
@@ -7,20 +7,25 @@ def _makeOne(self):
def test_pre(self):
inst = self._makeOne()
- vars = {'package':'one'}
+ vars = {'package':'one', 'package_full_name': 'b.one'}
inst.pre('command', 'output dir', vars)
self.assertTrue(vars['random_string'])
self.assertEqual(vars['package_logger'], 'one')
+ self.assertEqual(vars['package_full_path'], 'b/one')
+ self.assertEqual(vars['package_parent_path'], 'b')
+ self.assertEqual(vars['package_root_name'], 'b')
def test_pre_site(self):
inst = self._makeOne()
- vars = {'package':'site'}
+ vars = {'package':'site', 'package_full_name': 'c.site'}
self.assertRaises(ValueError, inst.pre, 'command', 'output dir', vars)
def test_pre_root(self):
inst = self._makeOne()
- vars = {'package':'root'}
+ vars = {'package':'root', 'package_full_name': 'root'}
inst.pre('command', 'output dir', vars)
self.assertTrue(vars['random_string'])
self.assertEqual(vars['package_logger'], 'app')
-
+ self.assertEqual(vars['package_full_path'], 'root')
+ self.assertEqual(vars['package_parent_path'], '')
+ self.assertEqual(vars['package_root_name'], 'root')
View
238 pyramid/tests/test_scripts/test_pcreate.py
@@ -1,4 +1,5 @@
import unittest
+import os
class TestPCreateCommand(unittest.TestCase):
def setUp(self):
@@ -58,73 +59,262 @@ def test_unknown_scaffold_name(self):
def test_known_scaffold_single_rendered(self):
import os
- cmd = self._makeOne('-s', 'dummy', 'Distro')
+ cmd = self._makeOne('-s', 'dummy', 'distro')
scaffold = DummyScaffold('dummy')
cmd.scaffolds = [scaffold]
result = cmd.run()
self.assertEqual(result, 0)
self.assertEqual(
scaffold.output_dir,
- os.path.normpath(os.path.join(os.getcwd(), 'Distro'))
+ os.path.abspath(os.path.normpath('distro'))
)
self.assertEqual(
scaffold.vars,
- {'project': 'Distro', 'egg': 'Distro', 'package': 'distro'})
+ {
+ 'project': 'distro',
+ 'egg': 'distro',
+ 'package': 'distro',
+ 'package_full_name': 'distro'
+ })
- def test_known_scaffold_absolute_path(self):
+ def test_known_scaffold_multiple_rendered(self):
+ import os
+ cmd = self._makeOne('-s', 'dummy1', '-s', 'dummy2', 'distro')
+ scaffold1 = DummyScaffold('dummy1')
+ scaffold2 = DummyScaffold('dummy2')
+ cmd.scaffolds = [scaffold1, scaffold2]
+ result = cmd.run()
+ self.assertEqual(result, 0)
+ self.assertEqual(
+ scaffold1.output_dir,
+ os.path.abspath(os.path.normpath('distro'))
+ )
+ self.assertEqual(
+ scaffold1.vars,
+ {
+ 'project': 'distro',
+ 'egg': 'distro',
+ 'package': 'distro',
+ 'package_full_name': 'distro'
+ })
+ self.assertEqual(
+ scaffold2.output_dir,
+ os.path.abspath(os.path.normpath('distro'))
+ )
+ self.assertEqual(
+ scaffold2.vars,
+ {
+ 'project': 'distro',
+ 'egg': 'distro',
+ 'package': 'distro',
+ 'package_full_name': 'distro'
+ })
+
+ def test_customized_output_dir(self):
import os
- path = os.path.abspath('Distro')
- cmd = self._makeOne('-s', 'dummy', path)
+ path = 'dummy_customized'
+ cmd = self._makeOne('-s', 'dummy', '-d', path, 'distro')
scaffold = DummyScaffold('dummy')
cmd.scaffolds = [scaffold]
result = cmd.run()
+
self.assertEqual(result, 0)
self.assertEqual(
scaffold.output_dir,
- os.path.normpath(os.path.join(os.getcwd(), 'Distro'))
+ os.path.abspath(os.path.normpath(path))
)
self.assertEqual(
scaffold.vars,
- {'project': 'Distro', 'egg': 'Distro', 'package': 'distro'})
+ {
+ 'project': 'distro',
+ 'egg': 'distro',
+ 'package': 'distro',
+ 'package_full_name': 'distro'
+ })
- def test_known_scaffold_multiple_rendered(self):
+ def test_customized_output_dir_module(self):
import os
- cmd = self._makeOne('-s', 'dummy1', '-s', 'dummy2', 'Distro')
- scaffold1 = DummyScaffold('dummy1')
- scaffold2 = DummyScaffold('dummy2')
- cmd.scaffolds = [scaffold1, scaffold2]
+ path = 'dummy_customized2'
+ cmd = self._makeOne('-s', 'dummy', '-d', path, 'distro.distro2')
+ scaffold = DummyScaffold('dummy')
+ cmd.scaffolds = [scaffold]
result = cmd.run()
+
self.assertEqual(result, 0)
+ join_path = os.path.join(path, 'distro')
self.assertEqual(
- scaffold1.output_dir,
- os.path.normpath(os.path.join(os.getcwd(), 'Distro'))
+ scaffold.output_dir,
+ os.path.abspath(os.path.normpath(join_path))
)
self.assertEqual(
- scaffold1.vars,
- {'project': 'Distro', 'egg': 'Distro', 'package': 'distro'})
+ scaffold.vars,
+ {
+ 'project': 'distro2',
+ 'egg': 'distro2',
+ 'package': 'distro2',
+ 'package_full_name': 'distro.distro2'
+ })
+
+ def test_customized_output_dir_module_dir_based(self):
+ import os
+ path = 'dummy_customized'
+ cmd = self._makeOne('-s', 'dummy', '-d', path, 'distro/Test2')
+ scaffold = DummyScaffold('dummy')
+ cmd.scaffolds = [scaffold]
+ result = cmd.run()
+
+ self.assertEqual(result, 0)
+ join_path = os.path.join(path, 'distro')
self.assertEqual(
- scaffold2.output_dir,
- os.path.normpath(os.path.join(os.getcwd(), 'Distro'))
+ scaffold.output_dir,
+ os.path.abspath(os.path.normpath(join_path))
)
self.assertEqual(
- scaffold2.vars,
- {'project': 'Distro', 'egg': 'Distro', 'package': 'distro'})
+ scaffold.vars,
+ {
+ 'project': 'Test2',
+ 'egg': 'Test2',
+ 'package': 'test2',
+ 'package_full_name': 'distro.Test2'
+ })
+
+ def test_customized_output_dir_abspath(self):
+ import os
+ path = os.path.abspath('dummy_customized_abspath')
+ cmd = self._makeOne('-s', 'dummy', '-d', path, 'distro')
+ scaffold = DummyScaffold('dummy')
+ cmd.scaffolds = [scaffold]
+ result = cmd.run()
+
+ self.assertEqual(result, 0)
+ self.assertEqual(
+ scaffold.output_dir,
+ os.path.abspath(os.path.normpath(path))
+ )
+ self.assertEqual(
+ scaffold.vars,
+ {
+ 'project': 'distro',
+ 'egg': 'distro',
+ 'package': 'distro',
+ 'package_full_name': 'distro'
+ })
+
+ def test_customized_output_dir_home(self):
+ import os
+ path = "~"
+ cmd = self._makeOne('-s', 'dummy', '-d', path, 'distro')
+ scaffold = DummyScaffold('dummy')
+ cmd.scaffolds = [scaffold]
+ result = cmd.run()
+ user_path = os.path.expanduser('~')
+ self.assertEqual(result, 0)
+ self.assertEqual(
+ scaffold.output_dir,
+ os.path.abspath(os.path.normpath(user_path))
+ )
+
+ def test_customized_output_dir_root(self):
+ import os
+ path = "~root"
+ cmd = self._makeOne('-s', 'dummy', '-d', path, 'distro/Test2')
+ scaffold = DummyScaffold('dummy')
+ cmd.scaffolds = [scaffold]
+ result = cmd.run()
+ self.assertEqual(result, 0)
+ join_path = os.path.join(os.path.expanduser("~root"), 'distro')
+ self.assertEqual(
+ scaffold.output_dir,
+ os.path.abspath(os.path.normpath(join_path))
+ )
+ self.assertEqual(
+ scaffold.vars,
+ {
+ 'project': 'Test2',
+ 'egg': 'Test2',
+ 'package': 'test2',
+ 'package_full_name': 'distro.Test2'
+ })
+
+ def test_customized_output_dir_non_exist_user(self):
+ path = "~__pcreate_test_non_exist_user__"
+ cmd = self._makeOne('-s', 'dummy', '-d', path, 'distro')
+ scaffold = DummyScaffold('dummy')
+ cmd.scaffolds = [scaffold]
+ try:
+ cmd.run()
+ except Exception as e:
+ self.assertTrue(str(e) == 'invalid user dir')
def test_known_scaffold_with_path_as_project_target_rendered(self):
import os
- cmd = self._makeOne('-s', 'dummy', '/tmp/foo/Distro/')
+ cmd = self._makeOne('-s', 'dummy', '/tmp/foo/distro/')
scaffold = DummyScaffold('dummy')
cmd.scaffolds = [scaffold]
result = cmd.run()
self.assertEqual(result, 0)
self.assertEqual(
scaffold.output_dir,
- os.path.normpath(os.path.join(os.getcwd(), '/tmp/foo/Distro'))
+ os.path.abspath(os.path.normpath('/tmp/foo/distro'))
)
self.assertEqual(
scaffold.vars,
- {'project': 'Distro', 'egg': 'Distro', 'package': 'distro'})
+ {
+ 'project': 'distro',
+ 'egg': 'distro',
+ 'package': 'distro',
+ 'package_full_name': 'tmp.foo.distro'
+ })
+ def test__set_args0(self):
+ args0 = 'a.b.c.d'
+ cmd = self._makeOne('-s', 'dummy', args0)
+ result = cmd._set_args0(args0)
+ self.assertEqual(result, 'a/b/c/d')
+
+ def test__set_pkg_full_name(self):
+ pkg_path = 'a/b/c/d'
+ cmd = self._makeOne('-s', 'dummy', pkg_path)
+ pkg_full_name = cmd._set_pkg_full_name(pkg_path)
+ self.assertEqual(pkg_full_name, 'a.b.c.d')
+
+ def test__set_output_dir(self):
+ dir_path = 'a/b/c/d'
+ pkg_path = 'e/f'
+ cmd = self._makeOne('-s', 'dummy', '-d', dir_path, pkg_path)
+ output_dir = cmd._set_output_dir(dir_path, pkg_path)
+ assert output_dir == os.path.abspath('a/b/c/d/e')
+
+ dir_path = '~/a/b/c/d'
+ pkg_path = 'e/f'
+ cmd = self._makeOne('-s', 'dummy', '-d', dir_path, pkg_path)
+ output_dir = cmd._set_output_dir(dir_path, pkg_path)
+ join_path = os.path.join(os.path.expanduser('~'), 'a/b/c/d', 'e')
+ self.assertEqual(
+ output_dir,
+ os.path.abspath(os.path.normpath(join_path))
+ )
+
+ dir_path = '/a/b/c/d'
+ pkg_path = 'e/f'
+ cmd = self._makeOne('-s', 'dummy', '-d', dir_path, pkg_path)
+ output_dir = cmd._set_output_dir(dir_path, pkg_path)
+ join_path = os.path.join('/a/b/c/d', 'e')
+ self.assertEqual(
+ output_dir,
+ os.path.abspath(os.path.normpath(join_path))
+ )
+
+ dir_path = '/a/b/c/d/'
+ pkg_path = '/e/f/'
+ cmd = self._makeOne('-s', 'dummy', '-d', dir_path, pkg_path)
+ output_dir = cmd._set_output_dir(dir_path, pkg_path)
+ join_path = os.path.join('/a/b/c/d', 'e')
+ self.assertEqual(
+ output_dir,
+ os.path.abspath(os.path.normpath(join_path))
+ )
+
class Test_main(unittest.TestCase):
def _callFUT(self, argv):
from pyramid.scripts.pcreate import main
View
2  setup.py
@@ -106,6 +106,8 @@
starter=pyramid.scaffolds:StarterProjectTemplate
zodb=pyramid.scaffolds:ZODBProjectTemplate
alchemy=pyramid.scaffolds:AlchemyProjectTemplate
+ simple_module=pyramid.scaffolds:SimpleModuleTemplate
+ simple_pkg=pyramid.scaffolds:SimplePkgTemplate
[console_scripts]
pcreate = pyramid.scripts.pcreate:main
pserve = pyramid.scripts.pserve:main
Something went wrong with that request. Please try again.