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