Saravanan666/pypi-org huggingface dataset:
Package: tornado-mstp
Tornado MSTPA tornado MSTP library, using WebSocket.Installationpip install tornado_mstpEasy ExamplesSee repo's directory named 'examples'.UsageServerAs a server-side application usingtornado_mstp. You should first create a
handler class inherited fromMstpSocketHandler.fromtornado_mstpimportMstpSocketHandlerclassMyMstpSocketHandler(MstpSocketHandler):passThere are two optional class attributes,automatic_closing_time(default to 10) andver(default to "0.1"), that indicate MSTP server information
need to be set.fromtornado_mstpimportMstpSocketHandlerclassMyMstpSocketHandler(MstpSocketHandler):automatic_closing_time=15ver="0.1"loginmethodMUSTbe overridden to make an authorization, and returns atornado_mstp.schema.LoginResponse.fromtypingimportOptionalfromtornado_mstpimportMstpSocketHandlerfromtornado_mstp.schemaimportLoginResponseclassMyMstpSocketHandler(MstpSocketHandler):automatic_closing_time=15ver="0.1"asyncdeflogin(self,*,secret:Optional[str]=None)->LoginResponse:# your login processingreturnLoginResponse(status=True,connection_interval=300,session_alive_time=300,session_id="ajsdkjalskdjlka")So asreconnect, that returns atornado_mstp.schema.ReconnectResponse.fromtypingimportOptionalfromtornado_mstpimportMstpSocketHandlerfromtornado_mstp.schemaimportReconnectResponseclassMyMstpSocketHandler(MstpSocketHandler):automatic_closing_time=15ver="0.1"asyncdefreconnect(self,*,session_id:Optional[str]=None)->ReconnectResponse:# your reconnect logicsreturnReconnectResponse(status=True)There is no need to worry about tornado websocket handler'son_messagemethod.
Each MSTP package type of message has a callback function who needs to be
implemented. For example, for segment handling.fromtypingimportOptionalfromtornado_mstpimportMstpSocketHandlerfromtornado_mstp.schemaimportContentTypeclassMyMstpSocketHandler(MstpSocketHandler):automatic_closing_time=15ver="0.1"asyncdefhandle_segment(self,package_id:Optional[str]=None,message_index:Optional[int]=None,segment_index:Optional[int]=None,is_end:Optional[bool]=None,content_type:Optional[ContentType]=None,content:Optional[str]=None)->None:print(f"received content:{content}")After implementing all callback functions, server can handle any MSTP packages
as you want.ClientAs a client-side connection using tornado_mstp. You can just create anmstpsocket_connectusingtornado_mstp.mstpsocket_connect. It has the
same usage oftornado.websocket.websocket_connectwith some extra arguments.importasynciofromtypingimportOptionalfromtornado_mstpimportmstpsocket_connectfromtornado_mstpimportMstpSocketClientConnectionclassMyMstpSocketClientConnection(MstpSocketClientConnection):asyncdefhandle_login_response(self,*,status:Optional[bool]=None,connection_interval:Optional[int]=None,session_alive_time:Optional[int]=None,session_id:Optional[str]=None,reason:Optional[str]=None)->None:print(session_id)asyncdefmain():awaitmstpsocket_connect(url="mstp://localhost:8005/mstp",secret="secret",connection_class=MyMstpSocketClientConnection)f=asyncio.Future()awaitfif__name__=='__main__':asyncio.run(main())
Package: tornado-NCTU-OAuth
#NCTU-OAuth台灣國立交通大學推出 [NCTU OAuth]('https://id.nctu.edu.tw/')你可以透過本套件在tornado開發中使用NCTU OAuth根據[交通大學 OAuth 服務 - 開發者說明文件](https://id.nctu.edu.tw/docs/)進行對應的開發，以下是一個使用本套件的範例```Pythonimport tornadoimport tornado.webimport tornado.ioloopimport jsonfrom oauth import NCTUOAuth2MixinREDIRECT_URI = 'http://example.com:8080/auth/'CLIENT_ID = ''CLIENT_SECRET = ''class OAuthHandler(tornado.web.RequestHandler, NCTUOAuth2Mixin):@tornado.gen.coroutinedef get(self):code = self.get_argument('code', None)if code:access = yield self.get_authenticated_user(redirect_uri=REDIRECT_URI,code=code)self.set_secure_cookie('access', json.dumps(access))self.redirect('/')else:yield self.authorize_redirect(redirect_uri=REDIRECT_URI,client_id=self.settings[self._OAUTH_SETTINGS_KEY]['client_id'],scope=['profile'],response_type='code')class IndexHandler(tornado.web.RequestHandler, NCTUOAuth2Mixin):@tornado.gen.coroutinedef get(self):if self.get_secure_cookie('access'):access = json.loads(self.get_secure_cookie('access').decode())try:profile = yield self.oauth2_request(self._OAUTH_PROFILE_URL,access=access)self.finish(json.dumps(profile))except:self.redirect('/auth/')else:self.redirect('/auth/')if __name__ == '__main__':app = tornado.web.Application([('/', IndexHandler),('/auth/', OAuthHandler),],debug=True,cookie_secret='secret!',NCTU_OAuth2={'client_id': CLIENT_ID,'client_secret': CLIENT_SECRET})app.listen(8080)tornado.ioloop.IOLoop().instance().start()```
Package: tornado-openapi3
Tornado OpenAPI 3 request and response validation library.Provides integration between theTornadoweb framework andOpenapi-corelibrary for validating request and response objects against anOpenAPI 3specification.Full documentation is available athttps://tornado-openapi3.readthedocs.ioUsageAdding validation to request handlersimporttornado.ioloopimporttornado.webfromtornado_openapi3.handlerimportOpenAPIRequestHandlerclassMyRequestHandler(OpenAPIRequestHandler):spec_dict={"openapi":"3.0.0","info":{"title":"Simple Example","version":"1.0.0",},"paths":{"/":{"get":{"responses":{"200":{"description":"Index","content":{"text/html":{"schema":{"type":"string"},}},}}}}},}classRootHandler(MyRequestHandler):asyncdefget(self):self.finish("Hello, World!")if__name__=="__main__":app=tornado.web.Application([(r"/",RootHandler)])app.listen(8888)tornado.ioloop.IOLoop.current().start()Validating responses in testsimportunittestimporttornado.webfromtornado_openapi3.testingimportAsyncOpenAPITestCaseclassRootHandler(tornado.web.RequestHandler):asyncdefget(self):self.finish("Hello, World!")classBaseTestCase(AsyncOpenAPITestCase):spec_dict={"openapi":"3.0.0","info":{"title":"Simple Example","version":"1.0.0",},"paths":{"/":{"get":{"responses":{"200":{"description":"Index","content":{"text/html":{"schema":{"type":"string"},}},}}}}},}defget_app(self):returntornado.web.Application([(r"/",RootHandler)])deftest_root_endpoint(self):response=self.fetch("/")self.assertEqual(200,response.code)self.assertEqual(b"Hello, World!",response.body)if__name__=="__main__":unittest.main()ContributingGetting StartedThis project usesPoetryto manage its dependencies. To set up a local
development environment, just run:poetryinstallFormatting CodeTheBlacktool is used by this project to format Python code. It is included
as a development dependency, and should be run on all committed code. To format
code prior to committing it and submitting a PR, run:poetryrunblack.Running Testspytestis the preferred test runner for this project. It is included as a
development dependency, and is configured to track code coverage,Flake8style compliance, andBlackcode formatting. Tests can be run in your
development environment by running:poetryrunpytestAdditionally, tests can be run usingtox, which will run the tests using
multiple versions of both Python and Tornado to ensure broad compatibility.Configuring HypothesisMany of the tests make use ofHypothesisto specify their expectations and
generate a large volume of randomized test input. Because of this, the tests may
take a long time to run on slower computers. Two profiles are defined for
Hypothesis to use which can be selected by setting theHYPOTHESIS_PROFILEenvironment variable to one of the following values:ciRuns tests using the default Hypothesis settings (100 examples per test) and
no completion deadline.devThe fastest profile, meant for local development only. Uses only 10 examples
per test with no completion deadline.
Package: tornado-problem-details
This library provides a version oftornado.web.RequestHandler.send_errorthat speaksapplication/problem+jsoninstead of HTML.  The easiest
way to use this library is to inherit fromproblemdetails.ErrorWriterand raiseproblemdetails.Problemexceptions instead ofHTTPError.classMyHandler(problemdetails.ErrorWriter,web.RequestHandler):defget(self):ifnotself.do_something_hard():raiseproblemdetails.Problem(status_code=500,title='Failed to do_something_hard')HTTP/1.1500Internal Server ErrorContent-Type:application/problem+json{"status":500,"title":"Failed to do_something_hard","type":"https://tools.ietf.org/html/rfc7231#section-6.6.1"}You can easily construct more substantial response documents by passing
additional keyword parameters to theproblemdetails.Probleminitializer.  They become top-level properties in the response document.You can also callsend_errordirectly and produce a response docuemnt.
The following snippet produces the same output as the previous snippet.classMyHandler(problemdetails.ErrorWriter,web.RequestHandler):defget(self):try:self.do_something_hard()exceptSomeExceptionaserror:self.send_error(500,title="Failed to do_something_hard")The interface oftornado.web.RequestHandler.send_erroris less expressive
since keyword parameters may be swallowed by intervening code.  The only
parameters that are recognized are:instance,title, andtype.
Use the exception-based interface for more substantial documents.
Package: tornado-profile
Add this library to your routes to add a REST API for profiling your Tornado application.Usageimport tornado
from tornado_profile import TornadoProfiler

