Klein - A micro-framework for developing production-ready web services with Python

Overview

Klein, a Web Micro-Framework

Build Status Code Coverage Requirements Status Python Version Compatibility

Klein is a micro-framework for developing production-ready web services with Python. It is 'micro' in that it has an incredibly small API similar to Bottle and Flask. It is not 'micro' in that it depends on things outside the standard library. This is primarily because it is built on widely used and well tested components like Werkzeug and Twisted.

A Klein bottle is an example of a non-orientable surface, and a glass Klein bottle looks like a twisted bottle or twisted flask. This, of course, made it too good of a pun to pass up.

Klein's documentation can be found at Read The Docs.

Example

This is a sample Klein application that returns 'Hello, world!', running on port 8080.

from klein import run, route

@route('/')
def home(request):
    return 'Hello, world!'

run("localhost", 8080)

Contribute

klein is hosted on GitHub and is an open source project that welcomes contributions of all kinds from the community, including:

For more information about contributing, see the contributor guidelines.

Comments
  • A way to structure klein apps into (reusable) modules

    A way to structure klein apps into (reusable) modules

    nb. the pattern I'm showing here is basically flask's blueprints

    It seems that currently Klein doesn't have any builtin way to help factoring out view functions to separate modules.

    For example, if you had the following app:

    app = Klein()
    
    @app.route('/users')
    def list_all_users(request):
        return 'all users'
    

    then you could divide it into two modules like this:

    # main.py
    app = Klein()
    
    # users.py - version 1
    from main import app
    
    @app.route('/users')
    # ...
    

    This is bad because it leads to several problems, the most immediate being circular import issues, but also this is only a separate module technically, not logically: you can't really re-use that module with another app, or test it in isolation.

    An easy way to help that would be to use dependency injection:

    # main.py
    from users import add_users_routes
    
    app = Klein()
    add_users_routes(app)
    
    # users.py - version 2
    
    def list_all_users(request): 
        return 'all_users'
    
    def add_users_routes(app):
        app.route('/users')(list_all_users)
    

    Now users is a separate logical module, but it's a bit awkward, with the central add_users_routes function. We could use Klein's .resource() to help that:

    # users.py - version 3
    users = Klein()
    
    @users.route('/')
    def list_all_users(request):
        return 'all users'
    
    def add_users_routes(app):
        @app.route('/users', branch=True)
        def branch_to_users(request):
            return users.resource()
    

    This is already pretty nice, could maybe use some helpers so that you wouldn't need to implement that branch function, but is reusable and possible to test in isolation. The problem however is, routing to a Klein resource returns control to twisted.web, which then calls .render() on the nested resource, which causes a werkzeug map bind, etc - it's a performance hit. A simple hello-world-grade benchmark shown that a root Klein can serve ~2200 requests per second, routing one branch deep: ~1700, two branches deep: ~1400 (experience with flask's blueprints shows that 2 levels of nesting are enough in practice)

    I'm aware Klein is a web framework, and web applications aren't typically constrained by strict real-time requirements, and they're often easy to scale, but I think Klein needs some guideline on structuring applications, and while we're at it, might as well make it fast :)

    Basically I think we want the syntax of users.py version 2, with the performance of version 3. Here's how flask does it (translated to Klein):

    # main.py
    from users import users_blueprint
    app = Klein()
    users_blueprint.register(app, url_prefix='/users')
    
    # users.py
    users_blueprint = Blueprint()
    
    @users_blueprint.route('/')
    # ...
    

    The Blueprint is simply a container that records all @route() calls it was used for, and does them on the app when .register is called. This makes it only a setup-time thing, with no runtime (performance) effects.

    I've put together a proof-of-concept implementation for reference, see https://github.com/tehasdf/klein/tree/blueprints (here's an example.rst in the repo)

    opened by tehasdf 30
  • Added documentation for using decorators and flexible route handling

    Added documentation for using decorators and flexible route handling

    The following Pull Request focuses on exploring different options while registering new routes on Klein. The example provided shows primarily two things:

    • How to use decorators to avoid duplication of code i.e. request.setHeader('Content-Type', 'application/json') and an example of key authorization
    • Show other ways to register routes dynamically wrapping the klein instance in a custom class as instance attribute
    documentation 
    opened by larsx2 15
  • RFC: Drop CI support for Python 3.5

    RFC: Drop CI support for Python 3.5

    Usage stats via pypistats python_minor klein --last-month:

    | category | percent | downloads | |----------|--------:|----------:| | 2.7 | 46.53% | 10,612 | | 3.7 | 21.11% | 4,815 | | 3.6 | 21.09% | 4,809 | | 3.8 | 7.10% | 1,619 | | 3.5 | 2.30% | 525 | | null | 1.64% | 374 | | 3.4 | 0.23% | 52 | | 2.6 | 0.00% | 1 | | Total | | 22,807 |

    Date range: 2020-05-01 - 2020-05-31

    opened by wsanchez 14
  • Producer not being unregistered when wrapping static.File

    Producer not being unregistered when wrapping static.File

    (Using Klein master and Twisted 13.2.0)

    Hi, just started using Klein for a small project, and I noticed that whenever I return static.File from a route-decorated function or method, I will intermittently see "Producer was not unregistered" when accessing files in the directory being served by static.File.

    Plain old twisted.web works, this error only shows up when using Klein.

    Simple example, run with "twistd --nodaemon web --class=testing.resource":

    testing.py

    from klein import resource, route
    
    from twisted.web import static
    
    
    @route('/files/', branch=True)
    def files(request):
        return static.File('/Some/Directory/')
    

    And lastly, the traceback from the logfile:

    2013-11-13 10:47:26-0600 [HTTPChannel,0,127.0.0.1] 127.0.0.1 - - [13/Nov/2013:16:47:25 +0000] "GET /files/robots.txt HTTP/1.1" 200 27 "http://127.0.0.1:8080/files/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_5) AppleWebKit/537.71 (KHTML, like Gecko) Version/6.1 Safari/537.71" 2013-11-13 10:47:26-0600 [HTTPChannel,0,127.0.0.1] Unhandled Error Traceback (most recent call last): Failure: exceptions.RuntimeError: Producer was not unregistered for /files/robots.txt

    opened by ldanielburr 12
  • Suggest

    Suggest "::" as a value for run(host) to encourage ipv6 support

    The fact that "::" works for ipv4 connections as well surprises me but seems to be true on linux. I'm not sure what layer is making that work.

    opened by drewp 11
  • Added Klein extension support.

    Added Klein extension support.

    Hello,

    This pull request is to introduce support of the dynamic extension module loading into the klein.ext namespace.

    I've also moved _call method from module static namespace to Klein object methods. This is because I'll have to inject to this exact spot in my future extension (I am planning to create an extension that introduces injector support to Klein route handlers).

    opened by VRGhost 11
  • Enable mypy-zope plugin

    Enable mypy-zope plugin

    Enable Mypy-Zope so that we can properly type check the use of Zope Interface classes and remove the various hacks we have in place to make Mypy happy without the plugin.

    feature 
    opened by wsanchez 10
  • test_form failed with treq 20.4.1

    test_form failed with treq 20.4.1

    I'm the maintainer of Arch Linux package python-klein, and I run a periodic script to check compatibility among Python packages. Recently I notice tests in python-klein no longer work with python-treq 20.4.1.

    Steps to reproduce:

    1. Clone commit c91085d3b3a4b3521e1527fff82fa970c004eb2a of this repo

    2. Change the following line to treq==20.4.1 https://github.com/twisted/klein/blob/c91085d3b3a4b3521e1527fff82fa970c004eb2a/tox.ini#L46

    3. Run tox -e coverage-py38-twcurrent

    Actual results:

    [FAIL]
    Traceback (most recent call last):
      File "/home/yen/tmp/klein/.tox/coverage-py38-twcurrent/lib/python3.8/site-packages/klein/test/test_form.py", line 473, in test_customParameterValidation
        self.assertTrue(errorText.endswith("'not a number'"))
      File "/home/yen/tmp/klein/.tox/coverage-py38-twcurrent/lib/python3.8/site-packages/twisted/trial/_synctest.py", line 397, in assertTrue
        super(_Assertions, self).assertTrue(condition, msg)
      File "/usr/lib/python3.8/unittest/case.py", line 765, in assertTrue
        raise self.failureException(msg)
    twisted.trial.unittest.FailTest: False is not true
    
    klein.test.test_form.TestForms.test_customParameterValidation
    ===============================================================================
    [FAIL]
    Traceback (most recent call last):
      File "/home/yen/tmp/klein/.tox/coverage-py38-twcurrent/lib/python3.8/site-packages/klein/test/test_form.py", line 409, in test_handlingGET
        self.assertEqual(calls, [(u"hello, big world", 4321)])
      File "/home/yen/tmp/klein/.tox/coverage-py38-twcurrent/lib/python3.8/site-packages/twisted/trial/_synctest.py", line 434, in assertEqual
        super(_Assertions, self).assertEqual(first, second, msg)
      File "/usr/lib/python3.8/unittest/case.py", line 912, in assertEqual
        assertion_func(first, second, msg=msg)
      File "/usr/lib/python3.8/unittest/case.py", line 1118, in assertListEqual
        self.assertSequenceEqual(list1, list2, msg, seq_type=list)
      File "/usr/lib/python3.8/unittest/case.py", line 1100, in assertSequenceEqual
        self.fail(msg)
    twisted.trial.unittest.FailTest: Lists differ: [('hello, big+world', 4321.0)] != [('hello, big world', 4321)]
    
    First differing element 0:
    ('hello, big+world', 4321.0)
    ('hello, big world', 4321)
    
    - [('hello, big+world', 4321.0)]
    ?              ^            --
    
    + [('hello, big world', 4321)]
    ?              ^
    
    
    klein.test.test_form.TestForms.test_handlingGET
    

    Expected results: tests pass

    bug 
    opened by yan12125 10
  • Release 20.6 (old branch)

    Release 20.6 (old branch)

    This PR is a Klein 20.6 release.

    The primary goal for this release is to ship all work that's currently been done with support for Python 2.7 before we drop support for Python 2.7, so that we leave the 2.7 users with the latest available progress.

    In addition to incrementing the version, this PR adds a script for automating the release process.

    opened by wsanchez 10
  • Reconsider combined usage of bytes and text in new headers API.

    Reconsider combined usage of bytes and text in new headers API.

    The new headers API allows headers to be accessed and set using either bytes or text for the header names, as long as the same type is returned or provided for corresponding values.

    @moshez points out that this is icky and suggests that we use separate API for bytes and text, instead of having this polymorphism.

    The polymorphic API follows the pattern used by twisted.web.http_headers.Headers does.

    This ticket is here to solicit input on the path forward.

    improvement 
    opened by wsanchez 9
  • Klein.url_for() for reverse URL mapping

    Klein.url_for() for reverse URL mapping

    I'd like to propose Klein.url_for() method for reverse URL mapping.

    def url_for(self, request, endpoint, values = None, method = None, force_external = False, append_unknown = True)
    

    request is the Request object. It is used to obtain correct hostname for external links. Other arguments are just like in Werkzeug's MapAdapter.build().

    It can be used like this:

    from klein import route, run, url_for
    
    @route('/user/<username>')
    def user_page(request, username):
        return "Welcome to {}'s homepage".format(username)
    
    @route('/')
    def homepage(request):
        users = ['Alice', 'Bob', 'Carl']
        return '<br/>'.join([
            '<a href="{link}">{username}</a>'.format(
                link=url_for(request, 'user_page', {'username': username}),
                username=username)
            for username in users
        ])
    
    run('localhost', 8080)
    

    Actually, Klein already has url_for() method on IKleinRequest that is assumed to be used like this:

    @app.route("/")
    def homepage(request):
        krequest = IKleinRequest(request)
        url = krequest.url_for('user_page', {'username': username})
    

    But this looks like a piece of confusing magic. How does request know about url-mapping? Why are we asking the request to do url mapping, not the app? And this is working by exploiting the fact that Request is Componentized that can be problematic as described in #31. Having url_for() method on app seems more reasonable.

    Questions:

    • request argument to url_for is needed only if force_external=True. Most of the links are internal, so it might be more convenient to make request arg optional. May be have two methods: url_for(endpoint, ...) that always returns internal link and external_url_for(request, endpoint, ...) for external ones?

    If overall concept will be accepted I will add a docstring and example in docs.

    opened by IlyaSkriblovsky 9
  • AttributeError: module 'OpenSSL.SSL' has no attribute 'TLS_METHOD'

    AttributeError: module 'OpenSSL.SSL' has no attribute 'TLS_METHOD'

    When I import klein (i.e.: from klein import Klein), I get an error that concludes in the following lines:

     File "/usr/local/lib/python3.7/dist-packages/twisted/internet/_sslverify.py", line 1807, in fromOpenSSLCipherString
        SSL.TLS_METHOD,
    AttributeError: module 'OpenSSL.SSL' has no attribute 'TLS_METHOD'
    

    Appears related to this twisted issue.

    opened by thisAmericanLife 1
  • Twisted fools, hope you have a tragic life and painful death.

    Twisted fools, hope you have a tragic life and painful death.

    Death to twisted loser slave devs. Death to those monkeys for naming their garbage programs with disgusting & racist & childish (I'm referring to that stupid 6-letter word which comes after that stupid kiddish program starting with the word "py"). Hope your throats get slit, you daft imbeciles. Death to you and every idiot who uses that disgusting 6-letter childish word.

    Death to open source. Death to you garbage mainstream propaganda slaves. Death to you twisted devs. Hope you have a tragic life and painful death.

    opened by ghost 0
  • Death to you garbage mainstream propaganda slaves

    Death to you garbage mainstream propaganda slaves

    Death to twisted loser slave devs.

    Death to those monkeys for naming their garbage programs with disgusting & racist & childish (I'm referring to that stupid 6-letter word which comes after that stupid kiddish program starting with the word "py"). Hope your throats get slit, you daft imbeciles. Death to you and every idiot who uses that disgusting 6-letter childish word. Death to open source. Death to you garbage mainstream propaganda slaves. Death to you twisted devs. Hope you have a tragic life and painful death.

    opened by ghost 0
  • Death to twisted loser slave devs

    Death to twisted loser slave devs

    Death to twisted loser slave devs.

    Death to those monkeys for naming their garbage programs with disgusting & racist & childish (I'm referring to that stupid 6-letter word which comes after that stupid kiddish program starting with the word "py").

    Hope your throats get slit, you daft imbeciles. Death to you and every idiot who uses that disgusting 6-letter childish word. Death to open source. Death to you garbage mainstream propaganda slaves. Death to you twisted devs. Hope you have a tragic life and painful death.

    opened by ghost 0
  • KleinResourceTests.test_addSlash fails on Musl or glibc based system

    KleinResourceTests.test_addSlash fails on Musl or glibc based system

    Gentoo bug: https://bugs.gentoo.org/865677

    Full build log: https://865677.bugs.gentoo.org/attachment.cgi?id=800049

    ================================== FAILURES ===================================
    _______________________ KleinResourceTests.test_addSlash _______________________
    
    self = <klein.test.test_resource.KleinResourceTests testMethod=test_addSlash>
    
        def test_addSlash(self) -> None:
            app = self.app
            request = MockRequest(b"/foo")
        
            @app.route("/foo/")
            def foo(request: IRequest) -> KleinRenderable:
                return "foo"
        
            d = _render(self.kr, request)
        
            self.assertFired(d)
            self.assertEqual(
                request.setHeader.call_count,
                3,
            )
    >       request.setHeader.assert_has_calls(
                [
                    call(b"Content-Type", b"text/html; charset=utf-8"),
                    call(b"Content-Length", b"258"),
                    call(b"Location", b"http://localhost:8080/foo/"),
                ]
            )
    
    app        = <klein._app.Klein object at 0x7f463a37d610>
    d          = <Deferred at 0x7f4637efc730 current result: None>
    foo        = <function KleinResourceTests.test_addSlash.<locals>.foo at 0x7f4639dfa5e0>
    request    = <MockRequest at 0x7f463983cf70 method=GET uri=/foo clientproto=HTTP/1.1>
    self       = <klein.test.test_resource.KleinResourceTests testMethod=test_addSlash>
    
    src/klein/test/test_resource.py:642: 
    _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
    
    self = <Mock id='139939562899008'>
    calls = [call(b'Content-Type', b'text/html; charset=utf-8'), call(b'Content-Length', b'258'), call(b'Location', b'http://localhost:8080/foo/')]
    any_order = False
    
        def assert_has_calls(self, calls, any_order=False):
            """assert the mock has been called with the specified calls.
            The `mock_calls` list is checked for the calls.
        
            If `any_order` is False (the default) then the calls must be
            sequential. There can be extra calls before or after the
            specified calls.
        
            If `any_order` is True then the calls can be in any order, but
            they must all appear in `mock_calls`."""
            expected = [self._call_matcher(c) for c in calls]
            cause = next((e for e in expected if isinstance(e, Exception)), None)
            all_calls = _CallList(self._call_matcher(c) for c in self.mock_calls)
            if not any_order:
                if expected not in all_calls:
                    if cause is None:
                        problem = 'Calls not found.'
                    else:
                        problem = ('Error processing expected calls.\n'
                                   'Errors: {}').format(
                                       [e if isinstance(e, Exception) else None
                                        for e in expected])
    >               raise AssertionError(
                        f'{problem}\n'
                        f'Expected: {_CallList(calls)}'
                        f'{self._calls_repr(prefix="Actual").rstrip(".")}'
                    ) from cause
    E               AssertionError: Calls not found.
    E               Expected: [call(b'Content-Type', b'text/html; charset=utf-8'),
    E                call(b'Content-Length', b'258'),
    E                call(b'Location', b'http://localhost:8080/foo/')]
    E               Actual: [call(b'Content-Type', b'text/html; charset=utf-8'),
    E                call(b'Content-Length', b'239'),
    E                call(b'Location', b'http://localhost:8080/foo/')]
    
    all_calls  = [call(b'Content-Type', b'text/html; charset=utf-8'),
     call(b'Content-Length', b'239'),
     call(b'Location', b'http://localhost:8080/foo/')]
    any_order  = False
    calls      = [call(b'Content-Type', b'text/html; charset=utf-8'),
     call(b'Content-Length', b'258'),
     call(b'Location', b'http://localhost:8080/foo/')]
    cause      = None
    expected   = [call(b'Content-Type', b'text/html; charset=utf-8'),
     call(b'Content-Length', b'258'),
     call(b'Location', b'http://localhost:8080/foo/')]
    problem    = 'Calls not found.'
    self       = <Mock id='139939562899008'>
    
    /usr/lib/python3.8/unittest/mock.py:950: AssertionError
    =============================== warnings summary ===============================
    ../../../../../../../usr/lib/python3.8/site-packages/twisted/web/test/test_web.py:21
      /usr/lib/python3.8/site-packages/twisted/web/test/test_web.py:21: DeprecationWarning: twisted.test.proto_helpers.EventLoggingObserver was deprecated in Twisted 19.7.0: Please use twisted.internet.testing.EventLoggingObserver instead.
        from twisted.test.proto_helpers import EventLoggingObserver
    
    src/klein/_form.py:132: 1 warning
    src/klein/test/test_form.py: 14 warnings
      /var/tmp/portage/dev-python/klein-21.8.0/work/klein-21.8.0/src/klein/_form.py:132: DeprecationWarning: assoc is deprecated and will be removed after 2018/01.
        return attr.assoc(
    
    src/klein/test/test_form.py:38
      /var/tmp/portage/dev-python/klein-21.8.0/work/klein-21.8.0/src/klein/test/test_form.py:38: PytestCollectionWarning: cannot collect test class 'TestObject' because it has a __init__ constructor (from: src/klein/test/test_form.py)
        class TestObject:
    
    src/klein/test/test_form.py: 17 warnings
      /var/tmp/portage/dev-python/klein-21.8.0/work/klein-21.8.0/src/klein/_form.py:340: DeprecationWarning: assoc is deprecated and will be removed after 2018/01.
        yield attr.assoc(
    
    src/klein/test/test_resource.py::KleinResourceTests::test_explicitStaticBranch
      /var/tmp/portage/dev-python/klein-21.8.0/work/klein-21.8.0/src/klein/test/test_resource.py:596: ResourceWarning: unclosed file <_io.BufferedReader name='/var/tmp/portage/dev-python/klein-21.8.0/work/klein-21.8.0/src/klein/test/__init__.py'>
        expected = open(
    
    src/klein/test/test_resource.py::KleinResourceTests::test_staticRoot
      /var/tmp/portage/dev-python/klein-21.8.0/work/klein-21.8.0/src/klein/test/test_resource.py:578: ResourceWarning: unclosed file <_io.BufferedReader name='/var/tmp/portage/dev-python/klein-21.8.0/work/klein-21.8.0/src/klein/test/__init__.py'>
        expected = open(
    
    -- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
    =========================== short test summary info ============================
    FAILED src/klein/test/test_resource.py::KleinResourceTests::test_addSlash - A...
    ============ 1 failed, 241 passed, 36 warnings in 108.70s (0:01:48) ============
     * ERROR: dev-python/klein-21.8.0::gentoo failed (test phase):
     *   pytest failed with python3.8
    
    opened by dol-sen 9
Releases(16.12.0)
Owner
Twisted Matrix Labs
Twisted Matrix Labs
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
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
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
easyopt is a super simple yet super powerful optuna-based Hyperparameters Optimization Framework that requires no coding.

easyopt is a super simple yet super powerful optuna-based Hyperparameters Optimization Framework that requires no coding.

Federico Galatolo 9 Feb 04, 2022
Developer centric, performant and extensible Python ASGI framework

Introduction xpresso is an ASGI web framework built on top of Starlette, Pydantic and di, with heavy inspiration from FastAPI. Some of the standout fe

Adrian Garcia Badaracco 119 Dec 27, 2022
Pulumi-checkly - Checkly Pulumi Provider With Python

🚨 This project is still in very early stages and is not stable, use at your own

Checkly 16 Dec 15, 2022
Flask + Docker + Nginx + Gunicorn + MySQL + Factory Method Pattern

This Flask project is reusable and also an example of how to merge Flask, Docker, Nginx, Gunicorn, MySQL, new: Flask-RESTX, Factory Method design pattern, and other optional dependencies such as Dyna

Facundo Padilla 19 Jul 23, 2022
PipeLayer is a lightweight Python pipeline framework

PipeLayer is a lightweight Python pipeline framework. Define a series of steps, and chain them together to create modular applications

greaterthan 64 Jul 21, 2022
A Python package to easily create APIs in Python.

API_Easy An Python Package for easily create APIs in Python pip install easy-api-builder Requiremnets: = python 3.6 Required modules -- Flask Docume

Envyre-Coding 2 Jan 04, 2022
Asita is a web application framework for python based on express-js framework.

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

Mattéo 4 Nov 16, 2021
Light, Flexible and Extensible ASGI API framework

Starlite Starlite is a light, opinionated and flexible ASGI API framework built on top of pydantic and Starlette. Check out the Starlite documentation

Na'aman Hirschfeld 1.6k Jan 09, 2023
Library for building WebSocket servers and clients in Python

What is websockets? websockets is a library for building WebSocket servers and clients in Python with a focus on correctness and simplicity. Built on

Aymeric Augustin 4.3k Dec 31, 2022
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
Low code web framework for real world applications, in Python and Javascript

Full-stack web application framework that uses Python and MariaDB on the server side and a tightly integrated client side library.

Frappe 4.3k Dec 30, 2022
WAZO REST API for the call management of the C4 infrastructure

wazo-router-calld wazo-router-calld provides REST API for the C4 infrastructure. Installing wazo-router-calld The server is already provided as a part

Wazo Platform 4 Dec 21, 2022
web.py is a web framework for python that is as simple as it is powerful.

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

5.8k Dec 30, 2022
A 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
A PC remote controller for YouTube and Twitch

Lazynite Lazynite is a PC remote controller for YouTube and Twitch on Telegram. Features Volume control; Browser fullscreen / video fullscreen; PC shu

Alessio Celentano 46 Nov 12, 2022
FastAPI framework, high performance, easy to learn, fast to code, ready for production

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

Sebastián Ramírez 53k Jan 02, 2023
A simple Tornado based framework designed to accelerate web service development

Toto Toto is a small framework intended to accelerate web service development. It is built on top of Tornado and can currently use MySQL, MongoDB, Pos

Jeremy Olmsted-Thompson 61 Apr 06, 2022