tina4-python 0.2.122__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. tina4_python/Auth.py +222 -0
  2. tina4_python/Constant.py +43 -0
  3. tina4_python/Database.py +591 -0
  4. tina4_python/DatabaseResult.py +107 -0
  5. tina4_python/DatabaseTypes.py +15 -0
  6. tina4_python/Debug.py +126 -0
  7. tina4_python/Env.py +37 -0
  8. tina4_python/Localization.py +42 -0
  9. tina4_python/Messages.py +30 -0
  10. tina4_python/MiddleWare.py +90 -0
  11. tina4_python/Migration.py +107 -0
  12. tina4_python/ORM.py +639 -0
  13. tina4_python/Queue.py +615 -0
  14. tina4_python/Request.py +19 -0
  15. tina4_python/Response.py +121 -0
  16. tina4_python/Router.py +423 -0
  17. tina4_python/Session.py +342 -0
  18. tina4_python/ShellColors.py +20 -0
  19. tina4_python/Swagger.py +228 -0
  20. tina4_python/Template.py +107 -0
  21. tina4_python/Webserver.py +429 -0
  22. tina4_python/Websocket.py +49 -0
  23. tina4_python/__init__.py +392 -0
  24. tina4_python/messages.pot +83 -0
  25. tina4_python/public/css/readme.md +0 -0
  26. tina4_python/public/favicon.ico +0 -0
  27. tina4_python/public/images/403.png +0 -0
  28. tina4_python/public/images/404.png +0 -0
  29. tina4_python/public/images/500.png +0 -0
  30. tina4_python/public/images/logo.png +0 -0
  31. tina4_python/public/images/readme.md +0 -0
  32. tina4_python/public/js/readme.md +0 -0
  33. tina4_python/public/js/reconnecting-websocket.js +365 -0
  34. tina4_python/public/js/tina4helper.js +397 -0
  35. tina4_python/public/swagger/index.html +90 -0
  36. tina4_python/public/swagger/oauth2-redirect.html +63 -0
  37. tina4_python/templates/errors/403.twig +10 -0
  38. tina4_python/templates/errors/404.twig +10 -0
  39. tina4_python/templates/errors/500.twig +11 -0
  40. tina4_python/templates/readme.md +1 -0
  41. tina4_python/translations/en/LC_MESSAGES/messages.mo +0 -0
  42. tina4_python/translations/en/LC_MESSAGES/messages.po +80 -0
  43. tina4_python/translations/fr/LC_MESSAGES/messages.mo +0 -0
  44. tina4_python/translations/fr/LC_MESSAGES/messages.po +84 -0
  45. tina4_python-0.2.122.dist-info/METADATA +465 -0
  46. tina4_python-0.2.122.dist-info/RECORD +47 -0
  47. tina4_python-0.2.122.dist-info/WHEEL +4 -0
