Skip to content

Commit 84e136a

Browse files
committed
docs (Tornado): move Tornado docs to #5399
1 parent 7d91957 commit 84e136a

File tree

3 files changed

+35
-59
lines changed

3 files changed

+35
-59
lines changed

src/DIRAC/Core/Tornado/Server/TornadoREST.py

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -65,10 +65,12 @@ def web_users(self, count: int = 0):
6565
and we are running using executors, the methods you export cannot write
6666
back directly to the client. Please see inline comments for more details.
6767
68+
In order to pass information around and keep some states, we use instance attributes.
69+
These are initialized in the :py:meth:`.initialize` method.
70+
6871
The handler define the ``post`` and ``get`` verbs. Please refer to :py:meth:`.post` for the details.
6972
"""
7073

71-
# By default we enable all authorization grants
7274
USE_AUTHZ_GRANTS = ["SSL", "JWT", "VISITOR"]
7375
METHOD_PREFIX = "web_"
7476
LOCATION = "/"
@@ -116,15 +118,15 @@ def _getMethodName(self):
116118
@gen.coroutine
117119
def get(self, *args, **kwargs): # pylint: disable=arguments-differ
118120
"""Method to handle incoming ``GET`` requests.
119-
Note that all the arguments are already prepared in the :py:meth:`BaseRequestHandler.prepare` method.
121+
Note that all the arguments are already prepared in the :py:meth:`.prepare` method.
120122
"""
121123
retVal = yield IOLoop.current().run_in_executor(*self._prepareExecutor(args))
122124
self._finishFuture(retVal)
123125

124126
@gen.coroutine
125127
def post(self, *args, **kwargs): # pylint: disable=arguments-differ
126128
"""Method to handle incoming ``POST`` requests.
127-
Note that all the arguments are already prepared in the :py:meth:`BaseRequestHandler.prepare` method.
129+
Note that all the arguments are already prepared in the :py:meth:`.prepare` method.
128130
"""
129131
retVal = yield IOLoop.current().run_in_executor(*self._prepareExecutor(args))
130132
self._finishFuture(retVal)
@@ -133,7 +135,9 @@ def post(self, *args, **kwargs): # pylint: disable=arguments-differ
133135

134136
@staticmethod
135137
def web_echo(data):
136-
"""This method used for testing the performance of a service"""
138+
"""
139+
This method used for testing the performance of a service
140+
"""
137141
return S_OK(data)
138142

139143
auth_whoami = ["authenticated"]

src/DIRAC/Core/Tornado/Server/TornadoService.py

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -34,15 +34,6 @@ class TornadoService(BaseRequestHandler): # pylint: disable=abstract-method
3434
3535
Each HTTP request is served by a new instance of this class.
3636
37-
For compatibility with the existing :py:class:`DIRAC.Core.DISET.TransferClient.TransferClient`,
38-
the handler can define a method ``export_streamToClient``. This is the method that will be called
39-
whenever ``TransferClient.receiveFile`` is called. It is the equivalent of the DISET
40-
``transfer_toClient``.
41-
Note that this is here only for compatibility, and we discourage using it for new purposes, as it is
42-
bound to disappear.
43-
44-
The handler only define the ``post`` verb. Please refer to :py:meth:`.post` for the details.
45-
4637
In order to create a handler for your service, it has to
4738
follow a certain skeleton::
4839
@@ -98,6 +89,11 @@ def export_streamToClient(self, myDataToSend, token):
9889
and we are running using executors, the methods you export cannot write
9990
back directly to the client. Please see inline comments for more details.
10091
92+
In order to pass information around and keep some states, we use instance attributes.
93+
These are initialized in the :py:meth:`.initialize` method.
94+
95+
The handler only define the ``post`` verb. Please refer to :py:meth:`.post` for the details.
96+
10197
"""
10298

10399
# Prefix of methods names

src/DIRAC/Core/Tornado/Server/private/BaseRequestHandler.py

