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)
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 08, 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
Web framework based on type hint。

Hint API 中文 | English 基于 Type hint 的 Web 框架 hintapi 文档 hintapi 实现了 WSGI 接口,并使用 Radix Tree 进行路由查找。是最快的 Python web 框架之一。一切特性都服务于快速开发高性能的 Web 服务。 大量正确的类型

Aber 19 Dec 02, 2022
WebSocket and WAMP in Python for Twisted and asyncio

Autobahn|Python WebSocket & WAMP for Python on Twisted and asyncio. Quick Links: Source Code - Documentation - WebSocket Examples - WAMP Examples Comm

Crossbar.io 2.4k Jan 06, 2023
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
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
REST API framework designed for human beings

Eve Eve is an open source Python REST API framework designed for human beings. It allows to effortlessly build and deploy highly customizable, fully f

eve 6.6k Jan 07, 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 Jan 08, 2023
aiohttp-ratelimiter is a rate limiter for the aiohttp.web framework.

aiohttp-ratelimiter aiohttp-ratelimiter is a rate limiter for the aiohttp.web fr

JGL Technologies 4 Dec 11, 2022
Bablyon 🐍 A small ASGI web framework

A small ASGI web framework that you can make asynchronous web applications using uvicorn with using few lines of code

xArty 8 Dec 07, 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 08, 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
Embrace the APIs of the future. Hug aims to make developing APIs as simple as possible, but no simpler.

Read Latest Documentation - Browse GitHub Code Repository hug aims to make developing Python driven APIs as simple as possible, but no simpler. As a r

Hug API Framework 6.7k Dec 27, 2022
Quiz Web App with Flask and MongoDB as the Databases

quiz-app Quiz Web Application made with flask and mongodb as the Databases Before you run this application, change the inside MONGODB_URI ( in config.

gibran abdillah 7 Dec 14, 2022
A proof-of-concept CherryPy inspired Python micro framework

Varmkorv Varmkorv is a CherryPy inspired micro framework using Werkzeug. This is just a proof of concept. You are free to use it if you like, or find

Magnus Karlsson 1 Nov 22, 2021
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
The little ASGI framework that shines. ?

✨ The little ASGI framework that shines. ✨ Documentation: https://www.starlette.io/ Community: https://discuss.encode.io/c/starlette Starlette Starlet

Encode 7.7k Jan 01, 2023
A python application to log QSOs directly to QRZ.com from the command line

qrzlogger This script is a QRZ.com command line QSO logger. It does the following: asks the user for a call sign displays available call sign info pul

Michael Clemens 15 Jul 16, 2021
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
Asita is a web application framework for python.

What is Asita ? 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

Mattéo 4 Nov 16, 2021