Wsgi_15Watt.Kernel
1import traceback 2from importlib import import_module 3from sqlobject import * 4from .Request import Request 5from .Response import Response 6from .Route import HttpMethods 7from .Exceptions import Base 8 9 10class Kernel(object): 11 """ 12 Handles the complete request to response cycle. 13 """ 14 def __init__(self, nameConfig: str = 'config', nameRoutes: str = 'routes'): 15 """ 16 Sets the names of the configuration and routes files. 17 18 These files are expected to be in the project root. 19 20 :param nameConfig: str 21 22 :param nameRoutes: str 23 """ 24 25 self.__nameConfig = nameConfig 26 self.__nameRoutes = nameRoutes 27 28 self.__routes = {} 29 self.__config = {} 30 self.__env = {} 31 self.__loadConfig() 32 self.__connectToDatabase() 33 self.__loadRoutes() 34 35 36 def run(self, env: dict, startResponse): 37 """ 38 Handles to whole request. 39 40 Will be called by your application.py 41 """ 42 # Only needed for the __str__ method and debug purposes. DO NOT USE! 43 self.__env = env 44 45 # Iterate over all routes 46 for idx in self.__routes: 47 if not self.__routes[idx].match(path=env.get('PATH_INFO'), httpMethod=HttpMethods[env.get('REQUEST_METHOD')]): 48 continue 49 50 # Found, so I call the controller method 51 request = Request( 52 env=env, 53 paramsFromRoute=self.__routes[idx].getParamsFromPath(path=env.get('PATH_INFO')) 54 ) 55 56 response = Response( 57 startResponse=startResponse, 58 request=request 59 ) 60 61 response.addHeader('X-Framework', 'Wsgi by Thomas Siemion') 62 self.__addAccessControlHeader(request=request, response=response) 63 64 # Call the controller method 65 try: 66 self.__routes[idx].methodToCall( 67 request=request, 68 response=response 69 ) 70 71 except Exception as e: 72 if 'debug' in self.__config and self.__config['debug'] is True: 73 tb = traceback.format_exc() 74 else: 75 tb = '' 76 77 if issubclass(type(e), Base): 78 response.returnCode = e.returnCode 79 response.stringContent = e.returnMsg 80 else: 81 response.returnCode = 500 82 response.stringContent = f'Internal server _error.\n{tb}' 83 84 response.contentType = 'text/plain' 85 response.charset = 'utf-8' 86 87 return response.getContent() 88 89 # No matching route found 90 # todo create a Error-Controller 91 response = Response( 92 startResponse=startResponse, 93 request=Request(env=env, paramsFromRoute={}) 94 ) 95 96 response.returnCode = 404 97 response.stringContent = f"No controller method found for route: {env.get('REQUEST_METHOD')}_{env.get('PATH_INFO')}" 98 response.contentType = 'text/plain' 99 response.charset = 'utf-8' 100 101 return response.getContent() 102 103 104 def __loadConfig(self): 105 """ 106 Reads the variables from project root config.py 107 :return: 108 """ 109 config = import_module(name=self.__nameConfig) 110 for k in dir(config): 111 if k.startswith('__'): 112 continue 113 114 self.__config[k] = getattr(config, k) 115 116 return 117 118 119 def __connectToDatabase(self): 120 """ 121 If the key uriDb is present in the project root config.py, a SqlObject 122 database connection will be established. 123 :return: 124 """ 125 if 'uriDb' not in self.__config: 126 self.__config['dbConnection'] = None 127 return 128 129 self.__config['dbConnection'] = connectionForURI(uri=self.__config['uriDb']) 130 sqlhub.processConnection = self.__config['dbConnection'] 131 132 133 def __loadRoutes(self): 134 """ 135 Loads and creates all routes from project root routes.py 136 and injects the configuration to them. 137 :return: 138 """ 139 module = import_module(name=self.__nameRoutes) 140 for route in getattr(module, self.__nameRoutes): 141 route.setConfig(config=self.__config) 142 k = f'{route.httpMethod.name}_{route.pathRegEx}' 143 self.__routes[k] = route 144 145 146 def __addAccessControlHeader(self, request: Request, response: Response): 147 """ 148 Adds the Access-Control-Allow-Origin header to the response, 149 if project root config.py has a key accessControlAllowOrigin, 150 holding an list of strings. 151 152 :param request: 153 :param response: 154 :return: 155 """ 156 if 'accessControlAllowOrigin' not in self.__config: 157 return 158 159 accessControlAllowOrigin = [] 160 accessControlAllowOrigin = accessControlAllowOrigin + self.__config['accessControlAllowOrigin'] 161 162 if 0 == len(accessControlAllowOrigin) or False == request.hasHeader('Origin'): 163 return 164 165 for url in accessControlAllowOrigin: 166 if request.getHeader('Origin') == url: 167 response.addHeader('Access-Control-Allow-Origin', url) 168 169 170 def __str__(self): 171 """ 172 Just a dump string representation of the kernel 173 for debugging purposes only. 174 """ 175 ret = 'Config:\n' 176 for k in self.__config: 177 ret += '\t{key}={val}\n'.format(key=k, val=self.__config[k]) 178 179 ret += '\nRoutes:\n' 180 181 for k in self.__routes: 182 ret += '\t' + str(self.__routes[k]) + '\n' 183 184 ret += '\nENV:\n' 185 186 for k in self.__env: 187 ret += '\t{key}={val}\n'.format(key=k, val=self.__env[k]) 188 189 return ret
class
Kernel:
11class Kernel(object): 12 """ 13 Handles the complete request to response cycle. 14 """ 15 def __init__(self, nameConfig: str = 'config', nameRoutes: str = 'routes'): 16 """ 17 Sets the names of the configuration and routes files. 18 19 These files are expected to be in the project root. 20 21 :param nameConfig: str 22 23 :param nameRoutes: str 24 """ 25 26 self.__nameConfig = nameConfig 27 self.__nameRoutes = nameRoutes 28 29 self.__routes = {} 30 self.__config = {} 31 self.__env = {} 32 self.__loadConfig() 33 self.__connectToDatabase() 34 self.__loadRoutes() 35 36 37 def run(self, env: dict, startResponse): 38 """ 39 Handles to whole request. 40 41 Will be called by your application.py 42 """ 43 # Only needed for the __str__ method and debug purposes. DO NOT USE! 44 self.__env = env 45 46 # Iterate over all routes 47 for idx in self.__routes: 48 if not self.__routes[idx].match(path=env.get('PATH_INFO'), httpMethod=HttpMethods[env.get('REQUEST_METHOD')]): 49 continue 50 51 # Found, so I call the controller method 52 request = Request( 53 env=env, 54 paramsFromRoute=self.__routes[idx].getParamsFromPath(path=env.get('PATH_INFO')) 55 ) 56 57 response = Response( 58 startResponse=startResponse, 59 request=request 60 ) 61 62 response.addHeader('X-Framework', 'Wsgi by Thomas Siemion') 63 self.__addAccessControlHeader(request=request, response=response) 64 65 # Call the controller method 66 try: 67 self.__routes[idx].methodToCall( 68 request=request, 69 response=response 70 ) 71 72 except Exception as e: 73 if 'debug' in self.__config and self.__config['debug'] is True: 74 tb = traceback.format_exc() 75 else: 76 tb = '' 77 78 if issubclass(type(e), Base): 79 response.returnCode = e.returnCode 80 response.stringContent = e.returnMsg 81 else: 82 response.returnCode = 500 83 response.stringContent = f'Internal server _error.\n{tb}' 84 85 response.contentType = 'text/plain' 86 response.charset = 'utf-8' 87 88 return response.getContent() 89 90 # No matching route found 91 # todo create a Error-Controller 92 response = Response( 93 startResponse=startResponse, 94 request=Request(env=env, paramsFromRoute={}) 95 ) 96 97 response.returnCode = 404 98 response.stringContent = f"No controller method found for route: {env.get('REQUEST_METHOD')}_{env.get('PATH_INFO')}" 99 response.contentType = 'text/plain' 100 response.charset = 'utf-8' 101 102 return response.getContent() 103 104 105 def __loadConfig(self): 106 """ 107 Reads the variables from project root config.py 108 :return: 109 """ 110 config = import_module(name=self.__nameConfig) 111 for k in dir(config): 112 if k.startswith('__'): 113 continue 114 115 self.__config[k] = getattr(config, k) 116 117 return 118 119 120 def __connectToDatabase(self): 121 """ 122 If the key uriDb is present in the project root config.py, a SqlObject 123 database connection will be established. 124 :return: 125 """ 126 if 'uriDb' not in self.__config: 127 self.__config['dbConnection'] = None 128 return 129 130 self.__config['dbConnection'] = connectionForURI(uri=self.__config['uriDb']) 131 sqlhub.processConnection = self.__config['dbConnection'] 132 133 134 def __loadRoutes(self): 135 """ 136 Loads and creates all routes from project root routes.py 137 and injects the configuration to them. 138 :return: 139 """ 140 module = import_module(name=self.__nameRoutes) 141 for route in getattr(module, self.__nameRoutes): 142 route.setConfig(config=self.__config) 143 k = f'{route.httpMethod.name}_{route.pathRegEx}' 144 self.__routes[k] = route 145 146 147 def __addAccessControlHeader(self, request: Request, response: Response): 148 """ 149 Adds the Access-Control-Allow-Origin header to the response, 150 if project root config.py has a key accessControlAllowOrigin, 151 holding an list of strings. 152 153 :param request: 154 :param response: 155 :return: 156 """ 157 if 'accessControlAllowOrigin' not in self.__config: 158 return 159 160 accessControlAllowOrigin = [] 161 accessControlAllowOrigin = accessControlAllowOrigin + self.__config['accessControlAllowOrigin'] 162 163 if 0 == len(accessControlAllowOrigin) or False == request.hasHeader('Origin'): 164 return 165 166 for url in accessControlAllowOrigin: 167 if request.getHeader('Origin') == url: 168 response.addHeader('Access-Control-Allow-Origin', url) 169 170 171 def __str__(self): 172 """ 173 Just a dump string representation of the kernel 174 for debugging purposes only. 175 """ 176 ret = 'Config:\n' 177 for k in self.__config: 178 ret += '\t{key}={val}\n'.format(key=k, val=self.__config[k]) 179 180 ret += '\nRoutes:\n' 181 182 for k in self.__routes: 183 ret += '\t' + str(self.__routes[k]) + '\n' 184 185 ret += '\nENV:\n' 186 187 for k in self.__env: 188 ret += '\t{key}={val}\n'.format(key=k, val=self.__env[k]) 189 190 return ret
Handles the complete request to response cycle.
Kernel(nameConfig: str = 'config', nameRoutes: str = 'routes')
15 def __init__(self, nameConfig: str = 'config', nameRoutes: str = 'routes'): 16 """ 17 Sets the names of the configuration and routes files. 18 19 These files are expected to be in the project root. 20 21 :param nameConfig: str 22 23 :param nameRoutes: str 24 """ 25 26 self.__nameConfig = nameConfig 27 self.__nameRoutes = nameRoutes 28 29 self.__routes = {} 30 self.__config = {} 31 self.__env = {} 32 self.__loadConfig() 33 self.__connectToDatabase() 34 self.__loadRoutes()
Sets the names of the configuration and routes files.
These files are expected to be in the project root.
Parameters
nameConfig: str
nameRoutes: str
def
run(self, env: dict, startResponse):
37 def run(self, env: dict, startResponse): 38 """ 39 Handles to whole request. 40 41 Will be called by your application.py 42 """ 43 # Only needed for the __str__ method and debug purposes. DO NOT USE! 44 self.__env = env 45 46 # Iterate over all routes 47 for idx in self.__routes: 48 if not self.__routes[idx].match(path=env.get('PATH_INFO'), httpMethod=HttpMethods[env.get('REQUEST_METHOD')]): 49 continue 50 51 # Found, so I call the controller method 52 request = Request( 53 env=env, 54 paramsFromRoute=self.__routes[idx].getParamsFromPath(path=env.get('PATH_INFO')) 55 ) 56 57 response = Response( 58 startResponse=startResponse, 59 request=request 60 ) 61 62 response.addHeader('X-Framework', 'Wsgi by Thomas Siemion') 63 self.__addAccessControlHeader(request=request, response=response) 64 65 # Call the controller method 66 try: 67 self.__routes[idx].methodToCall( 68 request=request, 69 response=response 70 ) 71 72 except Exception as e: 73 if 'debug' in self.__config and self.__config['debug'] is True: 74 tb = traceback.format_exc() 75 else: 76 tb = '' 77 78 if issubclass(type(e), Base): 79 response.returnCode = e.returnCode 80 response.stringContent = e.returnMsg 81 else: 82 response.returnCode = 500 83 response.stringContent = f'Internal server _error.\n{tb}' 84 85 response.contentType = 'text/plain' 86 response.charset = 'utf-8' 87 88 return response.getContent() 89 90 # No matching route found 91 # todo create a Error-Controller 92 response = Response( 93 startResponse=startResponse, 94 request=Request(env=env, paramsFromRoute={}) 95 ) 96 97 response.returnCode = 404 98 response.stringContent = f"No controller method found for route: {env.get('REQUEST_METHOD')}_{env.get('PATH_INFO')}" 99 response.contentType = 'text/plain' 100 response.charset = 'utf-8' 101 102 return response.getContent()
Handles to whole request.
Will be called by your application.py