port = 8888
routes = []

routes += TornadoProfiler().get_routes()
app = tornado.web.Application(routes)
app.listen(port)
tornado.ioloop.IOLoop.current().start()

# Create with optional route prefix and base class for handlers
routes += TornadoProfiler(prefix="", handler_base_class=custom_base_class).get_routes()Installation$ pip install tornado-profileAPI# Start the profiler
POST /profiler

# Stop the profiler
DELETE /profiler

# Get the profiler status
GET /profiler
{"running": true/false}

# Get the profiler statistics
GET /profiler/stats
{
    "statistics": [
        {
            "path": ...,
            "line": ...,
            "func_name": ...,
            "num_calls": ...,
            "total_time": ...,
            "total_time_per_call": ...,
            "cum_time": ...,
            "cum_time_per_call": ...
        }
        ...
    ]
}

# Get the profiler statistics with optional query parameters
GET /profiler/stats?count=1&sort=num_calls&strip_dirs=false

# Clear the profiler statistics
DELETE /profiler/statsToolsCommand Line:https://github.com/dimrozakis/tornado-profile-client
Package: tornado-profiler
Tornado-ProfilerA profiler measures endpoints defined in your tornado application.ScreenshotsDashboard: Give a summary of all datasIf an endpoint has been accessed before, you can see its summary data as follows.Filtering: Give filtered datasYou can create filters to get datas that meet the criterias.Context: Give all details of a requestYou can get all details of a request as you wish.InstallationPyPI version:$ pip install tornado-profilerDevelopment version:$ pip install https://github.com/garenchan/tornado-profiler/zipball/masterQuick StartJust add a few lines to you codes:# demo.pyimporttornado.ioloopimporttornado.webfromtornado_profilerimportProfilerclassMainHandler(tornado.web.RequestHandler):defget(self):self.write("main")classHelloHandler(tornado.web.RequestHandler):defget(self):self.write("Hello, world")defmake_app():app=tornado.web.Application([(r"/",MainHandler),])# use to store measurement datasbackend={"engine":"sqlalchemy",}# instantiate profilerprofiler=Profiler(backend)# do something to your appprofiler.init_app(app)# you can add some rules that won't be profiled hereapp.add_handlers(r".*",[(r"/hello",HelloHandler),])returnappif__name__=="__main__":app=make_app()app.listen(8888)tornado.ioloop.IOLoop.current().start()Now run yourdemo.pyand make some requests as follows:$ curl http://127.0.0.1:8888/
$ curl http://127.0.0.1:8888/helloIf everything is ok, tornado-profiler will measure these requests. You can see the result heading tohttp://127.0.0.1:8888/tornado-profileror get results as JSONhttp://127.0.0.1:8888/tornado-profiler/api/measurementsData Storage BackendYou can use some databases to store your measurement data, such as SQLite, Mysql. The drivers we support are shown as follows:SQLAlchemyIn order to use SQLAlchemy, just specify backend's engine as "sqlalchemy". This will useSQLiteby default and save it totornado_profiler.dbin your working directory.backend = {
    "engine": "sqlalchemy",
}If your want to change default sqlite database filename or use other databases, you need to setdb_urlmanually:backend = {
    "engine": "sqlalchemy",
    "db_url": "sqlite:///dbname.db",
}

