School/IKEA_scraper/.venv/Lib/site-packages/snakeviz/cli.py
Kristofers Solo 2b19d56787 venv update
2021-09-19 12:05:06 +03:00

170 lines
5.7 KiB
Python

"""
This module contains the command line interface for snakeviz.
"""
from __future__ import print_function
import argparse
import os
import random
import socket
import sys
import threading
import webbrowser
from pstats import Stats
try:
from urllib.parse import quote
except ImportError:
from urllib import quote
from . import version
# As seen in IPython:
# https://github.com/ipython/ipython/blob/8be7f9abd97eafb493817371d70101d28640919c/IPython/html/notebookapp.py
# See the IPython license at:
# https://github.com/ipython/ipython/blob/master/COPYING.rst.
def random_ports(port, n):
"""Generate a list of n random ports near the given port.
The first 5 ports will be sequential, and the remaining n-5 will be
randomly selected in the range [port-2*n, port+2*n].
"""
for i in range(min(5, n)):
yield port + i
for i in range(n-5):
yield max(1, port + random.randint(-2*n, 2*n))
class SVArgumentParser(argparse.ArgumentParser):
def error(self, message):
message = message + '\n\n' + self.format_help()
args = {'prog': self.prog, 'message': message}
self.exit(2, '%(prog)s: error: %(message)s' % args)
def build_parser():
parser = SVArgumentParser(
description='Start SnakeViz to view a Python profile.')
parser.add_argument('filename', help='Python profile to view')
parser.add_argument('-v', '--version', action='version',
version=('%(prog)s ' + version.version))
parser.add_argument('-H', '--hostname', metavar='ADDR', default='127.0.0.1',
help='hostname to bind to (default: %(default)s)')
parser.add_argument('-p', '--port', type=int, metavar='PORT', default=8080,
help='port to bind to; if this port is already in use a '
'free port will be selected automatically '
'(default: %(default)s)')
parser.add_argument('-b', '--browser', metavar='BROWSER_PATH',
help='name of webbrowser to launch as described in '
'the documentation of Python\'s webbrowser module: '
'https://docs.python.org/3/library/webbrowser.html')
parser.add_argument('-s', '--server', action="store_true", default=False,
help='start SnakeViz in server-only mode--'
'no attempt will be made to open a browser')
return parser
def main(argv=None):
parser = build_parser()
args = parser.parse_args(argv)
if args.browser and args.server:
parser.error("options --browser and --server are mutually exclusive")
filename = os.path.abspath(args.filename)
if not os.path.exists(filename):
parser.error('the path %s does not exist' % filename)
if not os.path.isdir(filename):
try:
open(filename)
except IOError as e:
parser.error('the file %s could not be opened: %s'
% (filename, str(e)))
try:
Stats(filename)
except Exception:
parser.error(('The file %s is not a valid profile. ' % filename) +
'Generate profiles using: \n\n'
'\tpython -m cProfile -o my_program.prof my_program.py\n\n'
'Note that snakeviz must be run under the same '
'version of Python as was used to create the profile.\n')
filename = quote(filename, safe='')
hostname = args.hostname
port = args.port
if not 0 <= port <= 65535:
parser.error('invalid port number %d: use a port between 0 and 65535'
% port)
# Before starting tornado set the eventloop policy for windows and python 3.8 compatibility
# https://github.com/tornadoweb/tornado/issues/2608
if sys.platform == 'win32' and sys.version_info[:2] == (3, 8):
import asyncio
asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())
# Go ahead and import the tornado app and start it; we do an inline import
# here to avoid the extra overhead when just running the cli for --help and
# the like
from .main import app
import tornado.ioloop
# As seen in IPython:
# https://github.com/ipython/ipython/blob/8be7f9abd97eafb493817371d70101d28640919c/IPython/html/notebookapp.py
# See the IPython license at:
# https://github.com/ipython/ipython/blob/master/COPYING.rst.
for p in random_ports(port, 10):
try:
app.listen(p, address=hostname)
except socket.error as e:
print('Port {0} in use, trying another.'.format(p))
else:
port = p
break
else:
print('No available port found.')
return 1
url = "http://{0}:{1}/snakeviz/{2}".format(hostname, port, filename)
print(('snakeviz web server started on %s:%d; enter Ctrl-C to exit' %
(hostname, port)))
print(url)
if not args.server:
try:
browser = webbrowser.get(args.browser)
except webbrowser.Error as e:
parser.error('no web browser found: %s' % e)
# Launch the browser in a separate thread to avoid blocking the
# ioloop from starting
def bt():
browser.open(url, new=2)
threading.Thread(target=bt).start()
try:
tornado.ioloop.IOLoop.instance().start()
except KeyboardInterrupt:
# TODO: Cheap KeyboardInterrupt handler for now; iPython has some nicer
# stuff for handling SIGINT and SIGTERM that might be worth borrowing
tornado.ioloop.IOLoop.instance().stop()
print('\nBye!')
return 0
if __name__ == '__main__':
sys.exit(main())