From 2d82b8951f35a3478f584203191b82719d3ce030 Mon Sep 17 00:00:00 2001 From: Harsha Narayana Date: Sat, 15 Dec 2018 16:44:19 +0530 Subject: [PATCH] make release script black compliant and tweak documentation with indexing and format Signed-off-by: Harsha Narayana --- docs/index.rst | 12 +- docs/sanic/blueprints.md | 18 +-- docs/sanic/config.md | 53 ++++++--- docs/sanic/custom_protocol.md | 72 ------------ docs/sanic/custom_protocol.rst | 76 ++++++++++++ docs/sanic/extensions.md | 1 + docs/sanic/logging.md | 100 ---------------- docs/sanic/logging.rst | 103 ++++++++++++++++ docs/sanic/routing.md | 17 +-- docs/sanic/websocket.rst | 4 +- release.py | 207 +++++++++++++++++++++++---------- 11 files changed, 389 insertions(+), 274 deletions(-) delete mode 100644 docs/sanic/custom_protocol.md create mode 100644 docs/sanic/custom_protocol.rst delete mode 100644 docs/sanic/logging.md create mode 100644 docs/sanic/logging.rst diff --git a/docs/index.rst b/docs/index.rst index 10b9e9c166..dd4801c696 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -7,24 +7,24 @@ Guides :maxdepth: 2 sanic/getting_started - sanic/routing + sanic/config + sanic/logging sanic/request_data sanic/response + sanic/cookies + sanic/routing + sanic/blueprints sanic/static_files + sanic/versioning sanic/exceptions sanic/middleware - sanic/blueprints sanic/websocket - sanic/config - sanic/cookies sanic/decorators sanic/streaming sanic/class_based_views sanic/custom_protocol sanic/sockets sanic/ssl - sanic/logging - sanic/versioning sanic/debug_mode sanic/testing sanic/deploying diff --git a/docs/sanic/blueprints.md b/docs/sanic/blueprints.md index 9a47609c82..e38cf4b12a 100644 --- a/docs/sanic/blueprints.md +++ b/docs/sanic/blueprints.md @@ -118,9 +118,9 @@ app = Sanic(__name__) app.blueprint(api) ``` -## Using blueprints +## Using Blueprints -Blueprints have much the same functionality as an application instance. +Blueprints have almost the same functionality as an application instance. ### WebSocket routes @@ -201,7 +201,7 @@ async def close_connection(app, loop): Blueprints can be very useful for API versioning, where one blueprint may point at `/v1/`, and another pointing at `/v2/`. -When a blueprint is initialised, it can take an optional `url_prefix` argument, +When a blueprint is initialised, it can take an optional `version` argument, which will be prepended to all routes defined on the blueprint. This feature can be used to implement our API versioning scheme. @@ -210,8 +210,8 @@ can be used to implement our API versioning scheme. from sanic.response import text from sanic import Blueprint -blueprint_v1 = Blueprint('v1', url_prefix='/v1') -blueprint_v2 = Blueprint('v2', url_prefix='/v2') +blueprint_v1 = Blueprint('v1', url_prefix='/api', version="v1") +blueprint_v2 = Blueprint('v2', url_prefix='/api', version="v2") @blueprint_v1.route('/') async def api_v1_root(request): @@ -222,7 +222,7 @@ async def api_v2_root(request): return text('Welcome to version 2 of our documentation') ``` -When we register our blueprints on the app, the routes `/v1` and `/v2` will now +When we register our blueprints on the app, the routes `/v1/api` and `/v2/api` will now point to the individual blueprints, which allows the creation of *sub-sites* for each API version. @@ -232,8 +232,8 @@ from sanic import Sanic from blueprints import blueprint_v1, blueprint_v2 app = Sanic(__name__) -app.blueprint(blueprint_v1, url_prefix='/v1') -app.blueprint(blueprint_v2, url_prefix='/v2') +app.blueprint(blueprint_v1) +app.blueprint(blueprint_v2) app.run(host='0.0.0.0', port=8000, debug=True) ``` @@ -246,7 +246,7 @@ takes the format `.`. For example: ```python @blueprint_v1.route('/') async def root(request): - url = request.app.url_for('v1.post_handler', post_id=5) # --> '/v1/post/5' + url = request.app.url_for('v1.post_handler', post_id=5) # --> '/v1/api/post/5' return redirect(url) diff --git a/docs/sanic/config.md b/docs/sanic/config.md index 5f87348af1..4140559708 100644 --- a/docs/sanic/config.md +++ b/docs/sanic/config.md @@ -85,30 +85,53 @@ DB_USER = 'appuser' Out of the box there are just a few predefined values which can be overwritten when creating the application. - | Variable | Default | Description | - | ------------------------- | --------- | ------------------------------------------------------ | - | REQUEST_MAX_SIZE | 100000000 | How big a request may be (bytes) | + | Variable | Default | Description | + | ------------------------- | --------- | --------------------------------------------------------- | + | REQUEST_MAX_SIZE | 100000000 | How big a request may be (bytes) | | REQUEST_BUFFER_QUEUE_SIZE | 100 | Request streaming buffer queue size | - | REQUEST_TIMEOUT | 60 | How long a request can take to arrive (sec) | - | RESPONSE_TIMEOUT | 60 | How long a response can take to process (sec) | - | KEEP_ALIVE | True | Disables keep-alive when False | - | KEEP_ALIVE_TIMEOUT | 5 | How long to hold a TCP connection open (sec) | - | GRACEFUL_SHUTDOWN_TIMEOUT | 15.0 | How long take to force close non-idle connection (sec) | - | ACCESS_LOG | True | Disable or enable access log | + | REQUEST_TIMEOUT | 60 | How long a request can take to arrive (sec) | + | RESPONSE_TIMEOUT | 60 | How long a response can take to process (sec) | + | KEEP_ALIVE | True | Disables keep-alive when False | + | KEEP_ALIVE_TIMEOUT | 5 | How long to hold a TCP connection open (sec) | + | GRACEFUL_SHUTDOWN_TIMEOUT | 15.0 | How long to wait to force close non-idle connection (sec) | + | ACCESS_LOG | True | Disable or enable access log | ### The different Timeout variables: -A request timeout measures the duration of time between the instant when a new open TCP connection is passed to the Sanic backend server, and the instant when the whole HTTP request is received. If the time taken exceeds the `REQUEST_TIMEOUT` value (in seconds), this is considered a Client Error so Sanic generates a HTTP 408 response and sends that to the client. Adjust this value higher if your clients routinely pass very large request payloads or upload requests very slowly. +#### `REQUEST_TIMEOUT` -A response timeout measures the duration of time between the instant the Sanic server passes the HTTP request to the Sanic App, and the instant a HTTP response is sent to the client. If the time taken exceeds the `RESPONSE_TIMEOUT` value (in seconds), this is considered a Server Error so Sanic generates a HTTP 503 response and sets that to the client. Adjust this value higher if your application is likely to have long-running process that delay the generation of a response. +A request timeout measures the duration of time between the instant when a new open TCP connection is passed to the +Sanic backend server, and the instant when the whole HTTP request is received. If the time taken exceeds the +`REQUEST_TIMEOUT` value (in seconds), this is considered a Client Error so Sanic generates an `HTTP 408` response +and sends that to the client. Set this parameter's value higher if your clients routinely pass very large request payloads +or upload requests very slowly. -### What is Keep Alive? And what does the Keep Alive Timeout value do? +#### `RESPONSE_TIMEOUT` -Keep-Alive is a HTTP feature indroduced in HTTP 1.1. When sending a HTTP request, the client (usually a web browser application) can set a Keep-Alive header to indicate for the http server (Sanic) to not close the TCP connection after it has send the response. This allows the client to reuse the existing TCP connection to send subsequent HTTP requests, and ensures more efficient network traffic for both the client and the server. +A response timeout measures the duration of time between the instant the Sanic server passes the HTTP request to the +Sanic App, and the instant a HTTP response is sent to the client. If the time taken exceeds the `RESPONSE_TIMEOUT` +value (in seconds), this is considered a Server Error so Sanic generates an `HTTP 503` response and sends that to the +client. Set this parameter's value higher if your application is likely to have long-running process that delay the +generation of a response. -The `KEEP_ALIVE` config variable is set to `True` in Sanic by default. If you don't need this feature in your application, set it to `False` to cause all client connections to close immediately after a response is sent, regardless of the Keep-Alive header on the request. +#### `KEEP_ALIVE_TIMEOUT` -The amount of time the server holds the TCP connection open is decided by the server itself. In Sanic, that value is configured using the `KEEP_ALIVE_TIMEOUT` value. By default, it is set to 5 seconds, this is the same default setting as the Apache HTTP server and is a good balance between allowing enough time for the client to send a new request, and not holding open too many connections at once. Do not exceed 75 seconds unless you know your clients are using a browser which supports TCP connections held open for that long. +##### What is Keep Alive? And what does the Keep Alive Timeout value do? + +`Keep-Alive` is a HTTP feature introduced in `HTTP 1.1`. When sending a HTTP request, the client (usually a web browser application) +can set a `Keep-Alive` header to indicate the http server (Sanic) to not close the TCP connection after it has send the response. +This allows the client to reuse the existing TCP connection to send subsequent HTTP requests, and ensures more efficient +network traffic for both the client and the server. + +The `KEEP_ALIVE` config variable is set to `True` in Sanic by default. If you don't need this feature in your application, +set it to `False` to cause all client connections to close immediately after a response is sent, regardless of +the `Keep-Alive` header on the request. + +The amount of time the server holds the TCP connection open is decided by the server itself. +In Sanic, that value is configured using the `KEEP_ALIVE_TIMEOUT` value. By default, it is set to 5 seconds. +This is the same default setting as the Apache HTTP server and is a good balance between allowing enough time for +the client to send a new request, and not holding open too many connections at once. Do not exceed 75 seconds unless +you know your clients are using a browser which supports TCP connections held open for that long. For reference: ``` diff --git a/docs/sanic/custom_protocol.md b/docs/sanic/custom_protocol.md deleted file mode 100644 index 8355e8e9d3..0000000000 --- a/docs/sanic/custom_protocol.md +++ /dev/null @@ -1,72 +0,0 @@ -# Custom Protocols - -*Note: this is advanced usage, and most readers will not need such functionality.* - -You can change the behavior of Sanic's protocol by specifying a custom -protocol, which should be a subclass -of -[asyncio.protocol](https://docs.python.org/3/library/asyncio-protocol.html#protocol-classes). -This protocol can then be passed as the keyword argument `protocol` to the `sanic.run` method. - -The constructor of the custom protocol class receives the following keyword -arguments from Sanic. - -- `loop`: an `asyncio`-compatible event loop. -- `connections`: a `set` to store protocol objects. When Sanic receives - `SIGINT` or `SIGTERM`, it executes `protocol.close_if_idle` for all protocol - objects stored in this set. -- `signal`: a `sanic.server.Signal` object with the `stopped` attribute. When - Sanic receives `SIGINT` or `SIGTERM`, `signal.stopped` is assigned `True`. -- `request_handler`: a coroutine that takes a `sanic.request.Request` object - and a `response` callback as arguments. -- `error_handler`: a `sanic.exceptions.Handler` which is called when exceptions - are raised. -- `request_timeout`: the number of seconds before a request times out. -- `request_max_size`: an integer specifying the maximum size of a request, in bytes. - -## Example - -An error occurs in the default protocol if a handler function does not return -an `HTTPResponse` object. - -By overriding the `write_response` protocol method, if a handler returns a -string it will be converted to an `HTTPResponse object`. - -```python -from sanic import Sanic -from sanic.server import HttpProtocol -from sanic.response import text - -app = Sanic(__name__) - - -class CustomHttpProtocol(HttpProtocol): - - def __init__(self, *, loop, request_handler, error_handler, - signal, connections, request_timeout, request_max_size): - super().__init__( - loop=loop, request_handler=request_handler, - error_handler=error_handler, signal=signal, - connections=connections, request_timeout=request_timeout, - request_max_size=request_max_size) - - def write_response(self, response): - if isinstance(response, str): - response = text(response) - self.transport.write( - response.output(self.request.version) - ) - self.transport.close() - - -@app.route('/') -async def string(request): - return 'string' - - -@app.route('/1') -async def response(request): - return text('response') - -app.run(host='0.0.0.0', port=8000, protocol=CustomHttpProtocol) -``` diff --git a/docs/sanic/custom_protocol.rst b/docs/sanic/custom_protocol.rst new file mode 100644 index 0000000000..daf35b5df9 --- /dev/null +++ b/docs/sanic/custom_protocol.rst @@ -0,0 +1,76 @@ +Custom Protocols +================ + +.. note:: + + This is advanced usage, and most readers will not need such functionality. + +You can change the behavior of Sanic's protocol by specifying a custom +protocol, which should be a subclass +of `asyncio.protocol `_. +This protocol can then be passed as the keyword argument ``protocol`` to the ``sanic.run`` method. + +The constructor of the custom protocol class receives the following keyword +arguments from Sanic. + +- ``loop``: an ``asyncio``-compatible event loop. +- ``connections``: a ``set`` to store protocol objects. When Sanic receives + ``SIGINT`` or ``SIGTERM``, it executes ``protocol.close_if_idle`` for all protocol + objects stored in this set. +- ``signal``: a ``sanic.server.Signal`` object with the ``stopped`` attribute. When + Sanic receives ``SIGINT`` or ``SIGTERM``, ``signal.stopped`` is assigned ``True``. +- ``request_handler``: a coroutine that takes a ``sanic.request.Request`` object + and a ``response`` callback as arguments. +- ``error_handler``: a ``sanic.exceptions.Handler`` which is called when exceptions + are raised. +- ``request_timeout``: the number of seconds before a request times out. +- ``request_max_size``: an integer specifying the maximum size of a request, in bytes. + +Example +------- + +An error occurs in the default protocol if a handler function does not return +an ``HTTPResponse`` object. + +By overriding the ``write_response`` protocol method, if a handler returns a +string it will be converted to an ``HTTPResponse object``. + +.. code:: python + + from sanic import Sanic + from sanic.server import HttpProtocol + from sanic.response import text + + app = Sanic(__name__) + + + class CustomHttpProtocol(HttpProtocol): + + def __init__(self, *, loop, request_handler, error_handler, + signal, connections, request_timeout, request_max_size): + super().__init__( + loop=loop, request_handler=request_handler, + error_handler=error_handler, signal=signal, + connections=connections, request_timeout=request_timeout, + request_max_size=request_max_size) + + def write_response(self, response): + if isinstance(response, str): + response = text(response) + self.transport.write( + response.output(self.request.version) + ) + self.transport.close() + + + @app.route('/') + async def string(request): + return 'string' + + + @app.route('/1') + async def response(request): + return text('response') + + app.run(host='0.0.0.0', port=8000, protocol=CustomHttpProtocol) + diff --git a/docs/sanic/extensions.md b/docs/sanic/extensions.md index 4ee873c93b..7a5a7b915d 100644 --- a/docs/sanic/extensions.md +++ b/docs/sanic/extensions.md @@ -11,6 +11,7 @@ A list of Sanic extensions created by the community. ## Security - [Sanic JWT](https://github.com/ahopkins/sanic-jwt): Authentication, JWT, and permission scoping for Sanic. +- [Secure](https://github.com/cakinney/secure): Secure 🔒 is a lightweight package that adds optional security headers and cookie attributes for Python web frameworks. - [Sessions](https://github.com/subyraman/sanic_session): Support for sessions. Allows using redis, memcache or an in memory store. - [CORS](https://github.com/ashleysommer/sanic-cors): A port of flask-cors. - [Sanic-JWT-Extended](https://github.com/devArtoria/Sanic-JWT-Extended): Provides extended JWT support for diff --git a/docs/sanic/logging.md b/docs/sanic/logging.md deleted file mode 100644 index e1231eb9b1..0000000000 --- a/docs/sanic/logging.md +++ /dev/null @@ -1,100 +0,0 @@ -# Logging - - -Sanic allows you to do different types of logging (access log, error log) on the requests based on the [python3 logging API](https://docs.python.org/3/howto/logging.html). You should have some basic knowledge on python3 logging if you want to create a new configuration. - -### Quick Start - -A simple example using default settings would be like this: - -```python -from sanic import Sanic -from sanic.log import logger -from sanic.response import text - -app = Sanic('test') - -@app.route('/') -async def test(request): - logger.info('Here is your log') - return text('Hello World!') - -if __name__ == "__main__": - app.run(debug=True, access_log=True) -``` - -After the server is running, you can see some messages looks like: -``` -[2018-11-06 21:16:53 +0800] [24622] [INFO] Goin' Fast @ http://127.0.0.1:8000 -[2018-11-06 21:16:53 +0800] [24667] [INFO] Starting worker [24667] -``` - -You can send a request to server and it will print the log messages: -``` -[2018-11-06 21:18:53 +0800] [25685] [INFO] Here is your log -[2018-11-06 21:18:53 +0800] - (sanic.access)[INFO][127.0.0.1:57038]: GET http://localhost:8000/ 200 12 -``` - -To use your own logging config, simply use `logging.config.dictConfig`, or -pass `log_config` when you initialize `Sanic` app: - -```python -app = Sanic('test', log_config=LOGGING_CONFIG) -``` - -And to close logging, simply assign access_log=False: - -```python -if __name__ == "__main__": - app.run(access_log=False) -``` - -This would skip calling logging functions when handling requests. -And you could even do further in production to gain extra speed: - -```python -if __name__ == "__main__": - # disable debug messages - app.run(debug=False, access_log=False) -``` - -### Configuration - -By default, log_config parameter is set to use sanic.log.LOGGING_CONFIG_DEFAULTS dictionary for configuration. - -There are three `loggers` used in sanic, and **must be defined if you want to create your own logging configuration**: - -- sanic.root:
- Used to log internal messages. - -- sanic.error:
- Used to log error logs. - -- sanic.access:
- Used to log access logs. - -#### Log format: - -In addition to default parameters provided by python (asctime, levelname, message), -Sanic provides additional parameters for access logger with: - -- host (str)
- request.ip - - -- request (str)
- request.method + " " + request.url - - -- status (int)
- response.status - - -- byte (int)
- len(response.body) - - -The default access log format is -```python -%(asctime)s - (%(name)s)[%(levelname)s][%(host)s]: %(request)s %(message)s %(status)d %(byte)d -``` diff --git a/docs/sanic/logging.rst b/docs/sanic/logging.rst new file mode 100644 index 0000000000..1e76a84dc0 --- /dev/null +++ b/docs/sanic/logging.rst @@ -0,0 +1,103 @@ +Logging +======= + +Sanic allows you to do different types of logging (access log, error +log) on the requests based on the `python3 logging API`_. You should +have some basic knowledge on python3 logging if you want to create a new +configuration. + +Quick Start +~~~~~~~~~~~ + +A simple example using default settings would be like this: + +.. code:: python + + from sanic import Sanic + from sanic.log import logger + from sanic.response import text + + app = Sanic('test') + + @app.route('/') + async def test(request): + logger.info('Here is your log') + return text('Hello World!') + + if __name__ == "__main__": + app.run(debug=True, access_log=True) + +After the server is running, you can see some messages looks like: + +:: + + [2018-11-06 21:16:53 +0800] [24622] [INFO] Goin' Fast @ http://127.0.0.1:8000 + [2018-11-06 21:16:53 +0800] [24667] [INFO] Starting worker [24667] + +You can send a request to server and it will print the log messages: + +:: + + [2018-11-06 21:18:53 +0800] [25685] [INFO] Here is your log + [2018-11-06 21:18:53 +0800] - (sanic.access)[INFO][127.0.0.1:57038]: GET http://localhost:8000/ 200 12 + +To use your own logging config, simply use +``logging.config.dictConfig``, or pass ``log_config`` when you +initialize ``Sanic`` app: + +.. code:: python + + app = Sanic('test', log_config=LOGGING_CONFIG) + +And to close logging, simply assign access_log=False: + +.. code:: python + + if __name__ == "__main__": + app.run(access_log=False) + +This would skip calling logging functions when handling requests. And +you could even do further in production to gain extra speed: + +.. code:: python + + if __name__ == "__main__": + # disable debug messages + app.run(debug=False, access_log=False) + +Configuration +~~~~~~~~~~~~~ + +By default, ``log_config`` parameter is set to use +``sanic.log.LOGGING_CONFIG_DEFAULTS`` dictionary for configuration. + +There are three ``loggers`` used in sanic, and **must be defined if you +want to create your own logging configuration**: + +================ ============================== +Logger Name Usecase +================ ============================== +``sanic.root`` Used to log internal messages. +``sanic.error`` Used to log error logs. +``sanic.access`` Used to log access logs. +================ ============================== + +Log format: +^^^^^^^^^^^ + +In addition to default parameters provided by python (``asctime``, +``levelname``, ``message``), Sanic provides additional parameters for +access logger with: + +===================== ========================================== ======== +Log Context Parameter Parameter Value Datatype +===================== ========================================== ======== +``host`` ``request.ip`` str +``request`` ``request.method`` + " " + ``request.url`` str +``status`` ``response.status`` int +``byte`` ``len(response.body)`` int +===================== ========================================== ======== + +The default access log format is ``%(asctime)s - (%(name)s)[%(levelname)s][%(host)s]: %(request)s %(message)s %(status)d %(byte)d`` + +.. _python3 logging API: https://docs.python.org/3/howto/logging.html \ No newline at end of file diff --git a/docs/sanic/routing.md b/docs/sanic/routing.md index e9cb0aefef..54ea56a680 100644 --- a/docs/sanic/routing.md +++ b/docs/sanic/routing.md @@ -164,24 +164,24 @@ url = app.url_for('post_handler', post_id=5, arg_one='one', arg_two='two') url = app.url_for('post_handler', post_id=5, arg_one=['one', 'two']) # /posts/5?arg_one=one&arg_one=two ``` -- Also some special arguments (`_anchor`, `_external`, `_scheme`, `_method`, `_server`) passed to `url_for` will have special url building (`_method` is not support now and will be ignored). For example: +- Also some special arguments (`_anchor`, `_external`, `_scheme`, `_method`, `_server`) passed to `url_for` will have special url building (`_method` is not supported now and will be ignored). For example: ```python url = app.url_for('post_handler', post_id=5, arg_one='one', _anchor='anchor') # /posts/5?arg_one=one#anchor url = app.url_for('post_handler', post_id=5, arg_one='one', _external=True) # //server/posts/5?arg_one=one -# _external requires passed argument _server or SERVER_NAME in app.config or url will be same as no _external +# _external requires you to pass an argument _server or set SERVER_NAME in app.config if not url will be same as no _external url = app.url_for('post_handler', post_id=5, arg_one='one', _scheme='http', _external=True) # http://server/posts/5?arg_one=one # when specifying _scheme, _external must be True -# you can pass all special arguments one time +# you can pass all special arguments at once url = app.url_for('post_handler', post_id=5, arg_one=['one', 'two'], arg_two=2, _anchor='anchor', _scheme='http', _external=True, _server='another_server:8888') # http://another_server:8888/posts/5?arg_one=one&arg_one=two&arg_two=2#anchor ``` -- All valid parameters must be passed to `url_for` to build a URL. If a parameter is not supplied, or if a parameter does not match the specified type, a `URLBuildError` will be thrown. +- All valid parameters must be passed to `url_for` to build a URL. If a parameter is not supplied, or if a parameter does not match the specified type, a `URLBuildError` will be raised. ## WebSocket routes @@ -209,7 +209,7 @@ async def feed(request, ws): app.add_websocket_route(my_websocket_handler, '/feed') ``` -Handlers for a WebSocket route are passed the request as first argument, and a +Handlers to a WebSocket route are invoked with the request as first argument, and a WebSocket protocol object as second argument. The protocol object has `send` and `recv` methods to send and receive data respectively. @@ -243,7 +243,8 @@ app.blueprint(bp) ## User defined route name -You can pass `name` to change the route name to avoid using the default name (`handler.__name__`). +A custom route name can be used by passing a `name` argument while registering the route which will +override the default route name generated using the `handler.__name__` attribute. ```python @@ -305,8 +306,8 @@ def handler(request): ## Build URL for static files -You can use `url_for` for static file url building now. -If it's for file directly, `filename` can be ignored. +Sanic supports using `url_for` method to build static file urls. In case if the static url +is pointing to a directory, `filename` parameter to the `url_for` can be ignored. q ```python diff --git a/docs/sanic/websocket.rst b/docs/sanic/websocket.rst index 133e73da5d..3d00a70976 100644 --- a/docs/sanic/websocket.rst +++ b/docs/sanic/websocket.rst @@ -1,7 +1,7 @@ WebSocket ========= -Sanic supports websockets, to setup a WebSocket: +Sanic provides an easy to user abstraction on top of `websockets`. To setup a WebSocket: .. code:: python @@ -35,7 +35,7 @@ decorator: app.add_websocket_route(feed, '/feed') -Handlers for a WebSocket route are passed the request as first argument, and a +Handlers for a WebSocket route is invoked with the request as first argument, and a WebSocket protocol object as second argument. The protocol object has ``send`` and ``recv`` methods to send and receive data respectively. diff --git a/release.py b/release.py index 080932b5f1..e24bac80b7 100755 --- a/release.py +++ b/release.py @@ -14,13 +14,22 @@ GIT_COMMANDS = { "get_tag": ["git describe --tags --abbrev=0"], "commit_version_change": [ - "git add . && git commit -m 'Bumping up version from {current_version} to {new_version}'"], - "create_new_tag": ["git tag -a {new_version} -m 'Bumping up version from {current_version} to {new_version}'"], + "git add . && git commit -m 'Bumping up version from " + "{current_version} to {new_version}'" + ], + "create_new_tag": [ + "git tag -a {new_version} -m 'Bumping up version from " + "{current_version} to {new_version}'" + ], "push_tag": ["git push origin {new_version}"], - "get_change_log": ['git log --no-merges --pretty=format:"%h::: %cn::: %s" {current_version}..'] + "get_change_log": [ + 'git log --no-merges --pretty=format:"%h::: %cn::: %s" ' + "{current_version}.." + ], } -RELASE_NOTE_TEMPLATE = """ + +RELEASE_NOTE_TEMPLATE = """ # {{ release_name }} - {% now 'utc', '%Y-%m-%d' %} To see the exhaustive list of pull requests included in this release see: @@ -37,23 +46,25 @@ {% endfor %} """ -JINJA_RELASE_NOTE_TEMPLATE = Environment( - loader=BaseLoader, extensions=['jinja2_time.TimeExtension']).from_string(RELASE_NOTE_TEMPLATE) +JINJA_RELEASE_NOTE_TEMPLATE = Environment( + loader=BaseLoader, extensions=["jinja2_time.TimeExtension"] +).from_string(RELEASE_NOTE_TEMPLATE) -RELEASE_NOTE_UPDATE_URL = \ - "https://api.github.com/repos/huge-success/sanic/releases/tags/{new_version}?access_token={token}" +RELEASE_NOTE_UPDATE_URL = ( + "https://api.github.com/repos/huge-success/sanic/releases/tags/" + "{new_version}?access_token={token}" +) def _run_shell_command(command: list): try: - process = Popen(command, stderr=PIPE, stdout=PIPE, stdin=PIPE, - shell=True) + process = Popen( + command, stderr=PIPE, stdout=PIPE, stdin=PIPE, shell=True + ) output, error = process.communicate() return_code = process.returncode return output.decode("utf-8"), error, return_code except: - import traceback - traceback.print_exc() return None, None, -1 @@ -66,7 +77,10 @@ def _fetch_current_version(config_file: str) -> str: config_parser = RawConfigParser() with open(config_file) as cfg: config_parser.read_file(cfg) - return config_parser.get("version", "current_version") or _fetch_default_calendar_release_version() + return ( + config_parser.get("version", "current_version") + or _fetch_default_calendar_release_version() + ) else: return _fetch_default_calendar_release_version() @@ -77,8 +91,11 @@ def _change_micro_version(current_version: str): return ".".join(version_string) -def _get_new_version(config_file: str = "./setup.cfg", current_version: str = None, - micro_release: bool = False): +def _get_new_version( + config_file: str = "./setup.cfg", + current_version: str = None, + micro_release: bool = False, +): if micro_release: if current_version: return _change_micro_version(current_version) @@ -100,16 +117,21 @@ def _get_current_tag(git_command_name="get_tag"): return None -def _update_release_version_for_sanic(current_version, new_version, config_file): +def _update_release_version_for_sanic( + current_version, new_version, config_file +): config_parser = RawConfigParser() with open(config_file) as cfg: config_parser.read_file(cfg) config_parser.set("version", "current_version", new_version) version_file = config_parser.get("version", "file") - current_version_line = config_parser.get("version", "current_version_pattern").format( - current_version=current_version) - new_version_line = config_parser.get("version", "new_version_pattern").format(new_version=new_version) + current_version_line = config_parser.get( + "version", "current_version_pattern" + ).format(current_version=current_version) + new_version_line = config_parser.get( + "version", "new_version_pattern" + ).format(new_version=new_version) with open(version_file) as init_file: data = init_file.read() @@ -122,10 +144,16 @@ def _update_release_version_for_sanic(current_version, new_version, config_file) config_parser.write(config) command = GIT_COMMANDS.get("commit_version_change") - command[0] = command[0].format(new_version=new_version, current_version=current_version) + command[0] = command[0].format( + new_version=new_version, current_version=current_version + ) _, err, ret = _run_shell_command(command) if int(ret) != 0: - print("Failed to Commit Version upgrade changes to Sanic: {}".format(err.decode("utf-8"))) + print( + "Failed to Commit Version upgrade changes to Sanic: {}".format( + err.decode("utf-8") + ) + ) exit(1) @@ -144,20 +172,25 @@ def _generate_change_log(current_version: str = None): for line in str(output).split("\n"): commit, author, description = line.split(":::") - if 'GitHub' not in author: + if "GitHub" not in author: commit_details["authors"][author] = 1 commit_details["commits"].append(" - ".join([commit, description])) return commit_details -def _generate_markdown_document(milestone, release_name, current_version, release_version): - global JINJA_RELASE_NOTE_TEMPLATE +def _generate_markdown_document( + milestone, release_name, current_version, release_version +): + global JINJA_RELEASE_NOTE_TEMPLATE release_name = release_name or release_version change_log = _generate_change_log(current_version=current_version) - return JINJA_RELASE_NOTE_TEMPLATE.render( - release_name=release_name, milestone=milestone, changelogs=change_log["commits"], - authors=change_log["authors"].keys()) + return JINJA_RELEASE_NOTE_TEMPLATE.render( + release_name=release_name, + milestone=milestone, + changelogs=change_log["commits"], + authors=change_log["authors"].keys(), + ) def _tag_release(new_version, current_version, milestone, release_name, token): @@ -165,25 +198,27 @@ def _tag_release(new_version, current_version, milestone, release_name, token): global RELEASE_NOTE_UPDATE_URL for command_name in ["create_new_tag", "push_tag"]: command = GIT_COMMANDS.get(command_name) - command[0] = command[0].format(new_version=new_version, current_version=current_version) + command[0] = command[0].format( + new_version=new_version, current_version=current_version + ) out, error, ret = _run_shell_command(command=command) if int(ret) != 0: print("Failed to execute the command: {}".format(command[0])) exit(1) - change_log = _generate_markdown_document(milestone, release_name, current_version, new_version) + change_log = _generate_markdown_document( + milestone, release_name, current_version, new_version + ) - body = { - "name": release_name or new_version, - "body": change_log - } + body = {"name": release_name or new_version, "body": change_log} - headers = { - "content-type": "application/json" - } + headers = {"content-type": "application/json"} - response = patch(RELEASE_NOTE_UPDATE_URL.format(new_version=new_version, token=token), - data=dumps(body), headers=headers) + response = patch( + RELEASE_NOTE_UPDATE_URL.format(new_version=new_version, token=token), + data=dumps(body), + headers=headers, + ) response.raise_for_status() @@ -191,31 +226,79 @@ def release(args: Namespace): current_tag = _get_current_tag() current_version = _fetch_current_version(args.config) if current_tag and current_version not in current_tag: - print("Tag mismatch between what's in git and what was provided by --current-version. " - "Existing: {}, Give: {}".format(current_tag, current_version)) + print( + "Tag mismatch between what's in git and what was provided by " + "--current-version. Existing: {}, Give: {}".format( + current_tag, current_version + ) + ) exit(1) - new_version = args.release_version or _get_new_version(args.config, current_version, args.micro_release) - _update_release_version_for_sanic(current_version=current_version, new_version=new_version, config_file=args.config) - _tag_release(current_version=current_version, new_version=new_version, - milestone=args.milestone, release_name=args.release_name, token=args.token) - - -if __name__ == '__main__': + new_version = args.release_version or _get_new_version( + args.config, current_version, args.micro_release + ) + _update_release_version_for_sanic( + current_version=current_version, + new_version=new_version, + config_file=args.config, + ) + _tag_release( + current_version=current_version, + new_version=new_version, + milestone=args.milestone, + release_name=args.release_name, + token=args.token, + ) + + +if __name__ == "__main__": cli = ArgumentParser(description="Sanic Release Manager") - cli.add_argument("--release-version", "-r", help="New Version to use for Release", - default=_fetch_default_calendar_release_version(), - required=False) - cli.add_argument("--current-version", "-cv", help="Current Version to default in case if you don't want to " - "use the version configuration files", - default=None, required=False) - cli.add_argument("--config", "-c", help="Configuration file used for release", default="./setup.cfg", - required=False) - cli.add_argument("--token", "-t", help="Git access token with necessary access to Huge Sanic Org", - required=True) - cli.add_argument("--milestone", "-ms", help="Git Release milestone information to include in relase note", - required=True) - cli.add_argument("--release-name", "-n", help="Release Name to use if any", required=False) - cli.add_argument("--micro-release", "-m", help="Micro Release with patches only", - default=False, action='store_true', required=False) + cli.add_argument( + "--release-version", + "-r", + help="New Version to use for Release", + default=_fetch_default_calendar_release_version(), + required=False, + ) + cli.add_argument( + "--current-version", + "-cv", + help="Current Version to default in case if you don't want to " + "use the version configuration files", + default=None, + required=False, + ) + cli.add_argument( + "--config", + "-c", + help="Configuration file used for release", + default="./setup.cfg", + required=False, + ) + cli.add_argument( + "--token", + "-t", + help="Git access token with necessary access to Huge Sanic Org", + required=True, + ) + cli.add_argument( + "--milestone", + "-ms", + help="Git Release milestone information to include in relase note", + required=True, + ) + cli.add_argument( + "--release-name", + "-n", + help="Release Name to use if any", + required=False, + ) + cli.add_argument( + "--micro-release", + "-m", + help="Micro Release with patches only", + default=False, + action="store_true", + required=False, + ) args = cli.parse_args() release(args)