backend = {
    "engine": "sqlalchemy",
    "db_url": "mysql+<driver-name>://user:password@<host>[:<port>]/<dbname>",
}Setting some attributes of SQLAlchemy is also necessary, you just need to pass them into the backend dict:backend = {
    "engine": "sqlalchemy",
    "db_url": "mysql+<driver-name>://user:password@<host>[:<port>]/<dbname>",
    # attributes
    "pool_recycle": 3600,
    "pool_timeout": 30,
    "pool_size": 30,
    "max_overflow": 20,
}In some scenarios, we do not want to persist measurement datas, we can use the in-memory database of SQLite and datas will be lost when your web server stops or restarts:backend = {
    "engine": "sqlalchemy",
    "db_url": "sqlite://",
}Other Driverscoming soon!CommentIf you have any other requirements, please submit PR or issues. I will reply to you as soon as possible.
Package: tornado-prometheus
HTTP metrics for a tornado applicationInstallingpipinstalltornado-prometheusUsagefromtornado.webimportApplication,RequestHandlerfromtornado.ioloopimportIOLoopfromtornado_prometheusimportPrometheusMixIn,MetricsHandlerclassSampleApp(PrometheusMixIn,Application):passif__name__=='__main__':app=SampleApp([(r"/metrics",MetricsHandler),])app.listen(8888)IOLoop.current().start()Example output for metric route# HELP tornado_http_request_duration_seconds HTTP request duration in seconds
# TYPE tornado_http_request_duration_seconds histogram
tornado_http_request_duration_seconds_bucket{handler="StatusHandler",le="0.01",method="GET"} 0.0
tornado_http_request_duration_seconds_bucket{handler="StatusHandler",le="0.05",method="GET"} 0.0
tornado_http_request_duration_seconds_bucket{handler="StatusHandler",le="0.1",method="GET"} 1.0
tornado_http_request_duration_seconds_bucket{handler="StatusHandler",le="0.5",method="GET"} 1.0
tornado_http_request_duration_seconds_bucket{handler="StatusHandler",le="0.75",method="GET"} 1.0
tornado_http_request_duration_seconds_bucket{handler="StatusHandler",le="1.0",method="GET"} 1.0
tornado_http_request_duration_seconds_bucket{handler="StatusHandler",le="2.5",method="GET"} 2.0
tornado_http_request_duration_seconds_bucket{handler="StatusHandler",le="5.0",method="GET"} 2.0
tornado_http_request_duration_seconds_bucket{handler="StatusHandler",le="7.5",method="GET"} 2.0
tornado_http_request_duration_seconds_bucket{handler="StatusHandler",le="10.0",method="GET"} 2.0
tornado_http_request_duration_seconds_bucket{handler="StatusHandler",le="15.0",method="GET"} 2.0
tornado_http_request_duration_seconds_bucket{handler="StatusHandler",le="20.0",method="GET"} 2.0
tornado_http_request_duration_seconds_bucket{handler="StatusHandler",le="30.0",method="GET"} 2.0
tornado_http_request_duration_seconds_bucket{handler="StatusHandler",le="+Inf",method="GET"} 2.0

