Coder Social home page Coder Social logo

cr0hn / aiohttp-swagger Goto Github PK

View Code? Open in Web Editor NEW
186.0 14.0 80.0 4.75 MB

Swagger API Documentation builder for aiohttp server

Home Page: http://aiohttp-swagger.readthedocs.io/en/latest/

License: Other

Python 1.41% CSS 3.90% HTML 0.35% JavaScript 94.31% Makefile 0.02%
aiohttp swagger aiohttp-swagger aiohttp-server python apidoc

aiohttp-swagger's Introduction

aiohttp-swagger

LOOCKING FOR MAINTAINERS!!!!!

Logo

Build Status codecov.io

aiohttp-swagger: Swagger API Documentation builder for aiohttp server

Documentation http://aiohttp-swagger.readthedocs.io/en/latest/
Code https://github.com/cr0hn/aiohttp-swagger
Issues https://github.com/cr0hn/aiohttp-swagger/issues/
Python version Python 3.4 and above

What's aiohttp-swagger

aiohttp-swagger is a plugin for aiohttp.web server that allow to document APIs using Swagger show the Swagger-ui console.

What's new?

Version 1.0.0

  • First version released

You can read entire list in CHANGELOG file.

aiohttp-swagger's People

Contributors

alexei-kornienko avatar arcenik avatar asvetlov avatar avostap avatar burkovba avatar cr0hn avatar daanklijn avatar denismakogon avatar dutradda avatar goranpavlovic avatar guoyiang avatar kapucko avatar katajakasa avatar kriskonina avatar melihcolpan avatar olexandr-klymenko avatar pascal-de-ladurantaye avatar pierrecdn avatar regqueryvalueex avatar stasfilin avatar thedeadone avatar timofurrer avatar timway avatar vkropotko avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

aiohttp-swagger's Issues

Data format from Jsonschema

Hello.
For validation incoming data from client I use Jsonschema.
Is there way to describe format of data from the Jsonschema?

Incorrect behavior in case of `/` character in the `tags` section

I use library version 1.0.5
When I put / to the tags section the method expanding doesn't work, for exapmple:

description: Returns current scale settings
tags:
- API/Scale settings
produces:
- application/json
responses:
    "200":
        description: successful operation.
    "405":
        description: invalid HTTP Method

When I click to the method in the web UI nothing happens and there are error message in the js-console:

http://localhost:8000/doc#!/API%2FScale_settings/head_api_configuration_scaling

Error: Syntax error, unrecognized expression: %2FScale_settings_head_api_configuration_scaling_content jquery-1.8.0.min.js:2:56628
	Z.error http://localhost:8000/doc/swagger_static/lib/jquery-1.8.0.min.js:2:56628
	bg http://localhost:8000/doc/swagger_static/lib/jquery-1.8.0.min.js:2:46474
	Z.compile http://localhost:8000/doc/swagger_static/lib/jquery-1.8.0.min.js:2:57617
	bm http://localhost:8000/doc/swagger_static/lib/jquery-1.8.0.min.js:2:58497
	bm http://localhost:8000/doc/swagger_static/lib/jquery-1.8.0.min.js:2:59823
	Z http://localhost:8000/doc/swagger_static/lib/jquery-1.8.0.min.js:2:50393
	find http://localhost:8000/doc/swagger_static/lib/jquery-1.8.0.min.js:2:60731
	init http://localhost:8000/doc/swagger_static/lib/jquery-1.8.0.min.js:2:10549
	p http://localhost:8000/doc/swagger_static/lib/jquery-1.8.0.min.js:2:9319
	shebang client.js:693
	shebang self-hosted:972:17

Ability to have swagger_def without swagger_home.

Currently, setup_swagger is a one size fits all solution. It generates the swagger_def JSON file, then hosts a copy of swagger-ui (a.k.a. swagger_home).
I propose adding an option to decouple the two, so that it is possible to host just the swagger.json file, then the developer can choose to either self-host swagger-home or not to host it at all (if that is what they prefer). I am happy to make a PR to support this.

Create sphinx docs

REAME is very good place for library introduction.

But sphinx documentation stored on readthedocs.io also makes sense.

The doc could contain not only introduction part but the reference for all public API.
For example I cannot figure out the full list of setup_swagger parameters without looking into the source code.

I believe you understand my pain very well.

Setup swagger UI within main app, but consider indexing sub app as well

This flow is terribly broken currently. It's partially affected by aio-libs/aiohttp#2656.
But also it becomes messy in terms of setup sequence.

For now I won't suggest a long-term solution (till upstream issue fixed), but here's what I had to hack to get this working:

"""The app configuration module."""
import logging

from aiohttp.web import Application
from aiohttp_swagger import setup_swagger

from .views import APIView

_logger = logging.getLogger(__name__)


async def build_application():
    """Create and pre-populate an aiohttp.web.Application instance."""
    app = Application()
    _logger.info('App initialized.')

    api_app = Application()
    _logger.info('API App initialized.')

    api_app.router.add_route('POST', r'/ping-cad/', APIView)
    _logger.info('Routes configured.')

    # Achtung! Keep add_subapp after routes declaration and
    # before swagger setup. Otherwise things will get fragile.
    # Affected by https://github.com/aio-libs/aiohttp/issues/2656
    app.add_subapp('/api/v1', api_app)
    _logger.info('API App mounted within main App.')

    # Accepts also `swagger_url='/api/v1/doc'`, defaults to '/api/doc':
    # we set api_base_url='/' because setting up within main App,
    # but referring API App, which after .add_subapp() has routes prepended
    # with /api/v1
    # We have to mount it before configuring swagger to make it recognise API.
    setup_swagger(app, api_base_url='/', swagger_url='/api/doc')
    _logger.info('Swagger Web UI configured.')

    return app

Note api_base_url reset to /, setup_swagger called with app, add_subapp() done before swagger setup, routes done before add_subapp()

Why I needed to setup it on the main app?

It's just that I've got a middleware processing error responses and converting them into JSON. And I didn't want that middleware to affect queries to swagger app.

Add setup_swagger(path_prefix) parameter

The param should be used as prefix to yaml definitions.

Now swagger_path accepts either absolute path or relative to current directory.