Lines changed: 22 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -38,26 +38,17 @@
3838

3939

4040
class TornadoResponse(object):
41-
"""This class registers tornado methods with arguments in the same order they are called
42-
from TornadoResponse instance to call them later in the main thread.
41+
"""This class registers tornadoes with arguments in the order they are called
42+
from TornadoResponse to call them later.
4343
44-
This class can be useful if you are afraid to use Tornado methods in a non-main thread due to a warning from Tornado that "methods on RequestHandler and elsewhere in Tornado are not thread-safe"
45-
https://www.tornadoweb.org/en/stable/web.html#thread-safety-notes.
46-
47-
This is used in exceptional cases, in most cases it is not required,
48-
just use `return S_OK(data)` instead.
49-
50-
Usage example::
44+
Use::
5145
5246
def web_myEndpoint(self):
53-
# We need not only to return the result but also to set a header.
54-
resp = TornadoResponse('data')
55-
resp.set_header("Content-Type", "application/x-tar")
56-
# And for example redirect to another place
57-
return resp.redirect('https://server')
47+
resp = TornadoResponse("data")
48+
resp.set_status(400)
49+
return resp
5850
"""
5951

60-
# Let's see what methods RequestHandler has
6152
__attrs = inspect.getmembers(RequestHandler)
6253

6354
def __init__(self, payload=None, status_code=None):
@@ -70,7 +61,6 @@ def __init__(self, payload=None, status_code=None):
7061
self.status_code = status_code
7162
self.actions = []
7263
for mName, mObj in self.__attrs:
73-
# Let's make sure that this is the usual RequestHandler method
7464
if inspect.isroutine(mObj) and not mName.startswith("_") and not mName.startswith("get"):
7565
setattr(self, mName, partial(self.__setAction, mName))
7666

@@ -82,31 +72,23 @@ def __setAction(self, mName, *args, **kwargs):
8272
:return: TornadoResponse instance
8373
"""
8474
self.actions.append((mName, args, kwargs))
85-
# Let's return the instance of the class so that it can be returned immediately. For example:
86-
# resp = TornadoResponse('data')
87-
# return resp.redirect('https://server')
8875
return self
8976

9077
def _runActions(self, reqObj):
91-
"""Calling methods in the order of their registration.
92-
This method is called at the end of the request, when the main work is already done in the thread.
93-
Look the :py:meth:`_finishFuture` method.
78+
"""Calling methods in the order of their registration
9479
9580
:param reqObj: RequestHandler instance
9681
"""
97-
# Assign a status code if it has been transmitted.
9882
if self.status_code:
9983
reqObj.set_status(self.status_code)
10084
for mName, args, kwargs in self.actions:
10185
getattr(reqObj, mName)(*args, **kwargs)
102-
# Will we check if the finish method has already been called.
10386
if not reqObj._finished:
104-
# if not what are we waiting for?
10587
reqObj.finish(self.payload)
10688

10789

10890
class BaseRequestHandler(RequestHandler):
109-
"""Base class for all the Handlers that uses HTTP tornado framework on server side.
91+
"""Base class for all the Handlers.
11092
It directly inherits from :py:class:`tornado.web.RequestHandler`
11193
11294
Each HTTP request is served by a new instance of this class.
@@ -122,8 +104,8 @@ class BaseRequestHandler(RequestHandler):
122104
123105
class TornadoInstance(BaseRequestHandler):
124106
125-
# Prefix of methods names if need to use a special prefix. By default its "export_".
126-
METHOD_PREFIX = "web_"
107+
# Prefix of methods names
108+
METHOD_PREFIX = "export_"
127109
128110
@classmethod
129111
def _getServiceName(cls, request):
@@ -133,7 +115,7 @@ def _getServiceName(cls, request):
133115
134116
@classmethod
135117
def _getServiceInfo(cls, serviceName, request):
136-
''' Fill service information. By default return empty dictionary.
118+
''' Fill service information.
137119
'''
138120
return {'serviceName': serviceName,
139121
'serviceSectionPath': PathFinder.getServiceSection(serviceName),
@@ -174,8 +156,12 @@ def post(self, *args, **kwargs): # pylint: disable=arguments-differ
174156
# retVal is :py:class:`tornado.concurrent.Future`
175157
self._finishFuture(retVal)
176158
177-
In order to pass information around and keep some states, we use instance attributes.
178-
These are initialized in the :py:meth:`.initialize` method.
159+
For compatibility with the existing :py:class:`DIRAC.Core.DISET.TransferClient.TransferClient`,
160+
the handler can define a method ``export_streamToClient``. This is the method that will be called
161+
whenever ``TransferClient.receiveFile`` is called. It is the equivalent of the DISET
162+
``transfer_toClient``.
163+
Note that this is here only for compatibility, and we discourage using it for new purposes, as it is
164+
bound to disappear.
179165
"""
180166

