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)
Asynchronous HTTP client/server framework for asyncio and Python

Async http client/server framework Key Features Supports both client and server side of HTTP protocol. Supports both client and server Web-Sockets out

aio-libs 13.2k Jan 05, 2023
Klein - A micro-framework for developing production-ready web services with Python

Klein, a Web Micro-Framework Klein is a micro-framework for developing production-ready web services with Python. It is 'micro' in that it has an incr

Twisted Matrix Labs 814 Jan 08, 2023
A Flask API REST to access words' definition

A Flask API to access words' definitions

Pablo Emídio S.S 9 Jul 22, 2022
CherryPy is a pythonic, object-oriented HTTP framework. https://docs.cherrypy.org/

Welcome to the GitHub repository of CherryPy! CherryPy is a pythonic, object-oriented HTTP framework. It allows building web applications in much the

CherryPy 1.6k Dec 29, 2022
A simple todo app using flask and sqlachemy

TODO app This is a simple TODO app made using Flask. Packages used: DoodleCSS Special thanks to Chris McCormick (@mccrmx) :) Flask Flask-SQLAlchemy Fl

Lenin 1 Dec 26, 2021
The core of a service layer that integrates with the Pyramid Web Framework.

pyramid_services The core of a service layer that integrates with the Pyramid Web Framework. pyramid_services defines a pattern and helper methods for

Michael Merickel 78 Apr 15, 2022
Persistent remote applications for X11; screen sharing for X11, MacOS and MSWindows.

Table of Contents About Installation Usage Help About Xpra is known as "screen for X" : its seamless mode allows you to run X11 programs, usually on a

xpra.org 785 Dec 30, 2022
Loan qualifier app - Loan Qualifier Application Built With Python

Loan Qualifier Application This program is designed to automate the discovery pr

Phil Hills 1 Jan 04, 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
Goblet is an easy-to-use framework that enables developers to quickly spin up fully featured REST APIs with python on GCP

GOBLET Goblet is a framework for writing serverless rest apis in python in google cloud. It allows you to quickly create and deploy python apis backed

Austen 78 Dec 27, 2022
NO LONGER MAINTAINED - A Flask extension for creating simple ReSTful JSON APIs from SQLAlchemy models.

NO LONGER MAINTAINED This repository is no longer maintained due to lack of time. You might check out the fork https://github.com/mrevutskyi/flask-res

1k Jan 04, 2023
cirrina is an opinionated asynchronous web framework based on aiohttp

cirrina cirrina is an opinionated asynchronous web framework based on aiohttp. Features: HTTP Server Websocket Server JSON RPC Server Shared sessions

André Roth 32 Mar 05, 2022
You can use the mvc pattern in your flask application using this extension.

You can use the mvc pattern in your flask application using this extension. Installation Run the follow command to install mvc_flask: $ pip install mv

Marcus Pereira 37 Dec 17, 2022
Serverless Python

Zappa - Serverless Python About Installation and Configuration Running the Initial Setup / Settings Basic Usage Initial Deployments Updates Rollback S

Rich Jones 11.9k Jan 01, 2023
Swagger/OpenAPI First framework for Python on top of Flask with automatic endpoint validation & OAuth2 support

Connexion Connexion is a framework that automagically handles HTTP requests based on OpenAPI Specification (formerly known as Swagger Spec) of your AP

Zalando SE 4.2k Jan 07, 2023
A micro web-framework using asyncio coroutines and chained middleware.

Growler master ' dev Growler is a web framework built atop asyncio, the asynchronous library described in PEP 3156 and added to the standard library i

687 Nov 27, 2022
Tornado is a Python web framework and asynchronous networking library, originally developed at FriendFeed.

Tornado Web Server Tornado is a Python web framework and asynchronous networking library, originally developed at FriendFeed. By using non-blocking ne

20.9k Jan 01, 2023
An easy-to-use high-performance asynchronous web framework.

An easy-to-use high-performance asynchronous web framework.

Aber 264 Dec 31, 2022
Phoenix LiveView but for Django

Reactor, a LiveView library for Django Reactor enables you to do something similar to Phoenix framework LiveView using Django Channels. What's in the

Eddy Ernesto del Valle Pino 526 Jan 02, 2023
An easy-to-use high-performance asynchronous web framework.

中文 | English 一个易用的高性能异步 web 框架。 Index.py 文档 Index.py 实现了 ASGI3 接口,并使用 Radix Tree 进行路由查找。是最快的 Python web 框架之一。一切特性都服务于快速开发高性能的 Web 服务。 大量正确的类型注释 灵活且高效的

Index.py 264 Dec 31, 2022