A minimal, extensible, fast and productive API framework for Python 3.

Overview
Comments
  • Can't find the wsgi wrapper programatically

    Can't find the wsgi wrapper programatically

    Checklist

    • [x] Does your title concisely summarize the problem?
    • [x] Did you include a minimal, reproducible example?
    • [x] What OS are you using?
    • [x] What version of molten are you using?
    • [x] What did you do?
    • [x] What did you expect would happen?
    • [x] What happened?

    What OS are you using?

    macOS 10.13.6

    What version of molten are you using?

    molten==0.4.1

    What did you do?

    I'm using the serverless framework to deploy an API to AWS lambda. It has a function call -- serve -- that is expecting to find a wsgi app.

    With flask this "just works" (i.e. default supported framework for most of these easy-of-use frameworks like zappa or serverless).

    You can see that the serve function call isn't very complex other than some monkey patching.

    # serve.py
    def serve(cwd, app, port, host="localhost"):
        sys.path.insert(0, cwd)
    
        os.environ["IS_OFFLINE"] = "True"
    
        print(app)
        wsgi_fqn = app.rsplit(".", 1)
        print(wsgi_fqn)
        wsgi_fqn_parts = wsgi_fqn[0].rsplit("/", 1)
        print(wsgi_fqn_parts)
        if len(wsgi_fqn_parts) == 2:
            sys.path.insert(0, os.path.join(cwd, wsgi_fqn_parts[0]))
        wsgi_module = importlib.import_module(wsgi_fqn_parts[-1])
        print(wsgi_module)
        wsgi_app = getattr(wsgi_module, wsgi_fqn[1])
    
        # Attempt to force Flask into debug mode
        try:
            wsgi_app.debug = True
        except:  # noqa: E722
            pass
    
        serving.run_simple(
            host,
            int(port),
            wsgi_app,
            use_debugger=True,
            use_reloader=True,
            use_evalex=True,
            threaded=True,
        )
    

    This works with flask. It also works with the hug but it's not strait forward. With that I have to point serverless explicitly at the wisgi "magic method": __hug_wsgi__.

    Digging through hug I see where the http.server is added into the app singleton.

    What did you expect would happen?

    Ideally, the molten app instance would caugh up wsgi as simply as flask but even if it were like hug that would work. I'm open to other options.

    I was able to get werkzeug to serve molten like this:

    if __name__ == '__main__':
        from werkzeug import serving
    
        serving.run_simple('127.0.0.1', 8888, app)
    

    What happened?

    Right now I'm unable to find something suitable in molten to pass to pass into werkzeug so at present I can't host molten inside serverless.

    opened by dgonzo 7
  • Ability to test api with Swagger UI to upload file/s

    Ability to test api with Swagger UI to upload file/s

    As discussed on the reddit thread there is issue with current swagger api generation. It does shows the content type option as multipart/form-data but doesn't give option to browse and upload the file.

    It might be related to the missing format: binary option as mentioned in https://swagger.io/docs/specification/describing-request-body/file-upload/

    What version of molten are you using?

    0.7.1

    bug 
    opened by gurvindersingh 6
  • fix(validation): accept null for optional union types.

    fix(validation): accept null for optional union types.

    Validating a field that is an optional union will fail when the value is null:

    >>> field = Field(annotation=Optional[Union[int,str]])
    >>> field.select_validator()
    >>> field.validate(None)
    ---------------------------------------------------------------------------
    
    molten/validation/field.py in validate(self, value)
        181         if value is None:
        182             if not is_optional:
    --> 183                 raise FieldValidationError("this field cannot be null")
        184
        185             return value
    
    FieldValidationError: this field cannot be null
    

    The cause of this is that when determining if a field is optional in is_optional_annotation the simply checks the second argument of the Union.

    This works when the annotation is Optional[X] which expands to Union[X, NoneType] but not, for instance, with Optional[Union[X, Y]] which expands to Union[X, Y, NoneType].

    We could check the last argument to Union but that would still fail on the, slightly more contrived, example of Union[Optional[X], Y] which expands to Union[X, NoneType, Y] and for which null would be perfectly valid.

    Therefore, in this implementation, is_optional_annotation is dropped as that involves iterating over the arguments to determine if one is NoneType and we also need to iterate over the arguments in extract_optional_annotation to produce the "inner annotation" so I do both in the same place now instead. is_optional_annotation is not referenced anywhere else in the project, but as this affects what is possibly the external API this is possibly a breaking change.

    Adds tests for the examples in test_fields.py.

    BREAKING CHANGE: removes is_optional_annotation from molten.typing

    opened by edwardgeorge 4
  • User guide example fails on Windows with ModuleNotFoundError: No module named 'fcntl'

    User guide example fails on Windows with ModuleNotFoundError: No module named 'fcntl'

    Issues

    I am following the user guide hello-world and it fails. https://moltenframework.com/guide.html#hello-world I am on Windows10 git bash.

    The fcntl module is not available on Windows. The functionality it exposes does not exist on that platform.

    $ pip freeze
    atomicwrites==1.3.0
    attrs==19.3.0
    cachetools==3.1.1
    certifi==2019.9.11
    chardet==3.0.4
    colorama==0.4.1
    coverage==4.5.4
    google-api-core==1.14.3
    google-api-python-client==1.7.11
    google-auth==1.6.3
    google-auth-httplib2==0.0.3
    google-cloud-bigquery==1.21.0
    google-cloud-core==1.0.3
    google-resumable-media==0.4.1
    googleapis-common-protos==1.6.0
    gunicorn==19.9.0
    httplib2==0.14.0
    idna==2.8
    importlib-metadata==0.23
    molten==0.7.4
    more-itertools==7.2.0
    mypy-extensions==0.4.3
    pluggy==0.13.0
    protobuf==3.10.0
    py==1.8.0
    pyasn1==0.4.7
    pyasn1-modules==0.2.7
    pytest==3.8.1
    pytest-cov==2.6.0
    python-dateutil==2.7.3
    pytz==2019.3
    requests==2.22.0
    rsa==4.0
    six==1.11.0
    typing-extensions==3.7.4
    typing-inspect==0.3.1
    uritemplate==3.0.0
    urllib3==1.25.6
    wsgicors==0.7.0
    zipp==0.6.
    

    app.py

    from molten import App, Route
    
    def hello(name: str) -> str:
        return f"Hello {name}!"
    
    app = App(routes=[Route("/hello/{name}", hello)])
    

    Using Molten 0.74. on Windows 10 64bit.

    What version of molten are you using?

    python -c 'import molten; print(molten.version)' 0.7.4

    What did you do?

     gunicorn --reload app:app
    Traceback (most recent call last):
      File "C:\Program Files\Python37\lib\runpy.py", line 193, in _run_module_as_main
        "__main__", mod_spec)
      File "C:\Program Files\Python37\lib\runpy.py", line 85, in _run_code
        exec(code, run_globals)
      File "C:\yarrascrapy\yarraplanning\yarraheritagemaps\server\Scripts\gunicorn.exe\__main__.py", line 4, in <module>
      File "c:\yarrascrapy\yarraplanning\yarraheritagemaps\server\lib\site-packages\gunicorn\app\wsgiapp.py", line 9, in <module>
        from gunicorn.app.base import Application
      File "c:\yarrascrapy\yarraplanning\yarraheritagemaps\server\lib\site-packages\gunicorn\app\base.py", line 12, in <module>  
        from gunicorn import util
      File "c:\yarrascrapy\yarraplanning\yarraheritagemaps\server\lib\site-packages\gunicorn\util.py", line 9, in <module>       
        import fcntl
    ModuleNotFoundError: No module named 'fcntl'
    (server) 
    

    I think its related to this issue

    What did you expect would happen?

    It would work on Windows python dev environment.

    What happened?

    It didn't run. I don't know how to fix it.

    opened by intotecho 2
  • [FEATURE REQUEST] dataclass support

    [FEATURE REQUEST] dataclass support

    PEP 557 dataclass fields support a metadata parameter that can hold arbitrary field metadata.

    It seems that could be used by molten's schema decorator on dataclasses to construct molten Fields from dataclasses who's fields include the necessary metadata parameters.

    I'd be happy to spend some time with the code base to submit a PR myself, but I raise the issue in case you get to it before I do, or in case you have any suggestions :)

    opened by knowsuchagency 2
  • APIKeySecuritySchema not functioning in openapi docs

    APIKeySecuritySchema not functioning in openapi docs

    Checklist

    • [x] Does your title concisely summarize the problem?
    • [x] Did you include a minimal, reproducible example?
    • [x] What OS are you using?
    • [x] What version of molten are you using?
    • [x] What did you do?
    • [x] What did you expect would happen?
    • [x] What happened?

    What OS are you using?

    macOS 10.13.6

    What version of molten are you using?

    0.5.2

    What did you do?

    I enabled APIKeySecurityScheme in the petstore example using the following modified petstore.app (see both variations of security_schemes):

    """An example **molten** application that automatically exposes an
    OpenAPI document to represent its structure.
    """
    from typing import Any, Callable, Optional, Tuple
    
    from molten import (
        App, Header, Include, ResponseRendererMiddleware, Route, annotate,
        Request, HTTP_200, HTTPError, HTTP_401)
    from molten.openapi import Metadata, OpenAPIHandler, OpenAPIUIHandler, APIKeySecurityScheme
    
    from . import categories, pets, tags
    from .database import DatabaseComponent
    
    
    def auth_middleware(handler: Callable[..., Any]) -> Callable[..., Any]:
        def middleware(x_api_key: Optional[Header]) -> Callable[..., Any]:
            if x_api_key == '58be92dd-61a9-4a27-8efa-b6a0e025439e' or getattr(handler, "no_auth", False):
                return handler()
            else:
                raise HTTPError(HTTP_401, {"error": "bad credentials"})
    
        return middleware
    
    
    def u(request: Request) -> Tuple[str, dict]:
        return HTTP_200, {"req": f"{request.headers!r}"}
    
    
    def setup_app():
        get_schema = OpenAPIHandler(
            metadata=Metadata(
                title="Pet Store",
                description=__doc__,
                version="0.0.0",
            ),
            # Option 1
            security_schemes=[APIKeySecurityScheme(name="X-API-KEY", in_="header")],
            # Option 2
            security_schemes=[APIKeySecurityScheme(name="apiKey", in_="header")],
            default_security_scheme="apiKey",
        )
    
        get_schema = annotate(no_auth=True)(get_schema)
        get_docs = annotate(no_auth=True)(OpenAPIUIHandler())
    
        return App(
            components=[
                DatabaseComponent(),
                categories.CategoryManagerComponent(),
                tags.TagManagerComponent(),
                pets.PetManagerComponent(),
            ],
    
            middleware=[
                ResponseRendererMiddleware(),
                auth_middleware,
            ],
    
            routes=[
                Include("/v1/categories", categories.routes),
                Include("/v1/pets", pets.routes),
                Include("/v1/tags", tags.routes),
                Route("/u", u),
    
                Route("/_docs", get_docs),
                Route("/_schema", get_schema),
            ],
        )
    
    

    What did you expect would happen?

    For either "Option 1" or "Option 2" above I expected that the apiKey would be used to authenticate calls to secure routes. Instead 'X-API-KEY' is absent from the headers and a "bad credentials" error is returned.

    Option 1 results in an empty "Authorizers available" dialogue box when clicking on the lock icon for a path but I'd expect that dialogue to offer a place to put the "X-API-KEY". The main authorize box does offer the expected dialogue box but it is not applied when executing calls from the docs.

    Option 2 results in the expected dialogue boxes but the apiKey is not applied to calls to routes.

    When I exercise the api outside of swagger (e.g. http :8000/v1/categories X-API-KEY:58be92dd-61a9-4a27-8efa-b6a0e025439e) authentication functions properly. So, only within swagger is the header not being properly applied.

    What happened?

    I noticed that the security schemes in openapi have, effectively, two names. The name of the security and the name of the header:

    components:
      securitySchemes:
        ApiKeyAuth:        # arbitrary name for the security scheme
          type: apiKey
          in: header       # can be "header", "query" or "cookie"
          name: X-API-KEY  # name of the header, query parameter or cookie
    

    When the arbitraty name is "apiKey" the dialogue boxes in the docs function as expected.

    To get the arbitrary name set in APIKeySecurityScheme the name attribute must be set to "apiKey" but that results in an incorrect header name.

    bug 
    opened by dgonzo 2
  • Calling generate_openapi_document fail when using a method as handler

    Calling generate_openapi_document fail when using a method as handler

    The following line

    https://github.com/Bogdanp/molten/blob/ef09cd96188b0bc04526a9c26ce26ce31909b406/molten/openapi/documents.py#L170

    should probably be replaced by

    if not isinstance(handler, (FunctionType, MethodType)):
    
    bug 
    opened by nicolas-leydet 2
  • A schema's field cannot be of type List[str]

    A schema's field cannot be of type List[str]

    What OS are you using?

    SLED 12.3

    What version of molten are you using?

    0.50

    What did you do?

    Use the following Schema as an handler return annotation

    @schema
    class SearchResult:
        results: List[str]
    

    What did you expect would happen?

    No error

    What happened?

    File "~/.virtualenvs/matching/lib/python3.7/site-packages/molten/openapi/documents.py", line 239, in generate_openapi_document
        response_schema_name = _generate_schema("response", response_annotation, schemas)
      File "~/.virtualenvs/matching/lib/python3.7/site-packages/molten/openapi/documents.py", line 319, in _generate_schema
        is_optional, field_schema = _generate_field_schema(field, context, schemas)
      File "~/.virtualenvs/matching/lib/python3.7/site-packages/molten/openapi/documents.py", line 345, in _generate_field_schema
        item_schema_name = _generate_schema(context, arguments[0], schemas)
      File "~/.virtualenvs/matching/lib/python3.7/site-packages/molten/openapi/documents.py", line 303, in _generate_schema
        for field in schema._FIELDS.values():  # noqa
    AttributeError: 'function' object has no attribute '_FIELDS'
    

    this is not valid if you use anything else than a schema as List argument

    bug 
    opened by nicolas-leydet 2
  • Adding support for a status, content, headers return type to ResponseMiddleware and Renders

    Adding support for a status, content, headers return type to ResponseMiddleware and Renders

    Checklist

    • [x] Does your title concisely summarize the problem?
    • [ ] ~~Did you include a minimal, reproducible example?~~
    • [x] What OS are you using?
    • [x] What version of molten are you using?
    • [x] What did you do?
    • [x] What did you expect would happen?
    • [x] What happened?

    What OS are you using?

    MacOS 10.13.6

    What version of molten are you using?

    0.4.1

    What did you do?

    I attempted to return a tuple from my handler containing a status code, payload to be serialized, and response headers.

    What did you expect would happen?

    I expected the ResponseRendererMiddleware to select an appropriate Render based on the request Accept header. The selected Render would then construct a Response object with the status, serialized payload, and response headers with the appropriate Content Type added to my own response headers.

    What happened?

    ValueError: too many values to unpack (expected 2)

    enhancement 
    opened by androiddrew 2
  • Importing molten.openapi raise a RecursionError exception

    Importing molten.openapi raise a RecursionError exception

    Environment

    • SUSE Linux Enterprise Desktop 12 SP3
    • Python 3.6.0
    • molten 0.2.1

    What did you do?

    bug.py

    import molten.openapi
    

    $ python bug.py

    What did you expect would happen?

    Do nothing but with no error

    What happened?

    Traceback (most recent call last):
      File "simple_app.py", line 1, in <module>
        import molten.openapi
      File "~/.virtualenvs/molten-test/lib/python3.6/site-packages/molten/openapi/__init__.py", line 18, in <module>
        from .documents import (
      File "~/.virtualenvs/molten-test/lib/python3.6/site-packages/molten/openapi/documents.py", line 78, in <module>
        @schema
      File "~/.virtualenvs/molten-test/lib/python3.6/site-packages/molten/validation/schema.py", line 83, in schema
        field.select_validator()
      File "~/.virtualenvs/molten-test/lib/python3.6/site-packages/molten/validation/field.py", line 143, in select_validator
        self.validator = _select_validator(self)
      File "~/.virtualenvs/molten-test/lib/python3.6/site-packages/molten/validation/field.py", line 466, in _select_validator
        if validator.can_validate_field(field):
      File "~/.virtualenvs/molten-test/lib/python3.6/site-packages/molten/validation/field.py", line 288, in can_validate_field
        return get_origin(annotation) in (list, List)
      File "/usr/local/lib/python3.6/typing.py", line 760, in __eq__
        return self._subs_tree() == other
      File "/usr/local/lib/python3.6/typing.py", line 760, in __eq__
        return self._subs_tree() == other
      File "/usr/local/lib/python3.6/typing.py", line 760, in __eq__
        return self._subs_tree() == other
      [Previous line repeated 240 more times]
      File "/usr/local/lib/python3.6/typing.py", line 759, in __eq__
        if not isinstance(other, _Union):
    RecursionError: maximum recursion depth exceeded while calling a Python object
    
    wontfix 
    opened by nicolas-leydet 2
  • Shouldn't the URI be 127.0.0.1 instead of 127.1?

    Shouldn't the URI be 127.0.0.1 instead of 127.1?

    FILE : https://github.com/Bogdanp/molten/blob/master/docs/source/guide.rst

    Example :

    `If you then make a curl request to 127.1:8000/hello/Jim you'll get back a JSON response containing the string "Hello Jim!":

    $ curl 127.1:8000/hello/Jim "Hello Jim"`

    question 
    opened by abhi-jha 2
  • better parsing of  docstrings

    better parsing of docstrings

    I was frusterated by my IDE, which attempts to helpfully provide sphinx parameter definitions in any docstrings, which caused the openapi spec docs to look funny. i have been using a version with these changes for a while, and decided they might be useful to others

    Im not sure if this is the appropriate place but this (or if it belongs more on annotation or something?)

    ignores parameter specifications in docstrings

    attempts to split the docstring into both a summary as well as a description.

    I also would like to propose allowing example as an argument to field() (not in this merge request) as it is a valid openapi specification for parameters

    opened by joranbeasley 1
  • openapi: support required fields read/writeOnly

    openapi: support required fields read/writeOnly

    The OpenAPI spec 3.0.0 specifies the following for read/writeOnly schema properties :

    readOnly: If the property is marked as readOnly being true and is in
    the required list, the required will take effect on the response
    only.
    

    This justifies adding a required argument on Field. Indeed this may be useful to API clients to know that the field will always be present in the response even if in python its type is Optional due to reuse of the schema for request and response.

    opened by sebdiem 2
  • Simple OpenAPI doubt

    Simple OpenAPI doubt

    Hello! Firstly, I would like to thank you for developing such a cool project.

    I would like to ask if there is any way to add openAPI specification elements such as tag summaries or action summaries/descriptions in molten.

    If there is no such capability it would be a good addition for future versions.

    Many thanks in advance.

    enhancement 
    opened by DNCoelho 1
Releases(v1.0.2)
bottle.py is a fast and simple micro-framework for python web-applications.

Bottle: Python Web Framework Bottle is a fast, simple and lightweight WSGI micro web-framework for Python. It is distributed as a single file module a

Bottle Micro Web Framework 7.8k Dec 31, 2022
A microservice written in Python detecting nudity in images/videos

py-nudec py-nudec (python nude detector) is a microservice, which scans all the images and videos from the multipart/form-data request payload and sen

Michael Grigoryan 8 Jul 09, 2022
Flask like web framework for AWS Lambda

lambdarest Python routing mini-framework for AWS Lambda with optional JSON-schema validation. ⚠️ A user study is currently happening here, and your op

sloev / Johannes Valbjørn 91 Nov 10, 2022
Daniel Vaz Gaspar 4k Jan 08, 2023
Official mirror of https://gitlab.com/pgjones/quart

Quart Quart is an async Python web microframework. Using Quart you can, render and serve HTML templates, write (RESTful) JSON APIs, serve WebSockets,

Phil Jones 2 Oct 05, 2022
The no-nonsense, minimalist REST and app backend framework for Python developers, with a focus on reliability, correctness, and performance at scale.

The Falcon Web Framework Falcon is a reliable, high-performance Python web framework for building large-scale app backends and microservices. It encou

Falconry 9k Jan 01, 2023
An effective, simple, and async security library for the Sanic framework.

Sanic Security An effective, simple, and async security library for the Sanic framework. Table of Contents About the Project Getting Started Prerequis

Sunset Dev 72 Nov 30, 2022
Chisel is a light-weight Python WSGI application framework built for creating well-documented, schema-validated JSON web APIs

chisel Chisel is a light-weight Python WSGI application framework built for creating well-documented, schema-validated JSON web APIs. Here are its fea

Craig Hobbs 2 Dec 02, 2021
A comprehensive reference for all topics related to building and maintaining microservices

This pandect (πανδέκτης is Ancient Greek for encyclopedia) was created to help you find and understand almost anything related to Microservices that i

Ivan Bilan 64 Dec 09, 2022
JustPy is an object-oriented, component based, high-level Python Web Framework

JustPy Docs and Tutorials Introduction JustPy is an object-oriented, component based, high-level Python Web Framework that requires no front-en

927 Jan 08, 2023
Web3.py plugin for using Flashbots' bundle APIs

This library works by injecting a new module in the Web3.py instance, which allows submitting "bundles" of transactions directly to miners. This is do

Flashbots 293 Dec 31, 2022
A framework that let's you compose websites in Python with ease!

Perry Perry = A framework that let's you compose websites in Python with ease! Perry works similar to Qt and Flutter, allowing you to create componen

Linkus 13 Oct 09, 2022
Full duplex RESTful API for your asyncio web apps

TBone TBone makes it easy to develop full-duplex RESTful APIs on top of your asyncio web application or webservice. It uses a nonblocking asynchronous

TBone Framework 37 Aug 07, 2022
Bromelia-hss implements an HSS by using the Python micro framework Bromélia.

Bromélia HSS bromelia-hss is the second official implementation of a Diameter-based protocol application by using the Python micro framework Bromélia.

henriquemr 7 Nov 02, 2022
FPS, fast pluggable server, is a framework designed to compose and run a web-server based on plugins.

FPS, fast pluggable server, is a framework designed to compose and run a web-server based on plugins. It is based on top of fastAPI, uvicorn, typer, and pluggy.

Adrien Delsalle 1 Nov 16, 2021
web.py is a web framework for python that is as simple as it is powerful.

web.py is a web framework for Python that is as simple as it is powerful. Visit http://webpy.org/ for more information. The latest stable release 0.62

5.8k Dec 30, 2022
A Flask API REST to access words' definition

A Flask API to access words' definitions

Pablo Emídio S.S 9 Jul 22, 2022
Pretty tornado wrapper for making lightweight REST API services

CleanAPI Pretty tornado wrapper for making lightweight REST API services Installation: pip install cleanapi Example: Project folders structure: . ├──

Vladimir Kirievskiy 26 Sep 11, 2022
Dockerized web application on Starlite, SQLAlchemy1.4, PostgreSQL

Production-ready dockerized async REST API on Starlite with SQLAlchemy and PostgreSQL

Artur Shiriev 10 Jan 03, 2023
Flask Sugar is a web framework for building APIs with Flask, Pydantic and Python 3.6+ type hints.

Flask Sugar is a web framework for building APIs with Flask, Pydantic and Python 3.6+ type hints. check parameters and generate API documents automatically. Flask Sugar是一个基于flask,pyddantic,类型注解的API框架

162 Dec 26, 2022