@@ -0,0 +1,15 @@
1
+ #
2
+ # Tina4 - This is not a 4ramework.
3
+ # Copy-right 2007 - current Tina4
4
+ # License: MIT https://opensource.org/licenses/MIT
5
+ #
6
+ # flake8: noqa: E501
7
+ SQLITE = "sqlite3"
8
+ FIREBIRD = "firebird.driver"
9
+ FIREBIRD_INSTALL = "pip install firebird-driver or poetry add firebird-driver"
10
+ MYSQL = "mysql.connector"
11
+ MYSQL_INSTALL = "pip install mysql-connector-python or poetry add mysql-connector-python"
12
+ POSTGRES = "psycopg2"
13
+ POSTGRES_INSTALL = "pip install psycopg2-binary or poetry add psycopg2-binary"
14
+ MSSQL = "pymssql"
15
+ MSSQL_INSTALL = "pip install pymssql or poetry add pymssql"
tina4_python/Debug.py ADDED
@@ -0,0 +1,126 @@
1
+ #
2
+ # Tina4 - This is not a 4ramework.
3
+ # Copy-right 2007 - current Tina4
4
+ # License: MIT https://opensource.org/licenses/MIT
5
+ #
6
+ # flake8: noqa: E501
7
+ import os
8
+ import sys
9
+ import logging
10
+ import logging.config
11
+ from logging.handlers import RotatingFileHandler
12
+ import tina4_python.Constant as Constant
13
+ from tina4_python.ShellColors import ShellColors
14
+ from datetime import datetime
15
+
16
+
17
+ LOGGING_CONFIG = {
18
+ 'version': 1,
19
+ 'disable_existing_loggers': False,
20
+ 'formatters': {
21
+ 'default': {
22
+ 'format': '%(levelname)s: %(asctime)s: %(message)s',
23
+ },
24
+ },
25
+ 'handlers': {
26
+ 'stdout': {
27
+ 'level': 'DEBUG',
28
+ 'class': 'logging.StreamHandler',
29
+ 'formatter': 'default',
30
+ },
31
+ },
32
+ 'loggers': {
33
+ 'TINA4': {
34
+ 'handlers': ['stdout'],
35
+ 'level': 'DEBUG',
36
+ 'propagate': True,
37
+ },
38
+ },
39
+ }
40
+
41
+ class Debug:
42
+
43
+ @staticmethod
44
+ def info(*args, **kwargs):
45
+ args += (Constant.TINA4_LOG_INFO,)
46
+ Debug(*args, **kwargs)
47
+
48
+ @staticmethod
49
+ def error(*args, **kwargs):
50
+ args += (Constant.TINA4_LOG_ERROR,)
51
+ Debug(*args, **kwargs)
52
+
53
+ @staticmethod
54
+ def debug(*args, **kwargs):
55
+ args += (Constant.TINA4_LOG_DEBUG,)
56
+ Debug(*args, **kwargs)
57
+
58
+ @staticmethod
59
+ def warning(*args, **kwargs):
60
+ args += (Constant.TINA4_LOG_WARNING,)
61
+ Debug(*args, **kwargs)
62
+
63
+ def __init__(self, *args, **kwargs):
64
+ now = datetime.now()
65
+ debug_level = os.getenv("TINA4_DEBUG_LEVEL", Constant.TINA4_LOG_INFO)
66
+
67
+ logging.config.dictConfig(LOGGING_CONFIG)
68
+ if debug_level == Constant.TINA4_LOG_ALL or debug_level == Constant.TINA4_LOG_DEBUG:
69
+ logging.basicConfig(stream=sys.stdout, level=logging.DEBUG)
70
+ elif debug_level == Constant.TINA4_LOG_INFO:
71
+ logging.basicConfig(stream=sys.stdout, level=logging.INFO)
72
+ elif debug_level == Constant.TINA4_LOG_ERROR:
73
+ logging.basicConfig(stream=sys.stdout, level=logging.ERROR)
74
+ elif debug_level == Constant.TINA4_LOG_WARNING:
75
+ logging.basicConfig(stream=sys.stdout, level=logging.WARNING)
76
+
77
+ params = [now.strftime("%Y-%m-%d %H:%M:%S") + ":"]
78
+ for value in args:
79
+ if value in [Constant.TINA4_LOG_ALL, Constant.TINA4_LOG_DEBUG, Constant.TINA4_LOG_INFO,
80
+ Constant.TINA4_LOG_ERROR, Constant.TINA4_LOG_WARNING]:
81
+ debug_level = value
82
+ else:
83
+ params.append(value)
84
+
85
+ file_name = "debug.log"
86
+ if "file_name" in kwargs:
87
+ file_name = kwargs["file_name"]
88
+
89
+ formatter = logging.Formatter("%(levelname)s: %(asctime)s: %(message)s")
90
+ logger = logging.getLogger('TINA4')
91
+ logger.setLevel(logging.DEBUG)
92
+
93
+ handler = RotatingFileHandler("."+os.sep+"logs"+os.sep+file_name, maxBytes=1024*1024, backupCount=5, encoding="utf-8")
94
+ handler.setFormatter(formatter)
95
+ logger.addHandler(handler)
96
+
97
+ if (os.getenv("TINA4_DEBUG_LEVEL", [Constant.TINA4_LOG_ALL]) == "[TINA4_LOG_ALL]"
98
+ or debug_level in os.getenv("TINA4_DEBUG_LEVEL", [Constant.TINA4_LOG_ALL])):
99
+
100
+ log_level = 0
101
+ # choose the color
102
+ color = ShellColors.bright_blue
103
+
104
+ if debug_level == Constant.TINA4_LOG_INFO:
105
+ color = ShellColors.cyan
106
+ log_level = 20
107
+
108
+ elif debug_level == Constant.TINA4_LOG_DEBUG:
109
+ color = ShellColors.bright_magenta
110
+ log_level = 10
111
+
112
+ elif debug_level == Constant.TINA4_LOG_ERROR:
113
+ color = ShellColors.bright_red
114
+ log_level = 40
115
+
116
+ elif debug_level == Constant.TINA4_LOG_WARNING:
117
+ color = ShellColors.bright_yellow
118
+ log_level = 30
119
+
120
+ end = ShellColors.end
121
+
122
+ logger.log(log_level, f"{color} ".join(str(param) for param in params[1:]).strip()+f"{end} ")
123
+
124
+ handler.flush()
125
+ logger.removeHandler(handler)
126
+ handler.close()
tina4_python/Env.py ADDED
@@ -0,0 +1,37 @@
1
+ #
2
+ # Tina4 - This is not a 4ramework.
3
+ # Copy-right 2007 - current Tina4
4
+ # License: MIT https://opensource.org/licenses/MIT
5
+ #
6
+ import os
7
+ import hashlib
8
+ from datetime import datetime
9
+ from dotenv import load_dotenv
10
+
11
+
12
+ # check .env for information
13
+ def load_env(path: str = '.env'):
14
+ if not os.path.isfile(path):
15
+ current_time = datetime.now()
16
+ result = hashlib.md5(current_time.strftime("%A,%d %B %Y").encode())
17
+ with open(path, 'w') as f:
18
+ f.write("# Project Settings\n")
19
+ f.write("PROJECT_NAME=\"My Project\"\n")
20
+ f.write("VERSION=1.0.0\n")
21
+ f.write("TINA4_LANGUAGE=en\n")
22
+ f.write("API_KEY="+result.hexdigest()+"\n")
23
+ f.write("TINA4_DEBUG_LEVEL=[TINA4_LOG_ALL]\n")
24
+ # Load the .env
25
+ load_dotenv(path)
26
+ # check for defaults we need
27
+ if "TINA4_LANGUAGE" not in os.environ:
28
+ with open(path, 'a') as f:
29
+ f.write("TINA4_LANGUAGE=en\n")
30
+ if "TINA4_DEBUG_LEVEL" not in os.environ:
31
+ with open(path, 'a') as f:
32
+ f.write("TINA4_DEBUG_LEVEL=[\"ALL\"]\n")
33
+ if "API_KEY" not in os.environ:
34
+ current_time = datetime.now()
35
+ result = hashlib.md5(current_time.strftime("%A,%d %B %Y").encode())
36
+ with open(path, 'a') as f:
37
+ f.write("API_KEY="+result.hexdigest()+"\n")
@@ -0,0 +1,42 @@
1
+ #
2
+ # Tina4 - This is not a 4ramework.
3
+ # Copy-right 2007 - current Tina4
4
+ # License: MIT https://opensource.org/licenses/MIT
5
+ #
6
+ # flake8: noqa: E501
7
+ import gettext
8
+ import os
9
+ import sys
10
+ from tina4_python.Debug import Debug
11
+ from tina4_python import Constant
12
+
13
+
14
+ # load environment variables from .env file
15
+ # check .env for information
16
+
17
+ def localize():
18
+ translation_path = os.path.join(os.path.dirname(__file__), 'translations')
19
+ available_languages = ['en', 'fr', 'af']
20
+
21
+ # get user language from environment variable
22
+ # default to English
23
+ if "TINA4_LANGUAGE" in os.environ:
24
+ user_language = os.environ.get('TINA4_LANGUAGE', 'en')
25
+ else:
26
+ user_language = "en"
27
+
28
+ # check if an argument is a language
29
+ if len(sys.argv) > 1:
30
+ try:
31
+ int(sys.argv[1])
32
+ except ValueError:
33
+ if sys.argv[1] in available_languages:
34
+ user_language = sys.argv[1]
35
+
36
+ if len(sys.argv) > 2 and sys.argv[2] in available_languages:
37
+ user_language = sys.argv[2]
38
+
39
+ Debug("Language: " + user_language, Constant.TINA4_LOG_INFO)
40
+ # Initialize the translation system
41
+ translation = gettext.translation('messages', translation_path, languages=[user_language])
42
+ translation.install()
@@ -0,0 +1,30 @@
1
+ #
2
+ # Tina4 - This is not a 4ramework.
3
+ # Copy-right 2007 - current Tina4
4
+ # License: MIT https://opensource.org/licenses/MIT
5
+ #
6
+ # flake8: noqa: E501
7
+ import gettext
8
+
9
+ _ = gettext.gettext
10
+
11
+ MSG_DEBUG = _('Debug: {message}')
12
+ MSG_WARNING = _('Warning: {message}')
13
+ MSG_ERROR = _('Error: {message}')
14
+ MSG_INFO = _('Info: {message}')
15
+
16
+ # Router messages
17
+ MSG_ROUTER_MATCHING = _('Matching: {matching}')
18
+ MSG_ROUTER_VARIABLES = _('Variables: {variables}')
19
+ MSG_ROUTER_ROOT_PATH = _('Root Path {root_path} {url}')
20
+ MSG_ROUTER_STATIC_FILE = _('Attempting to serve static file: {static_file}')
21
+ MSG_ROUTER_CSS_FILE = _('Attempting to serve CSS file: {css_file}')
22
+ MSG_ROUTER_IMAGE_FILE = _('Attempting to serve image file: {image_file}')
23
+
24
+ # Server messages
25
+ MSG_ASSUMING_ROOT_PATH = _('Assuming root path: {root_path}, library path: {library_path}')
26
+ MSG_LOAD_ALL_THINGS = _('Load all things')
27
+ MSG_SERVER_STARTED = _('Server started http://{host_name}:{port}')
28
+ MSG_SERVER_STOPPED = _('Server stopped.')
29
+ MSG_STARTING_WEBSERVER = _('Starting webserver on {port}')
30
+ MSG_ENTRY_POINT_NAME = _('Entry point name ... {name}')
@@ -0,0 +1,90 @@
1
+ #
2
+ # Tina4 - This is not a 4ramework.
3
+ # Copy-right 2007 - current Tina4
4
+ # License: MIT https://opensource.org/licenses/MIT
5
+ #
6
+ # flake8: noqa: E501
7
+ import asyncio
8
+
9
+ class MiddleWare:
10
+ def __init__(self, middleware_class):
11
+ """
12
+
13
+ :param middleware_class:
14
+ """
15
+ self.before_methods = []
16
+ self.after_methods = []
17
+ self.any_methods = []
18
+ self.middleware_class = middleware_class
19
+
20
+ self.methods_list = [method for method in vars(middleware_class) if callable(
21
+ getattr(middleware_class, method)) and not method.startswith("__")]
22
+
23
+ for method in self.methods_list:
24
+ if method.startswith("before"):
25
+ self.before_methods.append(method)
26
+ elif method.startswith("after"):
27
+ self.after_methods.append(method)
28
+ else:
29
+ self.any_methods.append(method)
30
+
31
+ async def call_before_methods(self, request, response):
32
+ """
33
+ Call before methods
34
+ :param request:
35
+ :param response:
36
+ :return:
37
+ """
38
+ for method in self.before_methods:
39
+ method = getattr(self.middleware_class, method)
40
+ result = method(request, response)
41
+ if asyncio.iscoroutine(result):
42
+ request, response = await result
43
+ else:
44
+ request, response = result
45
+
46
+ return request, response
47
+
48
+ async def call_after_methods(self, request, response):
49
+ """
50
+ Call after methods
51
+ :param request:
52
+ :param response:
53
+ :return:
54
+ """
55
+ for method in self.after_methods:
56
+ method = getattr(self.middleware_class, method)
57
+ result = method(request, response)
58
+ if asyncio.iscoroutine(result):
59
+ request, response = await result
60
+ else:
61
+ request, response = result
62
+ return request, response
63
+
64
+ async def call_any_methods(self, request, response):
65
+ """
66
+ Call any methods
67
+ :param request:
68
+ :param response:
69
+ :return:
70
+ """
71
+ for method in self.any_methods:
72
+ method = getattr(self.middleware_class, method)
73
+ result = method(request, response)
74
+ if asyncio.iscoroutine(result):
75
+ request, response = await result
76
+ else:
77
+ request, response = result
78
+ return request, response
79
+
80
+ def call_direct_method(self, request, response, method_name):
81
+ """
82
+ Call direct methods
83
+ :param request:
84
+ :param response:
85
+ :param method_name:
86
+ :return:
87
+ """
88
+ method = getattr(self.middleware_class, method_name)
89
+ request, response = method(request, response)
90
+ return request, response
@@ -0,0 +1,107 @@
1
+ #
2
+ # Tina4 - This is not a 4ramework.
3
+ # Copy-right 2007 - current Tina4
4
+ # License: MIT https://opensource.org/licenses/MIT
5
+ #
6
+ # flake8: noqa: E501
7
+ import os
8
+ import sys
9
+
10
+ from tina4_python import ShellColors
11
+ from tina4_python import Constant
12
+ from tina4_python.Debug import Debug
13
+ from tina4_python.Database import MSSQL, POSTGRES, FIREBIRD, MYSQL
14
+ import tina4_python
15
+
16
+
17
+ def migrate(dba, delimiter=";", migration_folder="migrations"):
18
+ """
19
+ Migrates the database from the migrate folder
20
+ :param delimiter: SQL delimiter
21
+ :param dba: Database connection
22
+ :param migration_folder: Alternative folder for migrations
23
+ :return:
24
+ """
25
+ if dba.database_engine == MSSQL:
26
+ if not dba.table_exists("tina4_migration"):
27
+ dba.execute("create table tina4_migration(id integer identity(1,1) not null, description varchar(200) default '', content nvarchar(max), error_message nvarchar(max), passed integer default 0, primary key(id))")
28
+ dba.execute("SET IDENTITY_INSERT tina4_migration ON")
29
+ elif dba.database_engine == POSTGRES:
30
+ dba.execute(
31
+ "create table if not exists tina4_migration(id serial primary key, description varchar(200) default '', content text, error_message text, passed integer default 0)")
32
+ elif dba.database_engine == MYSQL:
33
+ dba.execute(
34
+ "create table if not exists tina4_migration(id integer not null auto_increment, description varchar(200) default '', content text, error_message text, passed integer default 0, primary key(id))")
35
+ elif dba.database_engine == FIREBIRD:
36
+ if not dba.table_exists("tina4_migration"):
37
+ dba.execute(
38
+ "create table tina4_migration(id integer not null, description varchar(200) default '', content blob sub_type text, error_message blob sub_type text, passed integer default 0, primary key(id))")
39
+ else:
40
+ dba.execute(
41
+ "create table if not exists tina4_migration(id integer not null, description varchar(200) default '', content blob, error_message blob, passed integer default 0, primary key(id))")
42
+
43
+ Debug(ShellColors.bright_yellow, "Migration: Found ", tina4_python.root_path + os.sep + migration_folder, ShellColors.end, Constant.TINA4_LOG_INFO)
44
+ dir_list = os.listdir(tina4_python.root_path + os.sep + migration_folder)
45
+ dir_list.sort()
46
+
47
+ for file in dir_list:
48
+ if '.sql' in file:
49
+ Debug(ShellColors.bright_yellow, "Migration: Checking file", file, ShellColors.end, Constant.TINA4_LOG_INFO)
50
+ sql_file = open(tina4_python.root_path + os.sep + migration_folder + os.sep + file)
51
+ file_contents = sql_file.read()
52
+ sql_file.close()
53
+ try:
54
+ dba.execute("delete from tina4_migration where description = ? and passed = ?", [file, 0])
55
+ dba.commit()
56
+ # check if migration exists in the database and has passed - no need to run the scripts below
57
+
58
+ sql_check = "select * from tina4_migration where description = ? and passed = ?"
59
+ record = dba.fetch(sql_check, [file, 1])
60
+
61
+ if record.count == 0:
62
+ Debug(ShellColors.bright_yellow, "Migration: Running migration for", file, ShellColors.end, Constant.TINA4_LOG_INFO)
63
+ # get each migration
64
+ script_content = file_contents.split(";")
65
+
66
+ # all scripts need to pass
67
+ error = False
68
+ error_message = ""
69
+ for script in script_content:
70
+ if script.strip() != "":
71
+ result = dba.execute(script)
72
+ if result.error is not None:
73
+ error = True
74
+ error_message = result.error
75
+ break
76
+
77
+ if not error:
78
+ # passed print(color + f"{debug_level:5}:"+ShellColors.end, "", end="")
79
+ Debug(ShellColors.bright_yellow,"Migration:", ShellColors.end, ShellColors.bright_green+"PASSED running migration for", file, ShellColors.end, Constant.TINA4_LOG_INFO)
80
+ dba.commit()
81
+ next_id = dba.get_next_id("tina4_migration")
82
+ dba.execute("insert into tina4_migration (id, description, content, passed) values (?, ?, ?, 1) ",
83
+ [next_id, file, file_contents])
84
+ dba.commit()
85
+ else:
86
+ # did not pass
87
+ Debug(ShellColors.bright_yellow, "Migration:", ShellColors.end, ShellColors.bright_red+"FAILED running migration for", file, error_message, ShellColors.end, Constant.TINA4_LOG_ERROR)
88
+ dba.rollback()
89
+ next_id = dba.get_next_id("tina4_migration")
90
+ dba.execute(
91
+ "insert into tina4_migration (id, description, content, passed, error_message) values (?, ?, ?, 0, ?) ",
92
+ [next_id, file, file_contents, str(error_message)])
93
+ dba.commit()
94
+ sys.exit(1)
95
+ except Exception as e:
96
+ next_id = dba.get_next_id("tina4_migration")
97
+ dba.execute(
98
+ "insert into tina4_migration (id, description, content, passed, error_message) values (?, ?, ?, 0, ?) ",
99
+ [next_id, file, file_contents, str(e)])
100
+ dba.commit()
101
+
102
+ Debug("Migration: Failed to run", file, e, Constant.TINA4_LOG_ERROR)
103
+ sys.exit(1)
104
+
105
+ if dba.database_engine == MSSQL:
106
+ dba.execute("SET IDENTITY_INSERT tina4_migration OFF")
107
+