The parameter will allow to use relative to prefix paths.

Moreover, we could add loader concept like Jinja2 loaders -- I believe it makes sense.

Static path is wrong with default values

Hi,

after upgrade, I have hit issue that static path is generated as //api/doc. I have prepared PR: #69
Could you review or point me to correct solution?
Thank you for great project :)

docstring parsing doesn't work if you have inheritance in class based view

I'm trying to use inheritance in my class based view:

from aiohttp import web
from aiohttp_swagger3 import SwaggerDocs, SwaggerUiSettings


class BaseApi(web.View):
    async def get(self):
        return web.json_response(data={'called_method': 'GET'})

    async def post(self):
        return web.json_response(data={'called_method': 'POST'})

    async def put(self):
        return web.json_response(data={'called_method': 'PUT'})

    async def patch(self):
        return web.json_response(data={'called_method': 'PATCH'})


class SomeApi(BaseApi):
    def some_stuff(self):
        pass

    async def get(self):
        """
        ---
        summary: Some GET method
        responses:
          '200':
            description: OK.
        """
        self.some_stuff()
        return await super().get()


app = web.Application()

swagger = SwaggerDocs(
        app,
        swagger_ui_settings=SwaggerUiSettings(path="/api/v1.0.0/docs/"),
        title="Proto",
        version="1.0.0",
    )

swagger.add_routes([
        web.view('/api/some_api', SomeApi, name="some_api"),
    ])

web.run_app(app, host="127.0.0.1")

But I receive next exception:

File "lib/site-packages/aiohttp_swagger3/swagger_route.py", line 36, in _get_fn_parameters
    if func.__closure__ is None:
AttributeError: type object 'SomeApi' has no attribute '__closure__'

Multipart form body is not rendered properly

Hello,

