Metadata-Version: 2.1
Name: gnar-gear
Version: 1.0.1
Summary: The gnarliest gear in the world 🤙
Home-page: https://gitlab.com/gnaar/gear
Author: Brien R. Givens
Author-email: ic3b3rg@gmail.com
License: MIT
Description: # Gnar Gear: Gnarly Python Apps
        
        [![MIT license](http://img.shields.io/badge/license-MIT-brightgreen.svg)](http://opensource.org/licenses/MIT)
        [![codecov](https://codecov.io/gl/gnaar/gear/branch/master/graph/badge.svg?token=MRowdXaujg)](https://codecov.io/gl/gnaar/gear)
        [![pipeline status](https://gitlab.com/gnaar/gear/badges/master/pipeline.svg)](https://gitlab.com/gnaar/gear/commits/master)
        [![Python versions](https://img.shields.io/pypi/pyversions/gnar-gear.svg)](https://pypi.python.org/pypi/gnar-gear)
        [![PyPI version](https://badge.fury.io/py/gnar-gear.svg)](https://badge.fury.io/py/gnar-gear)
        
        Sets up a powerful Flask-based Python service with two lines of code:
        
        ``` python
        from gnar_gear import GnarApp
        
        ...
        
        GnarApp('my_gnarly_app', production=True, port=80).run()
        ```
        
        ## Installation
        
        ``` bash
        pip3 install gnar_gear
        ```
        
        ## Feature List
        
        - Flask app with auto blueprint registration
        - [Bjoern WSGI Server](https://github.com/jonashaag/bjoern)
          - Why Bjoern? Check out [these benchmarks!](https://blog.appdynamics.com/engineering/a-performance-analysis-of-python-wsgi-servers-part-2/)
          - And also [these benchmarks](https://github.com/kubeup/python-wsgi-benchmark)
        - Postgres database connection via [Postgres.py](https://postgres-py.readthedocs.io/en/latest/#tutorial)
        - SES client connection via [Boto 3](https://boto3.readthedocs.io/en/latest/)
        - JWT configuration via [Flaks-JWT-Extended](http://flask-jwt-extended.readthedocs.io/en/latest/)
        - [Flask-Bcrypt](http://flask-bcrypt.readthedocs.io/en/latest/) singleton
        - Logger configuration
        - Error handler with traceback
        - Overridable and extendable class-based design
        
        ## Requirements
        
        ### Bjoern
        
        `Bjoern` requires `libev` (high performance event loop)
        - Install `libev` with `brew install libev` on Mac, or find your platform-specific installation command [here](https://github.com/jonashaag/bjoern/wiki/Installation#libev)
        
        ### Application Structure
        
        `GnarApp` expects to be instantiated in `main.py` at `<top-level-module>/app`, i.e. the minimum app folder structure is
        ```
        + <top-level-module>
            + app
                main.py
            __init__.py
        ```
        It is recommended (not required) to place your apis in segregated folders under `app` and the tests in a `test` folder under the `<top-level-module>`, e.g.
        ```
        + <top-level-module>
            + app
                + admin
                    apis.py
                    constants.py
                    services.py
                + user
                    apis.py
                    constants.py
                    services.py
                __init__.py
                main.py
            + test
                constants.py
                test_app.py
            __init__.py
        ```
        
        ### Blueprints
        
        Each [Flask `Blueprint`](http://flask.pocoo.org/docs/1.0/blueprints/) must be assigned to a global-level `blueprint` variable in its module, e.g.
        
        ``` python
        from flask import Blueprint, jsonify
        
        
        api_name = 'user'
        url_prefix = '/{}'.format(api_name)
        
        blueprint = Blueprint(api_name, __name__, url_prefix=url_prefix)
        ^^^^^^^^^
        
        @blueprint.route('/get', methods=['GET'])
        def user_get():
            return jsonify({'status': 'ok'})
        ```
        
        By default, the `GnarApp` picks up every `blueprint` in an auto-scan of the application code.
        
        ## Overview
        
        The `GnarApp` class provides a highly configurable, feature-rich, production-ready Flask-based app.
        
        ### Parameters
        
        #### Args (required)
        
        - *name*: The name of the application's top-level module
        - *production*: Boolean flag indicating whether or not the build is in production mode
        - *port*: The port to bind to the WSGI server
        
        #### Kwargs (optional)
        
        - *env_prefix*: Environment variable prefix (defaults to `GNAR`)
        - *log_level*: Log level override - see [configure_logger](#configure_logger) for log level overview
        - *blueprint_modules*: List of modules to find Flask blueprints (default is auto-scan)
        - *no_db*: Boolean flag - specify `True` if the app does not need a Postgres connection
        - *no_jwt*: Boolean flag - specify `True` if the app does not use JWT headers (i.e. non-api services)
        
        ### Overridable Behavior
        
        `GnarApp.run` simply calls a set of steps in the class. Here is an example of how to override any of the steps:
        
        ``` python
        def postconfig():
            log.info('My Postconfig Step!')
        
        ga = GnarApp('my_gnarly_app', production=True, port=80)
        ga.postconfig = postconfig
        ga.run()
        ```
        
        ### Run Steps
        The run steps rely on a set of [environment variables](#environment-variables) which use a configurable prefix
        (i.e. the `env_prefix` parameter). The default `env_prefix` is `GNAR`. An example of a Gnar environment variable
        using a custom prefix is `GnarApp( ..., env_prefix='MY_APP')` and then instead of reading `GNAR_LOG_LEVEL`, the
        `configure_logger` step will read `MY_APP_LOG_LEVEL`.
        
        #### preconfig
        
        - No default behavior - provided as an optional initial step in the app configuration.
        
        #### configure_flask
        
        - Attaches a `Flask` instance to the Gnar app.
        
        #### configure_logger
        
        - Attaches the root logger to `sys.stdout`.
        - Sets the logging level to the first defined:
          - `log_level` parameter
          - `GNAR_LOG_LEVEL` environment variable
          - `INFO`
          - Reminder: [Valid settings](https://docs.python.org/2/library/logging.html#logging-levels) (in increasing order of severity) are `DEBUG`, `INFO`, `WARNING`, `ERROR`, `CRITICAL`
        - Sets the log format to the first defined:
          - `GNAR_LOG_FORMAT`
          - `'%(asctime)s %(levelname)-8s %(name)s:%(lineno)d   %(message)s'`, e.g.:
          <pre>
          2018-07-09 15:41:46.420 INFO     gear.gnar_app:75   Logging at INFO
          </pre>
        - Sets the log format `default_msec_format` to the first defined:
          - `GNAR_LOG_FORMAT_MSEC`
          - `'%s.%03d'` (e.g. `.001`)
        
        #### configure_bcrypt
        
        - Attaches a `Bcrypt` singleton (for password hashing) to the Gnar app.
        - To hash a password using `Bcrypt`:
          ``` python
          from <top-level-module>.main import app
          hash = app.bcrypt.generate_password_hash(<plain text password>).decode('utf8')
          ```
          Note that this creates a [salted hash based on the Blowfish cipher](https://www.wikiwand.com/en/Bcrypt)
        - To validate a password with `Bcrypt`:
          ``` python
          from <top-level-module>.main import app
          is_valid = app.bcrypt.check_password_hash(<password hash from database>, <plain text password>)
          ```
        
        #### configure_database
        
        - Creates a Postgres database connection and attaches it to the Gnar app
        - Reads the following environment variables to set the `host`, `dbname`, `user`, `password` connection string parameters, respectively:
          - `GNAR_PG_ENDPOINT`
          - `GNAR_PG_DATABASE`
          - `GNAR_PG_USERNAME`
          - `GNAR_PG_PASSWORD`
        - Note: The [Postgres API](https://postgres-py.readthedocs.io/en/latest/#tutorial) primarily consists of `run`, `one`, and `all`
        
        #### attach_instance
        
        - Attaches the `GnarApp` instance to the `app.main` module. This enables easy access to the Gnar app from anywhere in the application using
          ``` python
          from <top-level-module>.main import app
          ```
        - The `GnarApp`'s runtime assets are `db`, `bcrypt`, `flask`, and `get_ses_client`
        - For example, to fetch one result (or `None`) from the database:
          ``` python
          app.db.one("SELECT * FROM foo WHERE bar='buz'")
          ```
        
        #### configure_blueprints
        
        - By default, `GnarApp` [auto-scans every Python module](#blueprints) under the `app` folder for blueprints.
        - Each [Flask `Blueprint`](http://flask.pocoo.org/docs/1.0/blueprints/) must be assigned to a global-level `blueprint` variable in its module.
        - If you prefer to skip the auto-scan, you can provide a list (or single string) of blueprint modules.
          - Each item in the list of module names may use one of two formats:
            - Without a `.` in the module name: `GnarApp` will look for the module in `<top-level-module>.app.<module name>.apis`
            - With a `.` in the module: `GnarApp` will look for the module in `<top-level-module>.app.<module name>`
        
        #### configure_errorhandler
        
        - Defines a generic (Exception-level) Flask error handler which:
          - Logs the error message and its `traceback` (format_exec)
          - Returns a 200-level json response containing `{"error": <error message>, "traceback": <traceback>}`
        
        #### configure_jwt
        
        - Sets the Flask `JWT_SECRET_KEY` variable to the value of the `GNAR_JWT_SECRET_KEY` environment variable.
        - Sets the Flask `JWT_ACCESS_TOKEN_EXPIRES` variable to the value of the `GNAR_JWT_ACCESS_TOKEN_EXPIRES_MINUTES` environment variable (default 5 mins).
        - Attaches a [JWTManager](http://flask-jwt-extended.readthedocs.io/en/latest/_modules/flask_jwt_extended/jwt_manager.html#JWTManager) instance to the `GnarApp`.
        - Defines functions for `expired_token_loader`, `invalid_token_loader`, and `unauthorized_loader` which return meaningful error messages as 200-level json responses containing `{"error": <error message>}`.
        
        #### configure_after_request
        
        - Adds a JWT Authorization header (Bearer token) to responses which received a valid JWT token in the request.
        - In non-production mode, adds CORS headers to the response (so that you don't need to bother with circumventing CORS in development).
        
        #### postconfig
        
        - No default behavior - provided as an optional initial step in the app configuration.
        
        ### Runtime Functionality
        
        #### get_ses_client
        
        - Exposed as runtime functionality (as opposed to creating the client at initialization) because AWS will close the client after a short period of time
        - Returns an SES connection (using boto3)
        - Reads the following environment variables to set the `region_name`, `aws_access_key_id`, and `aws_secret_access_key` parameters of the `boto3.client` call, respectively:
          - `GNAR_SES_REGION_NAME`
          - `GNAR_SES_ACCESS_KEY_ID`
          - `GNAR_SES_SECRET_ACCESS_KEY`
        - Usage:
          ``` python
          from <top-level-module>.main import app
          app.get_ses_client().send_email( ... )
          ```
        - See the [`Boto 3 Docs`](https://boto3.readthedocs.io/en/latest/reference/services/ses.html#SES.Client.send_email) for the `send_email` request syntax.
        
        ### Environment Variables
        
        - The environment variables (with configurable prefix) used by `GnarApp` are:
          - `GNAR_JWT_SECRET_KEY`
          - `GNAR_LOG_LEVEL`
          - `GNAR_PG_DATABASE`
          - `GNAR_PG_ENDPOINT`
          - `GNAR_PG_PASSWORD`
          - `GNAR_PG_USERNAME`
          - `GNAR_SES_ACCESS_KEY_ID`
          - `GNAR_SES_REGION_NAME`
          - `GNAR_SES_SECRET_ACCESS_KEY`
        - See the relevant sections above for details
        
        ---
        <div align="center">Made with ❤ by a Canadian living in Redwood City, California | Keep it Rad, friends 🤙</div>
        
Platform: UNKNOWN
Classifier: Development Status :: 5 - Production/Stable
Classifier: Intended Audience :: Developers
Classifier: Natural Language :: English
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.5
Classifier: Programming Language :: Python :: 3.6
Classifier: Programming Language :: Python :: 3.7
Classifier: Framework :: Flask
Description-Content-Type: text/markdown