# HELP tornado_http_requests_total Total of HTTP requests processed
# TYPE tornado_http_requests_total counter
tornado_http_requests_total{handler="StatusHandler",method="GET",status="2xx"} 2.0
Package: tornado-proxy-handlers
# tornado-proxy-handlers
Tornado proxy handlers for HTTP requests and web sockets[![Build Status](https://github.com/timkpaine/tornado-proxy-handlers/workflows/Build%20Status/badge.svg?branch=main)](https://github.com/timkpaine/tornado-proxy-handlers/actions?query=workflow%3A%22Build+Status%22)
[![Coverage](https://codecov.io/gh/timkpaine/tornado-proxy-handlers/branch/main/graph/badge.svg)](https://codecov.io/gh/timkpaine/tornado-proxy-handlers)
[![License](https://img.shields.io/github/license/timkpaine/tornado-proxy-handlers.svg)](https://pypi.python.org/pypi/tornado-proxy-handlers/)
[![PyPI](https://img.shields.io/pypi/v/tornado-proxy-handlers.svg)](https://pypi.python.org/pypi/tornado-proxy-handlers/)## Installpip install tornado-proxy-handlersor from sourcepython setup.py install## Overview
This project contains 2 proxy handlers:
- HTTP Handler
- Websocket HandlerThe websocket handler requires the http handler for599protocol switching.## Use
These are designed to be embedded in a tornado server that needs to proxy. They can also be run as a standalone proxy server via thetornado-proxycommand.
Package: tornado-razorpay
Python ASYNC bindings for interacting with the Razorpay API.InstallationThrough pip:pip installtornado-razorpayManually:python setup.py installUsageYou need to setup your key and secret using the following: You can find
your API keys athttps://dashboard.razorpay.com/#/app/keys.fromtornado_razorpayimportClientrazor=Client("<YOUR_API_KEY>","<YOUR_API_SECRET>")PaymentsCapture a paymentawaitrazor.payment.capture("<PAYMENT_ID>","<AMOUNT>")Fetch a particular paymentawaitrazor.payment.fetch("<PAYMENT_ID>")Fetch all paymentsawaitrazor.payment.all()RefundsInitiate a refundawaitrazor.refund.create("<PAYMENT_ID>")# for whole amountawaitrazor.refund.create("<PAYMENT_ID>",data={"amount":"<AMOUNT_TO_BE_REFUNDED>"})# for particular amountFetch a particular refundawaitrazor.refund.fetch("<PAYMENT_ID>","<REFUND_ID>")Fetch all refunds for a particular paymentawaitrazor.refund.all("<PAYMENT_ID>")Compliance and ErrorsResponse that you receive from the functions is`tornado.httpclient.HTTPResponseobject <http://tornadokevinlee.readthedocs.io/en/latest/httpclient.html#response-objects>`__
For the success of your API call can be determined ifresponse.code == 200isTrue. Please handle Errors
accordingly.NOTE: You will have to use Tornado’s IOLoop to use this API in Async. If
you are looking for Sync API’s or don’t know what this is, please go tohttps://github.com/razorpay/razorpay-python.
Package: tornado-redis-yield
Tornadois a Python web framework and
asynchronous networking library, originally developed atFriendFeed.  By using non-blocking network I/O, Tornado
can scale to tens of thousands of open connections, making it ideal forlong polling,WebSockets, and other
applications that require a long-lived connection to each user.Hello, worldHere is a simple “Hello, world” example web app for Tornado:importtornado.ioloopimporttornado.webimporttornado.gen#redis clientfromredis_cliimportredis_cliclassMainHandler(tornado.web.RequestHandler):defget(self):self.write("Hello, world")def_call_back(self,value,other_data=None):print(value)print(other_data)self.write(value)self.finish()@gen.coroutinedefpost(self):key="your redis_key"other_data={"key":key}yieldgen.redis_sleep(redis_cli.redis_cli,key,self._call_back,timeout=20,other_data=other_data)defmake_app():returntornado.web.Application([(r"/",MainHandler),])if__name__=="__main__":app=make_app()app.listen(8888)tornado.ioloop.IOLoop.current().start()This example does not use any of Tornado’s asynchronous features; for
that see thissimple chat room.DocumentationDocumentation and links to additional resources are available athttp://www.tornadoweb.org
Package: tornado-request-mapping
installpipinstall-Ugit+https://github.com/sazima/tornado_request_mappingA simple exampleimporttornado.ioloopfromtornado.websocketimportWebSocketHandlerimporttornado.webfromtornado_request_mappingimportrequest_mapping,Route@request_mapping("/test")classMainHandler(tornado.web.RequestHandler):@request_mapping('/get_by_id',method='get')asyncdeftest(self):self.write("Hello, world. get")@request_mapping('/update_by_id',method='post')asyncdeftest1(self):self.write("Hello, world. post")@request_mapping('/t')classMyHandler(tornado.web.RequestHandler):@request_mapping('/get_by_id',method='put')asyncdeftest(self):self.write("Hello, world. put")@request_mapping("/ws")classWshandler(WebSocketHandler):defopen(self,*args:str,**kwargs:str):print('open')defclose(self,code:int=None,reason:str=None)->None:print('close')defcheck_origin(self,origin:str)->bool:returnTrueif__name__=="__main__":app=tornado.web.Application()route=Route(app)route.register(MainHandler)route.register(MyHandler)route.register(Wshandler)app.listen(8888)tornado.ioloop.IOLoop.current().start()
Package: tornado-resource-handler
tornado_resource_handlerPython Boilerplate contains all the boilerplate you need to create a Python package.Free software: MIT licenseDocumentation:https://tornado-resource-handler.readthedocs.io.FeaturesTODOCreditsThis package was created withCookiecutterand theaudreyr/cookiecutter-pypackageproject template.History0.1.0 (2020-02-21)First release on PyPI.
Package: tornado-rest-easy
tornado_rest_easy - RESTful extension for tornadoThis library aims to make it quicker and easier to define a RESTful API in tornado. Originally inspired by github.com/rancavil/tornado-rest.Installationpip install tornado_rest_easyUsagefromtornado_rest_easyimportRestfulHandler,RestfulMetaType,get,postclassWidgetHandler(RestfulHandler,metaclass=RestfulMetaType):@get('/widgets')defall_widgets(self):return[widget1,widget2,...]@get('/widgets/<int:id>')defget_widget(self,id):returnwidgets[id]@post('/widgets'):defadd_widget(self):return'Widget added'app=Application(WidgetHandler.get_handlers(dict(db=db))LicenseNew BSD. Seelicense.
Package: tornadorestframework
######################Tornado REST framework######################.. image:: https://travis-ci.org/007gzs/tornado-rest-framework.svg?branch=master:target: https://travis-ci.org/007gzs/tornado-rest-framework.. image:: https://img.shields.io/pypi/v/tornadoapi.svg:target: https://pypi.org/project/tornadoapiTornado REST framework`【阅读文档】 <http://tornadoapi.readthedocs.io/zh_CN/latest/>`_。安装---------------------目前 tornadoapi 支持的 Python 环境有 2.7, 3.4, 3.5, 3.6 和 pypy。::pip install tornadoapi快速开始_____________________启动之前或启动脚本开始时配置环境变量::os.environ.setdefault("TORNADOAPI_SETTINGS_MODULE", "config.settings")config/settings.py 中增加自定义配置::DEBUG = TrueTEST = 1通过以下代码可以获取到settings参数::from tornadoapi.conf import settingssettings.TESTApiHandler调用示例::from tornadoapi.handler import ApiHandlerclass TestHandler(ApiHandler):test_param = fields.CharField(description='测试参数', default=None)test_choice = fields.ChoiceField(description='选择参数', default=None, choices=((0, '选项0'), (1, '选项1')))@classmethoddef get_return_sample(cls):return ErrCode.SUCCESS.get_res_dict(data={'test_param': '测试参数', 'test_choice' :'选择参数'})@classmethoddef get_handler_name(cls):return '测试'def get(self, *args, **kwargs):ret = {'test_param': self.test_param,'test_choice': self.test_choice}self.write_api(ret)示例项目---------------------`demo <https://github.com/007gzs/tornadoapi-example/>`_
Package: tornadose
An implementation of the publish/subscribe pattern for theTornadoweb
server.InstallationTornadose is on PyPI:$pipinstalltornadoseThis will grab the latest official release. Alternatively, or for development,
you can clone the repository and install it manually:$gitclonehttps://github.com/mivade/tornadose.git$cdtornadose$pipinstall-e.UsageA simple example of using server-sent events (a.k.a. EventSource):importrandomfromtornado.ioloopimportIOLoop,PeriodicCallbackfromtornado.webimportApplicationfromtornadose.handlersimportEventSourcefromtornadose.storesimportDataStorestore=DataStore()app=Application([(r'/',EventSource,{'store':store})],debug=True)app.listen(9000)loop=IOLoop.instance()PeriodicCallback(lambda:store.submit(random.random()),1000).start()loop.start()To monitor the stream withcurl:$curlhttp://localhost:9000or withHTTPie:$http-Sgetlocalhost:9000Additional demos can be found in thedemosdirectory.ContributingContributions, complaints, criticisms, and whatever else are welcome. The source
code and issue tracker can be found onGitHub.See alsoSome other implementations of server-sent events with Tornado include:tornado-ssetornado-eventsourceLicenseTornadose is freely available under the terms of the MIT license. SeeLICENSEfor details.
Package: tornado-smtp
This is a thin wrapper aroundsmtplib.SMTPandsmtplib.SMTP_SSLthat
provides asynchronous functions (coroutines) for use in Tornado
applications. It provides a single class,tornado_smtp.client.TornadoSMTP,
which encapsulates either anSMTPorSMTP_SSLinstance. The API has
intentionally been kept the same in order to make usage obvious.