181167
# Because we initialize at first request, we use a flag to know if it's already done
@@ -190,8 +176,7 @@ def post(self, *args, **kwargs): # pylint: disable=arguments-differ
190176
# System name with which this component is associated
191177
SYSTEM = None
192178

193-
# Authorization requirements, properties that applied by default to all handler methods, if defined.
194-
# Nonte: `auth_methodName` will have a higher priority.
179+
# Auth requirements
195180
AUTH_PROPS = None
196181

197182
# Type of component
@@ -204,12 +189,7 @@ def post(self, *args, **kwargs): # pylint: disable=arguments-differ
204189
_idps = IdProviderFactory()
205190
_idp = {}
206191

207-
# Which grant type to use. This definition refers to the type of authorization, ie which algorithm will be used to verify the incoming request and obtain user credentials.
208-
# These algorithms will be applied in the same order as in the list.
209-
210-
# SSL - add to list to enable certificate reading
211-
# JWT - add to list to enable reading Bearer token
212-
# VISITOR - add to list to enable authorization as visitor, that is, without verification
192+
# Which grant type to use
213193
USE_AUTHZ_GRANTS = ["SSL", "JWT"]
214194

215195
@classmethod
@@ -362,8 +342,9 @@ def initializeHandler(cls, serviceInfo):
362342
And it must be a class method. This method is called only one time,
363343
at the first request
364344
365-
:param dict serviceInfo: infos about services, it contains information about service, e.g.:
366-
'serviceName', 'serviceSectionPath', 'csPaths' and 'URL'
345+
:param dict ServiceInfoDict: infos about services, it contains
346+
'serviceName', 'serviceSectionPath',
347+
'csPaths' and 'URL'
367348
"""
368349
pass
369350

@@ -441,22 +422,17 @@ def _getMethodArgs(self, args):
441422
def _getMethodAuthProps(self):
442423
"""Resolves the hard coded authorization requirements for method.
443424
444-
List of required :mod:`~DIRAC.Core.Security.Properties`.
445-
446425
:return: list
447426
"""
448-
# Convert default authorization requirements to list
449427
if self.AUTH_PROPS and not isinstance(self.AUTH_PROPS, (list, tuple)):
450428
self.AUTH_PROPS = [p.strip() for p in self.AUTH_PROPS.split(",") if p.strip()]
451-
# Use auth_< method name > as primary value of the authorization requirements
452429
return getattr(self, "auth_" + self.mehtodName, self.AUTH_PROPS)
453430

454431
def _getMethod(self):
455432
"""Get method function to call.
456433
457434
:return: function
458435
"""
459-
# Get method object using prefix and method name from request
460436
methodObj = getattr(self, "%s%s" % (self.METHOD_PREFIX, self.mehtodName), None)
461437
if not callable(methodObj):
462438
sLog.error("Invalid method", self.mehtodName)

0 commit comments

Comments
 (0)