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)
Async Python 3.6+ web server/framework | Build fast. Run fast.

Sanic | Build fast. Run fast. Build Docs Package Support Stats Sanic is a Python 3.6+ web server and web framework that's written to go fast. It allow

Sanic Community Organization 16.7k Jan 8, 2023
Async Python 3.6+ web server/framework | Build fast. Run fast.

Sanic | Build fast. Run fast. Build Docs Package Support Stats Sanic is a Python 3.6+ web server and web framework that's written to go fast. It allow

Sanic Community Organization 16.7k Dec 28, 2022
Fully featured framework for fast, easy and documented API development with Flask

Flask RestPlus IMPORTANT NOTICE: This project has been forked to Flask-RESTX and will be maintained by by the python-restx organization. Flask-RESTPlu

Axel H. 2.7k Jan 4, 2023
Fully featured framework for fast, easy and documented API development with Flask

Flask RestPlus IMPORTANT NOTICE: This project has been forked to Flask-RESTX and will be maintained by by the python-restx organization. Flask-RESTPlu

Axel H. 2.5k Feb 17, 2021
Bionic is Python Framework for crafting beautiful, fast user experiences for web and is free and open source

Bionic is fast. It's powered core python without any extra dependencies. Bionic offers stateful hot reload, allowing you to make changes to your code and see the results instantly without restarting your app or losing its state.

 ⚓ 0 Mar 5, 2022
Fast, asynchronous and elegant Python web framework.

Warning: This project is being completely re-written. If you're curious about the progress, reach me on Slack. Vibora is a fast, asynchronous and eleg

vibora.io 5.7k Jan 8, 2023
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
Fast⚡, simple and light💡weight ASGI micro🔬 web🌏-framework for Python🐍.

NanoASGI Asynchronous Python Web Framework NanoASGI is a fast ⚡ , simple and light ?? weight ASGI micro ?? web ?? -framework for Python ?? . It is dis

Kavindu Santhusa 8 Jun 16, 2022
TinyAPI - 🔹 A fast & easy and lightweight WSGI Framework for Python

TinyAPI - ?? A fast & easy and lightweight WSGI Framework for Python

xArty 3 Apr 8, 2022
Appier is an object-oriented Python web framework built for super fast app development.

Joyful Python Web App development Appier is an object-oriented Python web framework built for super fast app development. It's as lightweight as possi

Hive Solutions 122 Dec 22, 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
FastAPI framework, high performance, easy to learn, fast to code, ready for production

FastAPI framework, high performance, easy to learn, fast to code, ready for production Documentation: https://fastapi.tiangolo.com Source Code: https:

Sebastián Ramírez 53k Jan 2, 2023
Django Ninja - Fast Django REST Framework

Django Ninja is a web framework for building APIs with Django and Python 3.6+ type hints.

Vitaliy Kucheryaviy 3.8k Jan 2, 2023
Lemon is an async and lightweight API framework for python

Lemon is an async and lightweight API framework for python . Inspired by Koa and Sanic .

Joway 29 Nov 20, 2022
Endpoints is a lightweight REST api framework written in python and used in multiple production systems that handle millions of requests daily.

Endpoints Quickest API builder in the West! Endpoints is a lightweight REST api framework written in python and used in multiple production systems th

Jay Marcyes 30 Mar 5, 2022
APIFlask is a lightweight Python web API framework based on Flask and marshmallow-code projects

APIFlask APIFlask is a lightweight Python web API framework based on Flask and marshmallow-code projects. It's easy to use, highly customizable, ORM/O

Grey Li 705 Jan 4, 2023
Asita is a web application framework for python based on express-js framework.

Asita is a web application framework for python. It is designed to be easy to use and be more easy for javascript users to use python frameworks because it is based on express-js framework.

Mattéo 4 Nov 16, 2021
A public API written in Python using the Flask web framework to determine the direction of a road sign using AI

python-public-API This repository is a public API for solving the problem of the final of the AIIJC competition. The task is to create an AI for the c

Lev 1 Nov 8, 2021
Flask-Potion is a RESTful API framework for Flask and SQLAlchemy, Peewee or MongoEngine

Flask-Potion Description Flask-Potion is a powerful Flask extension for building RESTful JSON APIs. Potion features include validation, model resource

DTU Biosustain 491 Dec 8, 2022