I am trying to describe the parameters for an API endpoint, which is supposed to serve file uploads. My docstring looks like

    async def handle_upload(self, request: web.Request) -> web.Response:
        """
        ---
        description: This end-point allows to upload files to the storage service.
        tags:
        - Upload
        produces:
        - application/json
        parameters: []
        requestBody:
          required: true
          content:
            multipart/form-data:
              schema:
                type: object
                required:
                  - payload
                properties:
                  payload:
                    type: string
                    format: binary
                    description: the content of the file to be uploaded
                  name:
                    type: string
                    description: the file name (if unset then will be retrieved from `content-disposition` header)
        responses:
          "201":
            description: successful operation

...

Although the generated Swagger document looks like

upload

and does not contain any controls, which would allow file upload.

My question is whether such format supported by the library? Should I, probably, use another approach to describe multipart/form-data content?

[QUESTION] Passing a token to navigate swagger API

Hi there!
Firstly, congratulations for the project!

I'm experimenting the library to use in one of my projects.

Sorry for the ignorance. I'm having some trouble when navigating through static files from swagger. The problem is I need to use a token to have access to it.

Is there a way to set a token for swagger?

Here's an example, when I try to access:

My route:

def register_routes(app):
    app.router.add_route('GET', '/ping', ping)
    setup_swagger(app, swagger_url="/api/doc")

When I try to access a CSS static file:

http://127.0.0.1:8080/api/doc/swagger_static/css/screen.css 

I get:

{
"error_message": "Invalid token"
}

But when I pass a token in URL (through query string):

http://127.0.0.1:8080/api/doc/swagger_static/css/screen.css?token=test

I get the static CSS file content:

/* Original style from softwaremaniacs.org (c) Ivan Sagalaev <[email protected]> */
.swagger-section pre code {
  display: block;
  padding: 0.5em;
  background: #F0F0F0;
}
.swagger-section pre code,
.swagger-section pre .subst,
.swagger-section pre .tag .title,
.swagger-section pre .lisp .title,
.swagger-section pre .clojure .built_in,
.swagger-section pre .nginx .title {
  color: black;
}
.swagger-section pre .string,
.swagger-section pre .title,
.swagger-section pre .constant,
.swagger-section pre .parent,
.swagger-section pre .tag .value,
.swagger-section pre .rules .value,
.swagger-section pre .rules .value .number,
.swagger-section pre .preprocessor,
.swagger-section pre .ruby .symbol,
.swagger-section pre .ruby .symbol .string,
.swagger-section pre .aggregate,
.swagger-section pre .template_tag,
.swagger-section pre .django .variable,
.swagger-section pre .smalltalk .class,
.swagger-section pre .addition,
.swagger-section pre .flow,
.swagger-section pre .stream,
.swagger-section pre .bash .variable,
.swagger-section pre .apache .tag,
.swagger-section pre .apache .cbracket,
.swagger-section pre .tex .command,
.swagger-section pre .tex .special,
.swagger-section pre .erlang_repl .function_or_atom,
.swagger-section pre .markdown .header {
  color: #800;
}
.swagger-section pre .comment,
.swagger-section pre .annotation,
.swagger-section pre .template_comment,
.swagger-section pre .diff .header,
.swagger-section pre .chunk,
.swagger-section pre .markdown .blockquote {
  color: #888;
}
.swagger-section pre .number,
.swagger-section pre .date,
.swagger-section pre .regexp,
.swagger-section pre .literal,
.swagger-section pre .smalltalk .symbol,
.swagger-section pre .smalltalk .char,
.swagger-section pre .go .constant,
.swagger-section pre .change,
.swagger-section pre .markdown .bullet,
.swagger-section pre .markdown .link_url {
  color: #080;
}
.swagger-section pre .label,
.swagger-section pre .javadoc,
.swagger-section pre .ruby .string,
.swagger-section pre .decorator,
.swagger-section pre .filter .argument,
.swagger-section pre .localvars,
.swagger-section pre .array,
.swagger-section pre .attr_selector,
.swagger-section pre .important,
.swagger-section pre .pseudo,
.swagger-section pre .pi,
.swagger-section pre .doctype,
.swagger-section pre .deletion,
.swagger-section pre .envvar,
.swagger-section pre .shebang,
.swagger-section pre .apache .sqbracket,
.swagger-section pre .nginx .built_in,
.swagger-section pre .tex .formula,
.swagger-section pre .erlang_repl .reserved,
.swagger-section pre .prompt,
.swagger-section pre .markdown .link_label,
.swagger-section pre .vhdl .attribute,
.swagger-section pre .clojure .attribute,
.swagger-section pre .coffeescript .property {
  color: #88F;
}
.swagger-section pre .keyword,
.swagger-section pre .id,
.swagger-section pre .phpdoc,
.swagger-section pre .title,
.swagger-section pre .built_in,
.swagger-section pre .aggregate,
.swagger-section pre .css .tag,
.swagger-section pre .javadoctag,
.swagger-section pre .phpdoc,
.swagger-section pre .yardoctag,
.swagger-section pre .smalltalk .class,
.swagger-section pre .winutils,
.swagger-section pre .bash .variable,
.swagger-section pre .apache .tag,
.swagger-section pre .go .typename,
.swagger-section pre .tex .command,
.swagger-section pre .markdown .strong,
.swagger-section pre .request,
.swagger-section pre .status {
  font-weight: bold;
}
.swagger-section pre .markdown .emphasis {
  font-style: italic;
}
.swagger-section pre .nginx .built_in {
  font-weight: normal;
}
.swagger-section pre .coffeescript .javascript,
.swagger-section pre .javascript .xml,
.swagger-section pre .tex .formula,
.swagger-section pre .xml .javascript,
.swagger-section pre .xml .vbscript,
.swagger-section pre .xml .css,
.swagger-section pre .xml .cdata {
  opacity: 0.5;
}
.swagger-section .hljs {
  display: block;
  overflow-x: auto;
  padding: 0.5em;
  background: #F0F0F0;
}
.swagger-section .hljs,
.swagger-section .hljs-subst {
  color: #444;
}
.swagger-section .hljs-keyword,
.swagger-section .hljs-attribute,
.swagger-section .hljs-selector-tag,
.swagger-section .hljs-meta-keyword,
.swagger-section .hljs-doctag,
.swagger-section .hljs-name {
  font-weight: bold;
}
.swagger-section .hljs-built_in,
.swagger-section .hljs-literal,
.swagger-section .hljs-bullet,
.swagger-section .hljs-code,
.swagger-section .hljs-addition {
  color: #1F811F;
}

Thank you very much!

oneOf validation failed for optional property

Hello! I have an issue with describing an optional property with oneOf keyword.
Given a code:

from aiohttp import web
from aiohttp_swagger3 import SwaggerDocs, SwaggerUiSettings


async def handler(request: web.Request) -> web.Response:
    """
    Optional route description
    ---
    requestBody:
      required: true
      content:
        application/json:
          schema:
            type: object
            properties:
              key:
                oneOf:
                  - type: string
                  - type: integer
    responses:
      '200':
        description: Expected response to a valid request
    """
    return web.json_response({})


def main():
    app = web.Application()
    swagger = SwaggerDocs(
        app,
        swagger_ui_settings=SwaggerUiSettings(path="/docs/"),
        version="1.0.0",
    )
    swagger.add_routes([
        web.post("/api/", handler),
    ])
    web.run_app(app, port=8081)

main()

When running
curl -d '{}' -H "Content-Type: application/json" http://0.0.0.0:8081/api/
I expected 200 code, since key is not marked as required.But, instead, I get:
400: {"body": {"key": "fail to validate oneOf"}}

How to use `swagger_from_file` when file is in the parent directory?

I have the following structure in my project:

project
     โ”œโ”€โ”€ core
     โ”‚      โ””โ”€โ”€ factory.py
     โ””โ”€โ”€ docs
             โ””โ”€โ”€ swagger.yaml

My core.factory.py loads the swagger.yaml in the build_app function with:

    setup_swagger(
        app,
        swagger_url='/docs',
        swagger_from_file="/../docs/swagger.yaml"
    )

But it crashes the app raising the error gunicorn.errors.HaltServer: <HaltServer 'Worker failed to boot.' 3> (If I remove setup_swagger it works normally).

I have tried:

  • swagger_from_file="/../docs/swagger.yaml"
  • swagger_from_file="../docs/swagger.yaml"
  • swagger_from_file="docs/swagger.yaml"

And they all have failed. So I came to ask for help on that. Is there a way to load the swagger file when that file is located the parent dir?

Version 1.0.7. setup_swagger doesn't work

Hi,

Versions:
python==3.7.3
aiohttp==3.5.4
aiohttp-swagger==1.0.7

If I try to run examples from https://aiohttp-swagger.readthedocs.io/en/latest/quick_start.html,
it doesn't work.
Example:

>from aiohttp_swagger import *
>async def ping(request):
...     """
...     ---
...     description: This end-point allow to test that service is up.
...     tags:
...     - Health check
...     produces:
...     - text/plain
...     responses:
...         "200":
...             description: successful operation. Return "pong" text
...         "405":
...             description: invalid HTTP Method
...     """
...     return web.Response(text="pong")
...
>app = web.Application()
>app.router.add_route('GET', "/ping", ping)
<ResourceRoute [GET] <PlainResource  /ping> -> <function ping at 0x1066a6268>
>setup_swagger(app)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/local/lib/python3.7/site-packages/aiohttp_swagger/__init__.py", line 65, in setup_swagger
    security_definitions=security_definitions,
  File "/usr/local/lib/python3.7/site-packages/aiohttp_swagger/helpers/builders.py", line 139, in generate_doc_from_each_end_point
    end_point_doc = _build_doc_from_func_doc(route)
  File "/usr/local/lib/python3.7/site-packages/aiohttp_swagger/helpers/builders.py", line 43, in _build_doc_from_func_doc
    if issubclass(route.handler, web.View) and route.method == METH_ANY:
  File "/usr/local/Cellar/python/3.7.3/Frameworks/Python.framework/Versions/3.7/lib/python3.7/abc.py", line 143, in __subclasscheck__
    return _abc_subclasscheck(cls, subclass)
TypeError: issubclass() arg 1 must be a class

Integration with apispec?

Nice work on this project!

Would you be open to collaborating on an integration with apispec, a framework-agnostic swagger spec generator?

This would allow users of aiohttp-swagger to take advantage of the rest of the apispec ecosystem (marshmallow and webargs integration, for example).

BTW, I think this could happen without making breaking changes to the aiohttp-swagger API. setup_swagger could do the work of constructing an apispec.Spec object with the aiohttp plugin enabled.

How to `examples` section?

In Swagger 3 we can add common Schemas in section #/components/schemas/.
Also we can can add common examples in section #/components/examples/.

aiohttp-swagger can add multiple schemas in #/components/schemas/ through definitions parameter in swagger_setup(..) but can't add examples in section #/components/examples/.

How to add examples in section #/components/examples/?

UnicodeDecodeError

On Windows when using swagger_from_file argument and YAML file contains Cyrillic letters I get an error:

Traceback (most recent call last):
  File "app.py", line 162, in <module>
    setup_swagger(app, swagger_from_file='swagger.yaml')
  File "D:\playground\python\env3\lib\site-packages\aiohttp_swagger\__init__.py"
, line 58, in setup_swagger
    swagger_info = load_doc_from_yaml_file(swagger_from_file)
  File "D:\playground\python\env3\lib\site-packages\aiohttp_swagger\helpers\buil
ders.py", line 123, in load_doc_from_yaml_file
    loaded_yaml = yaml.load(open(doc_path, "r").read())
  File "D:\playground\python\env3\lib\encodings\cp1251.py", line 23, in decode
    return codecs.charmap_decode(input,self.errors,decoding_table)[0]
UnicodeDecodeError: 'charmap' codec can't decode byte 0x98 in position 871: char
acter maps to <undefined>

Routes not shown in Swagger UI when using custom decorators

When adding a route using a function with a decorator I am not able to see the route in the Swagger UI.
I am using 1.0.14, which I installed via pip.

Some code to reproduce the problem:

from aiohttp import web
from aiohttp_swagger import *

def my_decorator(func):
    def wrapper():
        print("Something is happening before the function is called.")
        func()
        print("Something is happening after the function is called.")
    return wrapper

@my_decorator
async def ping(request):
    """
    ---
    description: This end-point allow to test that service is up.
    tags:
    - Health check
    produces:
    - text/plain
    responses:
        "200":
            description: successful operation. Return "pong" text
        "405":
            description: invalid HTTP Method
    """
    return web.Response(text="pong")

app = web.Application()

app.router.add_route('GET', "/ping", ping)

setup_swagger(app, swagger_url="/api/v1/doc", ui_version=2)  # <-- NEW Doc URI

web.run_app(app, host="127.0.0.1")

Make docstring parser more flexible

This is an issue to judge interest in making the parser for docstrings more flexible (I will create a PR if so). Currently it looks like everything past --- is interpreted as a swagger specification for a route. I would like to create a PR for a docstring_handler function that can parse a given docstring and return the dict of the yaml specification. In my case I am using numpy docstring style https://www.sphinx-doc.org/en/master/usage/extensions/example_numpy.html and the --- conflicts with the documentation syntax. I would like to add a docstring_handler to can parse a specification like so.

def function_with_types_in_docstring(param1, param2):
    """Example function with types documented in the docstring.

    `PEP 484`_ type annotations are supported. If attribute, parameter, and
    return types are annotated according to `PEP 484`_, they do not need to be
    included in the docstring:

    Parameters
    ----------
    param1 : int
        The first parameter.
    param2 : str
        The second parameter.

    Route
    --------
    
    .. code-block:: yaml
 
              summary: Adds a new user
                requestBody:
                  content:
                    application/json:
                      schema:      # Request body contents
                        type: object
                        properties:
                          id:
                            type: integer
                          name:
                            type: string
                        example:   # Sample object
                          id: 10
                          name: Jessica Smith
                responses:
                  '200':
                    description: OK

    Returns
    -------
    bool
        True if successful, False otherwise.

    .. _PEP 484:
        https://www.python.org/dev/peps/pep-0484/

    """
    pass

This docstring_handler would return

summary: Adds a new user
  requestBody:
    content:
      application/json:
        schema:      # Request body contents
          type: object
          properties:
            id:
              type: integer
            name:
              type: string
          example:   # Sample object
            id: 10
            name: Jessica Smith
  responses:
    '200':
      description: OK

Class based view routes not shown in Swagger UI

When adding a single class based view route using add_route I am not able to see the route in the Swagger UI.
I am using 1.0.14, which I installed via pip.

Some code to reproduce the problem:

from aiohttp import web
from aiohttp_swagger import *

class PingHandler(web.View):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

    async def get(request):
        """
        ---
        description: This end-point allow to test that service is up.
        tags:
        - Health check
        produces:
        - text/plain
        responses:
            "200":
                description: successful operation. Return "pong" text
            "405":
                description: invalid HTTP Method
        """
        return web.Response(text="pong")

app = web.Application()
app.router.add_route('GET', "/ping", PingHandler)

setup_swagger(app, swagger_url="/api/v1/doc", ui_version=2)  # <-- NEW Doc URI

web.run_app(app, host="127.0.0.1")

I have fixed this issue in PR #90

Compatibility with new PyYAML (version 5.1)

Recently PyYAML was released new version 5.1 and tests for my application detects new warning yaml.YAMLLoadWarning for aiohttp-swagger:

Traceback (most recent call last):
  File "/home/_/.pyenv/versions/3.7.0/lib/python3.7/multiprocessing/process.py", line 297, in _bootstrap
    self.run()
  File "/home/_/.pyenv/versions/3.7.0/lib/python3.7/multiprocessing/process.py", line 99, in run
    self._target(*self._args, **self._kwargs)
  File "/home/_/develop/_/_/server.py", line 56, in serve
    web.run_app(app_factory(), port=port)
  File "/home/_/develop/_/.tox/py3.7/lib/python3.7/site-packages/aiohttp/web.py", line 415, in run_app
    reuse_port=reuse_port))
  File "/home/_/.pyenv/versions/3.7.0/lib/python3.7/asyncio/base_events.py", line 568, in run_until_complete
    return future.result()
  File "/home/_/develop/_/.tox/py3.7/lib/python3.7/site-packages/aiohttp/web.py", line 278, in _run_app
    app = await app  # type: ignore
  File "/home/_/develop/_/_/server.py", line 45, in app_factory
    contact='Coffee Team',
  File "/home/_/develop/_/.tox/py3.7/lib/python3.7/site-packages/aiohttp_swagger/__init__.py", line 62, in setup_swagger
    api_version=api_version, title=title, contact=contact
  File "/home/_/develop/_/.tox/py3.7/lib/python3.7/site-packages/aiohttp_swagger/helpers/builders.py", line 71, in generate_doc_from_each_end_point
    swagger = yaml.load(swagger_base)
  File "/home/_/develop/_/.tox/py3.7/lib/python3.7/site-packages/yaml/__init__.py", line 109, in load
    load_warning('load')
  File "/home/_/develop/_/.tox/py3.7/lib/python3.7/site-packages/yaml/__init__.py", line 55, in load_warning
    warnings.warn(message, YAMLLoadWarning, stacklevel=3)
yaml.YAMLLoadWarning: calling yaml.load() without Loader=... is deprecated, as the default Loader is unsafe. Please read https://msg.pyyaml.org/load for full details.

Now, I muted that warning in my tests but hope that aiohttp-swagger fix compatibility.

Support response object and error references in API spec

Currently only handlers are being analyzed for docstrings. So as part of the docstring it is possible to mention response object and errors using next notation:

      responses:
        200:
          description: List of apps.
          schema:
            $ref: '#/definitions/AppsWrapper'
        default:
          description: Unexpected error
          schema:
            $ref: '#/definitions/Error'

It would be nice to map response objects and errors using same swagger syntax.
New feature will extend current docstring syntax to include object references:

        """
        ---
        description: Creating project-scoped app
        tags:
        - Apps
        produces:
        - application/json
        parameters:
        - in: body
          name: app
          description: Created project-scoped app
          required: true
          schema:
            type: object
            properties:
              name:
                type: string
        responses:
            "200":
                description: Successful operation
                schema: 
                  $ref: app.App
            "401":
                description: Not authorized
            "409":
                description: App exists
            default:
                description: Unexpected error
                schema:
                 $ref: error.CustomError
        """

where app.App is importable class object reference that would be treated as response object which docstring should also follow specific format as route handlers:

  App:
    type: object
    properties:
      name:
        type: string
        description: "Name of this app."
        readOnly: true
      config:
        type: object
        description: Application configuration
        additionalProperties:
          type: string

Static UI assets reference malformed when using sub apps

Swagger UI static assets are set to

<link href="/doc/swagger_static/css/typography.css" media="screen" rel="stylesheet" type="text/css">

when they should actually live at

<link href="/api/v1/doc/swagger_static/css/typography.css" media="screen" rel="stylesheet" type="text/css">

if setup_swagger is called on a sub app like:

   setup_app(v1)
    setup_swagger(
        v1,
        swagger_url='/doc',
        swagger_from_file="v1_swagger.json",
        api_base_url='/api/v1'
    )
    app = web.Application()
    app.add_subapp('/api/v1', v1)

FIX:

setup_swagger should set statics_path = '{}{}/swagger_static'.format(api_base_url,_swagger_url) if sub apps are to work as specified in the documentation

PyPI Version behind

The last version on PyPI was published on Apr 4, 2017, yet the repo has some recent activity. Can a more recent version be published?

[Question] Please suggest the way to build swagger doc within next case

Assume we have such wrapper on top of each route handler

def api_action(**outter_kwargs):
    """
    Wrapps API controller action actions handler
    :param outter_kwargs: API instance action key-value args
    :return: _api_handler

    Example:

    class Controller(ControllerBase):

        @api_action(method='GET')
        async def index(self, request, **kwargs):
            return web.Response(
                text=str(request),
                reason="dumb API",
                status=201)

    """

    def _api_handler(func):

        @functools.wraps(func)
        def wrapper(self, *args, **kwargs):
            return func(self, *args, *kwargs)

       # custom logic here
        return wrapper

    return _api_handler

So, coming from examples provided in README, we'd have next app

from aiohttp import web
from aiohttp_swagger import *

@api_action(method="GET", route="/ping")
async def ping(request):
    """
    ---
    description: This end-point allow to test that service is up.
    tags:
    - Health check
    produces:
    - text/plain
    responses:
        "200":
            description: successful operation. Return "pong" text
        "405":
            description: invalid HTTP Method
    """
    return web.Response(text="pong")


app = web.Application()

setup_swagger(app)

web.run_app(app, host="127.0.0.1")

eventually, swagger is not capable to be assembled (empty page). I tried to debug his problem and it appears that route._handler.__doc__ is None, but if i would not use this decorator it will have the same doc string as ping. Can you please suggest me a way how to fix it?

`json.dumps` in `swagger_info` will fail on datetime serialization

If the swagger_info attribute contains a datetime object in an example definition, the default JSON serializer will fail for datetime types.

ex)

TypeError: datetime.datetime(2021, 11, 14, 1, 34, 26, tzinfo=datetime.timezone(datetime.timedelta(0, 720))) is not JSON serializable

https://swagger.io/docs/specification/data-models/data-types/#string

swagger_info = json.dumps(swagger_info)

Proposing a PR to either:

  1. allow the caller to pass in a string, a pre-serialized spec;
  2. allow the caller to specify a user-defined serializer function; or
  3. something else.

Add _ prefix to private API.

I believe swagger.swagger_home etc. are not part or Public API.
Please rename the function to swagger._swagger_home and do the same for others.

It gives very clean vision for readers of your code: what is internal detail and what is a part of Public API.
Also it gives very obvious rule to you: every _name not started from __ should be documented and enlisted in module's __all__.

I know I don't always follow the recommendation myself, sorry.
But it is good advise, especially on very early stage as you have for the library now.

Using regex with escaped characters crashes with "yaml.scanner.ScannerError: while scanning a double-quoted scalar"

When using classes with regexes, aiohttp-swagger attempts to convert these to patterns in the openapi v3 format.
If the regex got any escaped characters, such as \w, the code will crash:

Traceback (most recent call last):
  File "/c/git/app/rest/__init__.py", line 31, in setup_swagger  
    aiohttp_swagger.setup_swagger(app, api_version=__api_version__,
  File "/home/itay/.pyenv/versions/3.9.5/lib/python3.9/site-packages/aiohttp_swagger/__init__.py", line 66, in setup_swagger
    swagger_info = generate_doc_from_each_end_point(
  File "/home/itay/.pyenv/versions/3.9.5/lib/python3.9/site-packages/aiohttp_swagger/helpers/builders.py", line 129, in generate_doc_from_each_end_point
    swagger = yaml.full_load(swagger_base)
  File "/home/itay/.pyenv/versions/3.9.5/lib/python3.9/site-packages/yaml/__init__.py", line 142, in full_load
    return load(stream, FullLoader)
  File "/home/itay/.pyenv/versions/3.9.5/lib/python3.9/site-packages/yaml/__init__.py", line 114, in load
    return loader.get_single_data()
  File "/home/itay/.pyenv/versions/3.9.5/lib/python3.9/site-packages/yaml/constructor.py", line 49, in get_single_data
    node = self.get_single_node()
  File "/home/itay/.pyenv/versions/3.9.5/lib/python3.9/site-packages/yaml/composer.py", line 36, in get_single_node
    document = self.compose_document()
  File "/home/itay/.pyenv/versions/3.9.5/lib/python3.9/site-packages/yaml/composer.py", line 55, in compose_document
    node = self.compose_node(None, None)
  File "/home/itay/.pyenv/versions/3.9.5/lib/python3.9/site-packages/yaml/composer.py", line 84, in compose_node
    node = self.compose_mapping_node(anchor)
  File "/home/itay/.pyenv/versions/3.9.5/lib/python3.9/site-packages/yaml/composer.py", line 133, in compose_mapping_node
    item_value = self.compose_node(node, item_key)
  File "/home/itay/.pyenv/versions/3.9.5/lib/python3.9/site-packages/yaml/composer.py", line 84, in compose_node
    node = self.compose_mapping_node(anchor)
  File "/home/itay/.pyenv/versions/3.9.5/lib/python3.9/site-packages/yaml/composer.py", line 133, in compose_mapping_node
    item_value = self.compose_node(node, item_key)
  File "/home/itay/.pyenv/versions/3.9.5/lib/python3.9/site-packages/yaml/composer.py", line 84, in compose_node
    node = self.compose_mapping_node(anchor)
  File "/home/itay/.pyenv/versions/3.9.5/lib/python3.9/site-packages/yaml/composer.py", line 133, in compose_mapping_node
    item_value = self.compose_node(node, item_key)
  File "/home/itay/.pyenv/versions/3.9.5/lib/python3.9/site-packages/yaml/composer.py", line 84, in compose_node
    node = self.compose_mapping_node(anchor)
  File "/home/itay/.pyenv/versions/3.9.5/lib/python3.9/site-packages/yaml/composer.py", line 133, in compose_mapping_node
    item_value = self.compose_node(node, item_key)
  File "/home/itay/.pyenv/versions/3.9.5/lib/python3.9/site-packages/yaml/composer.py", line 84, in compose_node
    node = self.compose_mapping_node(anchor)
  File "/home/itay/.pyenv/versions/3.9.5/lib/python3.9/site-packages/yaml/composer.py", line 133, in compose_mapping_node
    item_value = self.compose_node(node, item_key)
  File "/home/itay/.pyenv/versions/3.9.5/lib/python3.9/site-packages/yaml/composer.py", line 84, in compose_node
    node = self.compose_mapping_node(anchor)
  File "/home/itay/.pyenv/versions/3.9.5/lib/python3.9/site-packages/yaml/composer.py", line 133, in compose_mapping_node
    item_value = self.compose_node(node, item_key)
  File "/home/itay/.pyenv/versions/3.9.5/lib/python3.9/site-packages/yaml/composer.py", line 64, in compose_node
    if self.check_event(AliasEvent):
  File "/home/itay/.pyenv/versions/3.9.5/lib/python3.9/site-packages/yaml/parser.py", 
line 98, in check_event
    self.current_event = self.state()
  File "/home/itay/.pyenv/versions/3.9.5/lib/python3.9/site-packages/yaml/parser.py", 
line 449, in parse_block_mapping_value
    if not self.check_token(KeyToken, ValueToken, BlockEndToken):
  File "/home/itay/.pyenv/versions/3.9.5/lib/python3.9/site-packages/yaml/scanner.py", line 116, in check_token
    self.fetch_more_tokens()
  File "/home/itay/.pyenv/versions/3.9.5/lib/python3.9/site-packages/yaml/scanner.py", line 251, in fetch_more_tokens
    return self.fetch_double()
  File "/home/itay/.pyenv/versions/3.9.5/lib/python3.9/site-packages/yaml/scanner.py", line 655, in fetch_double
    self.fetch_flow_scalar(style='"')
  File "/home/itay/.pyenv/versions/3.9.5/lib/python3.9/site-packages/yaml/scanner.py", line 666, in fetch_flow_scalar
    self.tokens.append(self.scan_flow_scalar(style))
  File "/home/itay/.pyenv/versions/3.9.5/lib/python3.9/site-packages/yaml/scanner.py", line 1149, in scan_flow_scalar
    chunks.extend(self.scan_flow_scalar_non_spaces(double, start_mark))
  File "/home/itay/.pyenv/versions/3.9.5/lib/python3.9/site-packages/yaml/scanner.py", line 1223, in scan_flow_scalar_non_spaces
    raise ScannerError("while scanning a double-quoted scalar", start_mark,
yaml.scanner.ScannerError: while scanning a double-quoted scalar
  in "<unicode string>", line 272, column 26:
                    pattern: "^s3://[\w]+/"
                             ^
found unknown escape character 'w'
  in "<unicode string>", line 272, column 35:
                    pattern: "^s3://[\w]+/"

This happens because the openapi.yaml jinja manifest exports the pattern as:

s3_bucket_key:
                title: "S3 Bucket Key"
                pattern: "^s3://[\\w]+/"
                type: "string"

and causes an error, since \ in double quote is parsed as escape sequence by YAML.

The solution would probably be to use single quotes instead of double quotes, probably in the nesteddict2yaml function.

Properly close files after use

Lots of files are opened but never closed (at least one for each documented endpoints)
I have identified 3 places where files are not closed:

__init__.py

app["SWAGGER_TEMPLATE_CONTENT"] = open(join(STATIC_PATH, "index.html"), "r").read() \
        .replace("##SWAGGER_CONFIG##", _swagger_def_url) \
        .replace("##STATIC_PATH##", statics_path)

helper/builders.py

end_point_doc = {
                    route.method.lower(): yaml.load(open(route.handler.swagger_file, "r").read())
                }

helper/builders.py

swagger_base = Template(open(join(SWAGGER_TEMPLATE, "swagger.yaml"), "r").read()).render(
        description=cleaned_description,
        version=api_version,
        title=title,
        contact=contact,
        base_path=api_base_url
    )

Use jinja2 template instead of custom way

Ath the moment a custom template way is implemented in the package:

   with open(join(STATIC_PATH, "index.html"), "r") as f:
        app["SWAGGER_TEMPLATE_CONTENT"] = (
            f.read()
            .replace("##SWAGGER_CONFIG##", '/{}{}'.
                     format(api_base_url.lstrip('/'), _swagger_def_url))
            .replace("##STATIC_PATH##", '/{}{}'.
                     format(api_base_url.lstrip('/'), statics_path)))

It should be replced by jinja2 Template as far as de-facto standard

Custom branding

Is there a way to change the logo, the colors, etc of the UI ?

If not, would you accept a pull request to support it ?

Thanks.

Support Class Based Views

class MyView(web.View):
    async def get(self):
        return await get_resp(self.request)

    async def post(self):
        return await post_resp(self.request)

app.router.add_route('*', '/path/to', MyView)

Add SWAGGER_VALIDATOR_URL variable in the swagger_ui/index.html

In order to be able to switch off swagger doc validation or change default URL by custom one SWAGGER_VALIDATOR_URL variable should be introduced in aiohttp_swagger/swagger_ui/index.html and supported in aiohttp_swagger/__init__.py by new argument of setup_swagger function (i.e. swagger_validator_url: str = '//online.swagger.io/validator').

aiohttp_swagger/__init__.py:

    with open(join(STATIC_PATH, "index.html"), "r") as f:
        app["SWAGGER_TEMPLATE_CONTENT"] = (
            f.read()
            .replace("##SWAGGER_CONFIG##", '/{}{}'.
                     format(api_base_url.lstrip('/'), _swagger_def_url))
            .replace("##STATIC_PATH##", '/{}{}'.
                     format(api_base_url.lstrip('/'), statics_path))
            .replace("##SWAGGER_VALIDATOR_URL##", swagger_validator_url)
        )

aiohttp_swagger/swagger_ui/index.html:

      window.swaggerUi = new SwaggerUi({
        url: url,
        validatorUrl: "##SWAGGER_VALIDATOR_URL##" || null,

How to add content to the index.html file?

I'm trying to add new content to the script so i can decide if i want to show the endpoint list or not but i seems that there's no easy way unless i use regex.

setup_swagger(
        app,
        swagger_url='/docs',
        swagger_from_file="docs/swagger.yaml",
        swagger_home_decor=_home_decor,
        ui_version=3
    )

setup_swagger_ui(app)

def setup_swagger_ui(app):
    html_path = abspath(join(dirname(__file__), "../docs/swagger.html"))
    with open(html_path) as f:

        # This key does not have my "##SHOW_ENDPOINTS##" tag
        # because it was read from the package itself.
        # and i cannot override it because my template does not have the ##STATIC_PATH##
        # that the package replaced on the setup_swagger method.
        app["SWAGGER_TEMPLATE_CONTENT"] = (
            f.read().replace('##SHOW_ENDPOINTS##', 'false')
        )

The only way i can imagine is to use regex to add my conditions, maybe grep by window.ui and change it to add my condition

<!-- my template -->
<!-- ... -->
<script>
    window.onload = function() {
      // Begin Swagger UI call region
      const ui = SwaggerUIBundle({
        url: "##SWAGGER_CONFIG##",
        dom_id: '#swagger-ui',
        deepLinking: true,
        presets: [
          SwaggerUIBundle.presets.apis,
          SwaggerUIStandalonePreset
        ],
        plugins: [
          SwaggerUIBundle.plugins.DownloadUrl
        ],
        layout: "StandaloneLayout"
      })
      // End Swagger UI call region

      // const showEndpoint = eval('##SHOW_ENDPOINTS##')
     // if (!showEndpoint) { document.querySelector(".wrapper").addClass('is-hidden')

      window.ui = ui
    }
</script>
<!-- ... -->

Possible solution

  1. Adds a parameter on the setup_swagger to define the path to the html file
    This way we can set all "configs" to the user file and let them replace their own.

  2. Adds a parameter on the setup_swagger so the user can pass a "component" to be injected on the html.
    e.g:

<!-- index.html file on the package -->
<script>
    window.onload = function() {
        // ... 
    }
 
      window.ui = ui
    }
  </script>
  ##CUSTOM_COMPONENT##
def setup_swagger(app, html_component=None, ...):
        # ...
        with open(join(STATIC_PATH, "index.html"), "r") as f:
        app["SWAGGER_TEMPLATE_CONTENT"] = (
            f.read()
            .replace("##SWAGGER_CONFIG##", '{}{}'.
                     format(api_base_url.rstrip('/'), _swagger_def_url))
            .replace("##STATIC_PATH##", '{}{}'.
                     format(api_base_url.rstrip('/'), statics_path))
            .replace("##SWAGGER_VALIDATOR_URL##", swagger_validator_url)
            .replace("##CUSTOM_COMPONENT##", html_component)
        )

Usage:

<!-- my component -->
<script>console.log('hello custom component')</script>
my_custom_component = '/files/component.html'
setup_swagger(app, html_component=my_custom_component)

Deployment: test failures due to missing datafiles

The sdist packages generated by setup.py are missing the tests/data directory, meaning that all tests fail when running from the source package (as opposed to from a git repo). This can be remedied by adding the directory to setup.py.

Show parameters description

For example:

        parameters:
        - in: query
          name: search
          type: string
          description: Search something

Description is empty on page.
Where I can paste that piece for render it?

Remote References

Hello, any chance you could consider supporting remote references in swagger files?

Support OpenAPI 3

Hi!
It is planned to support a new version?
Now, with app:

from aiohttp import web
from aiohttp_swagger import *


async def ping(request):
    return web.Response(text="pong")

app = web.Application()
app.router.add_route('GET', "/ping", ping)
setup_swagger(app, swagger_from_file="swagger.yaml")
web.run_app(app, host="127.0.0.1")

and swagger.yaml:

---

openapi: 3.0.0
info:
  title: API
  description: description
  version: 0.1.9

paths:
  /ping:
    get:
      responses:
        '200':
          description: return "pong"

i get an error (in browser console):

Uncaught TypeError: Cannot read property 'definitions' of null
    at module.exports.Resolver.resolve (swagger-ui.js:4566)
    at swagger-ui.js:3596
    at module.exports.SwaggerSpecConverter.finish (swagger-ui.js:6592)
    at module.exports.SwaggerSpecConverter.convert (swagger-ui.js:5966)
    at response (swagger-ui.js:3594)
    at responseInterceptor (swagger-ui.js:4211)
    at obj.on.response (swagger-ui.js:4226)
    at swagger-ui.js:4489
    at Request.callback (swagger-ui.js:20775)
    at Request.<anonymous> (swagger-ui.js:20597)

Use aiohttp-swagger version 1.0.5

generate_doc_from_each_end_point() should sort keys for defaul json

This allows the swagger spec to look consistent when generated off endpoints.
This is especially useful on Python3.5

I understand CPython3.6 and Python3.7+ specifies ordered dictionaries, but it would be great to at worst have an option to sort the items alphabetically.

Just changing generate_doc_from_each_end_point() to return

return json.dumps(swagger, sort_keys=True)

makes a big difference for me.

Unable to create proper swagger doc with two or more handlers to the same path

Consider next example:

from aiohttp import web
from aiohttp_swagger import *


async def ping(request):
    """
    ---
    description: This end-point allow to test that service is up.
    tags:
    - Health-check-GET
    produces:
    - text/plain
    responses:
        "200":
            description: successful operation. Return "pong" text
        "405":
            description: invalid HTTP Method
    """
    return web.Response(text="pong")


async def pingv2(request):
    """
    ---
    description: This end-point allow to test that service is up V2.
    tags:
    - Health-check-POST
    produces:
    - text/plain
    responses:
        "200":
            description: successful operation. Return "pong" text
        "405":
            description: invalid HTTP Method
    """
    return web.Response(text="pong")


app = web.Application()

app.router.add_route('POST', "/ping", pingv2)
app.router.add_route('GET', "/ping", ping)

setup_swagger(app, swagger_url="/api")

web.run_app(app, host="127.0.0.1")

Swagger doc for this example:

image

So, it appears that Swagger JSON builder mapps docstring to URL, if you have handlers assigned to more than one HTTP method but to the same HTTP route (in our case /ping), builder will overwrite docstring each time it mets the same route.

Update swagger_ui folder

Hi,
@cr0hn you need upload full swagger_ui, 'cause I didn't see lib folder
But index.html uses this folder

  <script src='##STATIC_PATH##/lib/object-assign-pollyfill.js' type='text/javascript'></script>
  <script src='##STATIC_PATH##/lib/jquery-1.8.0.min.js' type='text/javascript'></script>
  <script src='##STATIC_PATH##/lib/jquery.slideto.min.js' type='text/javascript'></script>
  <script src='##STATIC_PATH##/lib/jquery.wiggle.min.js' type='text/javascript'></script>
  <script src='##STATIC_PATH##/lib/jquery.ba-bbq.min.js' type='text/javascript'></script>
  <script src='##STATIC_PATH##/lib/handlebars-4.0.5.js' type='text/javascript'></script>
  <script src='##STATIC_PATH##/lib/lodash.min.js' type='text/javascript'></script>
  <script src='##STATIC_PATH##/lib/backbone-min.js' type='text/javascript'></script>
  <script src='##STATIC_PATH##/swagger-ui.js' type='text/javascript'></script>
  <script src='##STATIC_PATH##/lib/highlight.9.1.0.pack.js' type='text/javascript'></script>
  <script src='##STATIC_PATH##/lib/highlight.9.1.0.pack_extended.js' type='text/javascript'></script>
  <script src='##STATIC_PATH##/lib/jsoneditor.min.js' type='text/javascript'></script>
  <script src='##STATIC_PATH##/lib/marked.js' type='text/javascript'></script>
  <script src='##STATIC_PATH##/lib/swagger-oauth.js' type='text/javascript'></script>

Can you upload this to the repository? Or we can create package.json for npm

Bug in helpers/builders.py

Overview: if we declare route with class based view with method different from METH_ANY ('*') our endpoint doesn't show up
There is a bug in helpers/builders.py:43:

if issubclass(route.handler, web.View) and route.method == METH_ANY:

STR:

  1. Create route with class based view:
app.router.add_route( method='DELETE',
                                  path='/some_path/',
                                  handler=SubClassOf_web_View,
                                  name='some_name')
  1. Create doc string for DELETE method:
class SubClassOf_web_View(web.View):
    async def delete(self):
       """
       ---
       valid doc string
       """

Excpected: declared endpoint shows up on api page
Result: declared endpoint doesn't show up on api page

Solution: replace
if issubclass(route.handler, web.View) and route.method == METH_ANY:
with
if issubclass(route.handler, web.View):

Nested application static_prefix

I got a problem with nested app.

Pseudocode:

api_app = Application()
setup_swagger(api_app, swagger_url='/doc')

main_app = Application()
main_app.add_subapp('/api', api_app)

Problem is that Swagger is available on /api/doc, but Swagger template try to load static files from /doc/swagger_static/ that sure not exist in main app, because its created from nested with path /api/doc/swagger_static/

Need some hack to control static path building for allow rewrite it from /doc/swagger_static in templates to <prefix>/doc/swagger_static

It may be nested_prefix attr in setup_swagger() as example: setup_swagger(app, nested_prefix='/api')

Move examples to top-level

  1. Moving allows to find examples easier. People doesn't want to look into source code deeply for finding examples.
  2. It allows to pack lightweight wheels without including extra files.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.