Skip to content

Commit

Permalink
Merge pull request #2984 from mmerickel/pserve-open-url
Browse files Browse the repository at this point in the history
pserve open_url config setting
  • Loading branch information
mmerickel authored Mar 29, 2017
2 parents 4415036 + 839dbff commit 126c635
Show file tree
Hide file tree
Showing 3 changed files with 91 additions and 21 deletions.
8 changes: 8 additions & 0 deletions CHANGES.txt
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,14 @@ Features
request that the policy may create more than one request for retry
purposes. See https://github.com/Pylons/pyramid/pull/2964

- Support an ``open_url`` config setting in the ``pserve`` section of the
config file. This url is used to open a web browser when ``pserve --browser``
is invoked. When this setting is unavailable the ``pserve`` script will
attempt to guess the port the server is using from the
``server:<server_name>`` section of the config file but there is no
requirement that the server is being run in this format so it may fail.
See https://github.com/Pylons/pyramid/pull/2984

Bug Fixes
---------

Expand Down
74 changes: 55 additions & 19 deletions pyramid/scripts/pserve.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,6 @@
loadapp,
loadserver,
)
from paste.deploy.loadwsgi import (
SERVER,
loadcontext,
)

from pyramid.compat import PY2
from pyramid.compat import configparser
Expand Down Expand Up @@ -87,7 +83,9 @@ class PServeCommand(object):
'-b', '--browser',
dest='browser',
action='store_true',
help="Open a web browser to server url")
help=("Open a web browser to the server url. The server url is "
"determined from the 'open_url' setting in the 'pserve' "
"section of the configuration file."))
parser.add_argument(
'-v', '--verbose',
default=default_verbosity,
Expand Down Expand Up @@ -119,6 +117,8 @@ class PServeCommand(object):
loadapp = staticmethod(loadapp) # testing
loadserver = staticmethod(loadserver) # testing

open_url = None

_scheme_re = re.compile(r'^[a-z][a-z]+:', re.I)

def __init__(self, argv, quiet=False):
Expand All @@ -127,7 +127,7 @@ def __init__(self, argv, quiet=False):
self.args.verbose = 0
if self.args.reload:
self.worker_kwargs = {'argv': argv, "quiet": quiet}
self.watch_files = []
self.watch_files = set()

def out(self, msg): # pragma: no cover
if self.args.verbose > 0:
Expand Down Expand Up @@ -161,7 +161,32 @@ def pserve_file_config(self, filename, global_conf=None):
file = resolver.resolve(file).abspath()
elif not os.path.isabs(file):
file = os.path.join(here, file)
self.watch_files.append(os.path.abspath(file))
self.watch_files.add(os.path.abspath(file))

# attempt to determine the url of the server
open_url = items.get('open_url')
if open_url:
self.open_url = open_url

def _guess_server_url(self, filename, server_name,
global_conf=None): # pragma: no cover
server_name = server_name or 'main'
here = os.path.abspath(os.path.dirname(filename))
defaults = {}
if global_conf:
defaults.update(global_conf)
defaults['here'] = here

config = self.ConfigParser(defaults=defaults)
config.optionxform = str
config.read(filename)
try:
items = dict(config.items('server:' + server_name))
except configparser.NoSectionError:
return

if 'port' in items:
return 'http://127.0.0.1:{port}'.format(**items)

def run(self): # pragma: no cover
if not self.args.config_uri:
Expand All @@ -188,16 +213,27 @@ def run(self): # pragma: no cover

# do not open the browser on each reload so check hupper first
if self.args.browser and not hupper.is_active():
def open_browser():
context = loadcontext(
SERVER, app_spec, name=server_name, relative_to=base,
global_conf=vars)
url = 'http://127.0.0.1:{port}/'.format(**context.config())
time.sleep(1)
webbrowser.open(url)
t = threading.Thread(target=open_browser)
t.setDaemon(True)
t.start()
self.pserve_file_config(config_path, global_conf=vars)
url = self.open_url

# do not guess the url if the server is sourced from a different
# location than the config_path
if not url and server_spec == app_spec:
url = self._guess_server_url(config_path, server_name, vars)

if not url:
self.out('WARNING: could not determine the server\'s url to '
'open the browser. To fix this set the "open_url" '
'setting in the [pserve] section of the '
'configuration file.')

else:
def open_browser():
time.sleep(1)
webbrowser.open(url)
t = threading.Thread(target=open_browser)
t.setDaemon(True)
t.start()

if self.args.reload and not hupper.is_active():
if self.args.verbose > 1:
Expand All @@ -213,11 +249,11 @@ def open_browser():
if config_path:
setup_logging(config_path, global_conf=vars)
self.pserve_file_config(config_path, global_conf=vars)
self.watch_files.append(config_path)
self.watch_files.add(config_path)

if hupper.is_active():
reloader = hupper.get_reloader()
reloader.watch_files(self.watch_files)
reloader.watch_files(list(self.watch_files))

server = self.loadserver(
server_spec, name=server_name, relative_to=base, global_conf=vars)
Expand Down
30 changes: 28 additions & 2 deletions pyramid/tests/test_scripts/test_pserve.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,11 +74,37 @@ def test_config_file_finds_watch_files(self):
'a': '1',
'here': os.path.abspath('/base'),
})
self.assertEqual(inst.watch_files, [
self.assertEqual(inst.watch_files, set([
os.path.abspath('/base/foo'),
os.path.abspath('/baz'),
os.path.abspath(os.path.join(here, '*.py')),
])
]))

def test_config_file_finds_open_url(self):
inst = self._makeOne('development.ini')
self.config_factory.items = [(
'open_url', 'http://127.0.0.1:8080/',
)]
inst.pserve_file_config('/base/path.ini', global_conf={'a': '1'})
self.assertEqual(self.config_factory.defaults, {
'a': '1',
'here': os.path.abspath('/base'),
})
self.assertEqual(inst.open_url, 'http://127.0.0.1:8080/')

def test__guess_server_url(self):
inst = self._makeOne('development.ini')
self.config_factory.items = [(
'port', '8080',
)]
url = inst._guess_server_url(
'/base/path.ini', 'main', global_conf={'a': '1'})
self.assertEqual(self.config_factory.defaults, {
'a': '1',
'here': os.path.abspath('/base'),
})
self.assertEqual(self.config_factory.parser.section, 'server:main')
self.assertEqual(url, 'http://127.0.0.1:8080')

def test_reload_call_hupper_with_correct_args(self):
from pyramid.scripts import pserve
Expand Down

0 comments on commit 126c635

Please sign in to comment.