ApiLogicServer 15.0.0__py3-none-any.whl → 15.0.9__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.
- api_logic_server_cli/add_cust/add_cust.py +8 -2
- api_logic_server_cli/api_logic_server.py +2 -1
- api_logic_server_cli/api_logic_server_info.yaml +3 -3
- api_logic_server_cli/create_from_model/__pycache__/dbml.cpython-312.pyc +0 -0
- api_logic_server_cli/create_from_model/dbml.py +1 -0
- api_logic_server_cli/genai/genai_svcs.py +5 -2
- api_logic_server_cli/prototypes/base/api/api_discovery/mcp_discovery.py +63 -24
- api_logic_server_cli/prototypes/base/config/logging.yml +5 -0
- api_logic_server_cli/prototypes/base/config/server_setup.py +73 -0
- api_logic_server_cli/prototypes/base/integration/mcp/examples/mcp_discovery_response.json +150 -0
- api_logic_server_cli/prototypes/base/integration/mcp/examples/mcp_request.prompt +46 -0
- api_logic_server_cli/prototypes/base/integration/mcp/examples/mcp_tool_context_response.json +34 -0
- api_logic_server_cli/prototypes/base/integration/mcp/examples/mcp_tool_context_response_get.json +18 -0
- api_logic_server_cli/prototypes/base/integration/mcp/mcp_client_executor.py +129 -275
- api_logic_server_cli/prototypes/basic_demo/customizations/logic/logic_discovery/mcp_client_executor_request.py +11 -282
- api_logic_server_cli/prototypes/basic_demo/customizations/ui/admin/admin.yaml +3 -3
- api_logic_server_cli/prototypes/basic_demo/customizations/ui/admin/home.js +48 -0
- api_logic_server_cli/prototypes/manager/system/genai/mcp_learning/mcp.prompt +12 -0
- {apilogicserver-15.0.0.dist-info → apilogicserver-15.0.9.dist-info}/METADATA +1 -1
- {apilogicserver-15.0.0.dist-info → apilogicserver-15.0.9.dist-info}/RECORD +25 -31
- api_logic_server_cli/prototypes/base/integration/mcp/README_mcp.md +0 -15
- api_logic_server_cli/prototypes/base/integration/mcp/test_notes.txt +0 -37
- api_logic_server_cli/prototypes/basic_demo/customizations/api/api_discovery/mcp_discovery.py +0 -96
- api_logic_server_cli/prototypes/basic_demo/customizations/config/server_setup.py +0 -388
- api_logic_server_cli/prototypes/basic_demo/customizations/integration/mcp/.DS_Store +0 -0
- api_logic_server_cli/prototypes/basic_demo/customizations/integration/mcp/README_mcp.md +0 -15
- api_logic_server_cli/prototypes/basic_demo/customizations/integration/mcp/Zmcp_client_executor.py +0 -294
- api_logic_server_cli/prototypes/basic_demo/customizations/integration/mcp/mcp_schema.txt +0 -47
- api_logic_server_cli/prototypes/basic_demo/customizations/integration/mcp/mcp_server_discovery.json +0 -9
- api_logic_server_cli/prototypes/basic_demo/customizations/integration/mcp/mcp_tool_context.json +0 -25
- api_logic_server_cli/prototypes/basic_demo/customizations/integration/mcp/test_notes.txt +0 -37
- /api_logic_server_cli/prototypes/base/integration/mcp/{mcp_schema.txt → examples/mcp_schema.txt} +0 -0
- {apilogicserver-15.0.0.dist-info → apilogicserver-15.0.9.dist-info}/WHEEL +0 -0
- {apilogicserver-15.0.0.dist-info → apilogicserver-15.0.9.dist-info}/entry_points.txt +0 -0
- {apilogicserver-15.0.0.dist-info → apilogicserver-15.0.9.dist-info}/licenses/LICENSE +0 -0
- {apilogicserver-15.0.0.dist-info → apilogicserver-15.0.9.dist-info}/top_level.txt +0 -0
|
@@ -1,296 +1,150 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
|
|
3
|
+
###############################################################################
|
|
4
|
+
#
|
|
5
|
+
# This file initializes and starts the API Logic Server, e.g.:
|
|
6
|
+
# $ Use your IDE Run Configurations (for debug)
|
|
7
|
+
# $ sh run.sh
|
|
8
|
+
# $ python3 api_logic_server_run.py [--help]
|
|
9
|
+
# $ gunicorn --log-level=info -b 0.0.0.0:5656 -w2 --reload api_logic_server_run:flask_app
|
|
10
|
+
#
|
|
11
|
+
# Then, access the Admin App and API via the Browser, eg:
|
|
12
|
+
# http://localhost:5656
|
|
13
|
+
#
|
|
14
|
+
# You typically do not customize this file.
|
|
15
|
+
#
|
|
16
|
+
# (v 15.00.08, June 07, 2025 20:31:07)
|
|
17
|
+
#
|
|
18
|
+
# See Main Code (at end).
|
|
19
|
+
# Use log messages to understand API and Logic activation.
|
|
20
|
+
#
|
|
21
|
+
###############################################################################
|
|
22
|
+
|
|
23
|
+
api_logic_server__version = '15.00.08'
|
|
24
|
+
api_logic_server_created__on = 'June 07, 2025 20:31:07'
|
|
25
|
+
api_logic_server__host = 'localhost'
|
|
26
|
+
api_logic_server__port = '5656'
|
|
27
|
+
|
|
28
|
+
start_up_message = "normal start"
|
|
29
|
+
|
|
30
|
+
import os, logging, logging.config, sys, yaml # failure here means venv probably not set
|
|
31
|
+
from flask_sqlalchemy import SQLAlchemy
|
|
15
32
|
import json
|
|
16
|
-
import
|
|
17
|
-
from
|
|
18
|
-
import
|
|
19
|
-
import requests
|
|
20
|
-
from logic_bank.logic_bank import Rule
|
|
21
|
-
from logic_bank.util import ConstraintException
|
|
22
|
-
|
|
23
|
-
# Set your OpenAI API key
|
|
24
|
-
openai.api_key = os.getenv("APILOGICSERVER_CHATGPT_APIKEY")
|
|
25
|
-
|
|
26
|
-
server_url = os.getenv("APILOGICSERVER_URL", "http://localhost:5656/api")
|
|
27
|
-
|
|
28
|
-
# debug settings
|
|
29
|
-
test_type = 'orchestration' # 'simple_get' or 'orchestration'
|
|
30
|
-
create_tool_context_from_llm = True
|
|
31
|
-
''' set to False to bypass LLM call and save 2-3 secs in testing '''
|
|
32
|
-
use_test_schema = False
|
|
33
|
-
''' True means bypass discovery, use hard-coded schedma file '''
|
|
34
|
-
|
|
35
|
-
def discover_mcp_servers():
|
|
36
|
-
""" Discover the MCP servers by calling the /api/.well-known/mcp.json endpoint.
|
|
37
|
-
This function retrieves the list of available MCP servers and their capabilities.
|
|
38
|
-
"""
|
|
39
|
-
global server_url, use_test_schema
|
|
40
|
-
|
|
41
|
-
# create schema_text (for prompt), by reading integration/mcp/mcp_schema.txt
|
|
42
|
-
|
|
43
|
-
# find the servers - read the mcp_server_discovery.json file
|
|
44
|
-
discovery_file_path = os.path.join(os.path.dirname(__file__), "../../integration/mcp/mcp_server_discovery.json")
|
|
45
|
-
try:
|
|
46
|
-
with open(discovery_file_path, "r") as discovery_file:
|
|
47
|
-
discovery_data = json.load(discovery_file)
|
|
48
|
-
print(f"\n1. Discovered MCP servers from config file: {discovery_file_path}:" + json.dumps(discovery_data, indent=4))
|
|
49
|
-
except FileNotFoundError:
|
|
50
|
-
print(f"Discovery file not found at {discovery_file_path}.")
|
|
51
|
-
except json.JSONDecodeError as e:
|
|
52
|
-
print(f"Error decoding JSON from {discovery_file_path}: {e}")
|
|
53
|
-
|
|
54
|
-
for each_server in discovery_data["servers"]:
|
|
55
|
-
discovery_url = each_server["schema_url"]
|
|
56
|
-
|
|
57
|
-
# Call the discovery_url to get the MCP/API schema
|
|
58
|
-
try:
|
|
59
|
-
response = requests.get(discovery_url)
|
|
60
|
-
if response.status_code == 200:
|
|
61
|
-
api_schema = response.json()
|
|
62
|
-
print()
|
|
63
|
-
request_print = json.dumps(api_schema, indent=4)[0:400] + '\n... etc' # limit for readability
|
|
64
|
-
print(f"\n\nAPI Schema from discovery schema_url: {discovery_url}:\n" + request_print)
|
|
65
|
-
else:
|
|
66
|
-
print(f"Failed to retrieve API schema from {discovery_url}: {response.status_code}")
|
|
67
|
-
except requests.RequestException as e:
|
|
68
|
-
print(f"Error calling OpenAPI URL: {e}")
|
|
69
|
-
return json.dumps(api_schema)
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
def get_user_nl_query_and_training(query: str):
|
|
73
|
-
""" Get the natural language query from the user.
|
|
74
|
-
Add training for the LLM to generate a tool context block.
|
|
75
|
-
|
|
76
|
-
"""
|
|
77
|
-
|
|
78
|
-
global test_type
|
|
79
|
-
# read file docs/mcp_learning/mcp.prompt
|
|
80
|
-
prompt_file_path = os.path.join(os.path.dirname(__file__), "../../docs/mcp_learning/mcp.prompt")
|
|
81
|
-
if os.path.exists(prompt_file_path):
|
|
82
|
-
with open(prompt_file_path, "r") as prompt_file:
|
|
83
|
-
training_prompt = prompt_file.read()
|
|
84
|
-
# print(f"\nLoaded training prompt from {prompt_file_path}:\n{training_prompt}")
|
|
85
|
-
else:
|
|
86
|
-
training_prompt = ""
|
|
87
|
-
print(f"Prompt file not found at {prompt_file_path}.")
|
|
88
|
-
|
|
89
|
-
# if 1 argument, use it as the query
|
|
90
|
-
query_actual = query
|
|
91
|
-
if len(sys.argv) > 1:
|
|
92
|
-
query_actual = sys.argv[1]
|
|
93
|
-
if query_actual == '':
|
|
94
|
-
query_actual = "list customers with balance over 100."
|
|
95
|
-
return query_actual + ";\n\n" + training_prompt
|
|
96
|
-
|
|
33
|
+
from pathlib import Path
|
|
34
|
+
from config.config import Args # sets up logging
|
|
35
|
+
from config import server_setup
|
|
97
36
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
37
|
+
current_path = os.path.abspath(os.path.dirname(__file__))
|
|
38
|
+
sys.path.append(current_path)
|
|
39
|
+
project_dir = str(current_path)
|
|
40
|
+
project_name = os.path.basename(os.path.normpath(current_path))
|
|
101
41
|
|
|
102
|
-
|
|
103
|
-
|
|
42
|
+
if server_setup.is_docker():
|
|
43
|
+
sys.path.append(os.path.abspath('/home/api_logic_server'))
|
|
104
44
|
|
|
105
|
-
|
|
45
|
+
logic_alerts = True
|
|
46
|
+
""" Set False to silence startup message """
|
|
47
|
+
declare_logic_message = ""
|
|
48
|
+
declare_security_message = "ALERT: *** Security Not Enabled ***"
|
|
106
49
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
"content": "You are an API planner that converts natural language queries into MCP Tool Context blocks using JSON:API. Return only the tool context as JSON."
|
|
112
|
-
},
|
|
113
|
-
{
|
|
114
|
-
"role": "user",
|
|
115
|
-
"content": f"{content}"
|
|
116
|
-
}
|
|
117
|
-
]
|
|
50
|
+
os.chdir(project_dir) # so admin app can find images, code
|
|
51
|
+
import api.system.api_utils as api_utils
|
|
52
|
+
logic_logger_activate_debug = False
|
|
53
|
+
""" True prints all rules on startup """
|
|
118
54
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
55
|
+
from typing import TypedDict
|
|
56
|
+
import safrs # fails without venv - see https://apilogicserver.github.io/Docs/Project-Env/
|
|
57
|
+
from safrs import ValidationError, SAFRSBase, SAFRSAPI as _SAFRSAPI
|
|
58
|
+
from logic_bank.logic_bank import LogicBank
|
|
59
|
+
from logic_bank.exec_row_logic.logic_row import LogicRow
|
|
60
|
+
from logic_bank.rule_type.constraint import Constraint
|
|
61
|
+
from sqlalchemy.ext.declarative import declarative_base
|
|
62
|
+
from sqlalchemy.orm import Session
|
|
63
|
+
import socket
|
|
64
|
+
import warnings
|
|
65
|
+
from flask import Flask, redirect, send_from_directory, send_file
|
|
66
|
+
from flask_cors import CORS
|
|
67
|
+
import ui.admin.admin_loader as AdminLoader
|
|
68
|
+
from security.system.authentication import configure_auth
|
|
69
|
+
import oracledb
|
|
125
70
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
temperature=0.2
|
|
131
|
-
)
|
|
71
|
+
if os.getenv("EXPERIMENT") == '+':
|
|
72
|
+
app_logger = logging.getLogger("api_logic_server_app")
|
|
73
|
+
else:
|
|
74
|
+
app_logger = server_setup.logging_setup()
|
|
132
75
|
|
|
133
|
-
tool_context_str = response.choices[0].message.content
|
|
134
|
-
tool_context_str_no_cr = tool_context_str.replace("\n", '') # convert single quotes to double quotes
|
|
135
|
-
try:
|
|
136
|
-
tool_context = json.loads(tool_context_str_no_cr)
|
|
137
|
-
except json.JSONDecodeError:
|
|
138
|
-
print("Failed to decode JSON from response:", tool_context_str)
|
|
139
|
-
return None
|
|
140
76
|
|
|
141
|
-
print("\n2d. generated tool context from LLM:\n", json.dumps(tool_context, indent=4))
|
|
142
77
|
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
78
|
+
# ==================================
|
|
79
|
+
# MAIN CODE
|
|
80
|
+
# ==================================
|
|
146
81
|
|
|
82
|
+
flask_app = Flask("API Logic Server", template_folder='ui/templates') # templates to load ui/admin/admin.yaml
|
|
147
83
|
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
This executes the tool context blocks against a live JSON:API server.
|
|
151
|
-
It handles both GET and POST requests, and it can
|
|
152
|
-
orchestrate multiple requests based on the provided tool context.
|
|
84
|
+
CORS(flask_app, resources=[{r"/api/*": {"origins": "*"}},{r"/ontimizeweb/*": {"origins": "*"}}],
|
|
85
|
+
allow_headers=["Content-Type", "Authorization", "Access-Control-Allow-Credentials"],supports_credentials=True)
|
|
153
86
|
|
|
154
|
-
|
|
87
|
+
args = server_setup.get_args(flask_app) # creation defaults
|
|
155
88
|
|
|
156
|
-
|
|
89
|
+
import config.config as config
|
|
90
|
+
flask_app.config.from_object(config.Config)
|
|
91
|
+
app_logger.debug(f"\nConfig args: \n{args}") # config file (e.g., db uri's)
|
|
157
92
|
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
"""
|
|
161
|
-
global server_url
|
|
93
|
+
args.get_cli_args(dunder_name=__name__, args=args)
|
|
94
|
+
app_logger.debug(f"\nCLI args: \n{args}") # api_logic_server_run cl args
|
|
162
95
|
|
|
163
|
-
|
|
164
|
-
|
|
96
|
+
flask_app.config.from_prefixed_env(prefix="APILOGICPROJECT") # env overrides (e.g., docker)
|
|
97
|
+
app_logger.debug(f"\nENV args: \n{args}\n\n")
|
|
165
98
|
|
|
166
|
-
|
|
167
|
-
curl -qg 'http://localhost:5656/api/Order?filter=[{"name":"date_shipped","op":"eq","val":null},{"name":"CreatedOn","op":"lt","val":"2023-07-14"}]'
|
|
99
|
+
server_setup.validate_db_uri(flask_app)
|
|
168
100
|
|
|
169
|
-
|
|
170
|
-
curl -qg 'http://localhost:5656/api/Order?filter=[{"name":"date_shipped","op":"eq","val":null}]'
|
|
171
|
-
curl -qg 'http://localhost:5656/api/Customer?filter=[{"name":"credit_limit","op":"gt","val":"1000"}]'
|
|
172
|
-
|
|
173
|
-
query_params might be simple:
|
|
174
|
-
"query_params": [ {"name": "credit_limit", "op": "gt", "val": "1000"} ]
|
|
175
|
-
==> ?filter=[{"name":"credit_limit","op":"gt","val":"1000"}]
|
|
176
|
-
|
|
177
|
-
or a list:
|
|
178
|
-
"query_params": [
|
|
179
|
-
{
|
|
180
|
-
"name": "date_shipped",
|
|
181
|
-
"op": "eq",
|
|
182
|
-
"val": None
|
|
183
|
-
},
|
|
184
|
-
{
|
|
185
|
-
"name": "date_created",
|
|
186
|
-
"op": "lt",
|
|
187
|
-
"val": "2023-07-14"
|
|
188
|
-
}
|
|
189
|
-
],
|
|
190
|
-
|
|
191
|
-
"""
|
|
192
|
-
|
|
193
|
-
added_rows = 0
|
|
194
|
-
|
|
195
|
-
query_param_filter = ''
|
|
196
|
-
assert isinstance(query_params, list), "Query Params filter expected to be a list"
|
|
197
|
-
query_param_filter = 'filter=' + str(query_params)
|
|
198
|
-
# use urlencode to convert to JSON:API format...
|
|
199
|
-
# val urllib.parse.quote() or urllib.parse.urlencode()
|
|
200
|
-
# tool instructions... filtering, email etc "null"
|
|
201
|
-
query_param_filter = query_param_filter.replace("'", '"') # convert single quotes to double quotes
|
|
202
|
-
query_param_filter = query_param_filter.replace("None", 'null')
|
|
203
|
-
query_param_filter = query_param_filter.replace('"null"', 'null')
|
|
204
|
-
# query_param_filter = query_param_filter.replace("date_created", 'CreatedOn') # TODO - why this name?
|
|
205
|
-
return query_param_filter # end get_query_param_filter
|
|
206
|
-
|
|
207
|
-
def move_fields(src: dict, dest: dict, context_data: dict):
|
|
208
|
-
""" Move fields from src to dest, replacing any variables with their values from context_data."""
|
|
209
|
-
for variable_name, value in src.items():
|
|
210
|
-
move_value = value
|
|
211
|
-
if move_value.startswith("{") and move_value.endswith("}"):
|
|
212
|
-
# strip the braces, and get the name after the first dot, # eg: "{Order.customer_id}" ==> "customer_id"``
|
|
213
|
-
move_name = move_value[1:-1] # strip the braces
|
|
214
|
-
if '.' in move_value:
|
|
215
|
-
move_name = move_name.split('.', 1)[1]
|
|
216
|
-
move_value = context_data['attributes'][move_name]
|
|
217
|
-
dest[variable_name] = move_value
|
|
218
|
-
return dest
|
|
219
|
-
|
|
220
|
-
def print_get_response(query_param_filter, mcp_response):
|
|
221
|
-
""" Print the response from the GET request. """
|
|
222
|
-
print("\n3. MCP Server (als) GET filter(query_param_filter):\n", query_param_filter)
|
|
223
|
-
print(" GET Response:\n", mcp_response.text)
|
|
224
|
-
results : List[Dict] = mcp_response.json()['data']
|
|
225
|
-
# print results in a table format
|
|
226
|
-
if results:
|
|
227
|
-
# Get all unique keys from all result dicts
|
|
228
|
-
keys = set()
|
|
229
|
-
for row in results:
|
|
230
|
-
if isinstance(row, dict):
|
|
231
|
-
keys.update(row.keys())
|
|
232
|
-
keys = list(keys)
|
|
233
|
-
# Print header
|
|
234
|
-
print("\n| " + " | ".join(keys) + " |")
|
|
235
|
-
print("|" + "|".join(["---"] * len(keys)) + "|")
|
|
236
|
-
# Print rows
|
|
237
|
-
for row in results:
|
|
238
|
-
print("| " + " | ".join(str(row.get(k, "")) for k in keys) + " |")
|
|
239
|
-
else:
|
|
240
|
-
print("No results found.")
|
|
241
|
-
|
|
242
|
-
assert isinstance(tool_context, (dict, list)), "Tool context expected to be a dictionary"
|
|
243
|
-
context_data = {}
|
|
244
|
-
added_rows = 0
|
|
245
|
-
|
|
246
|
-
for each_block in tool_context["resources"]:
|
|
247
|
-
if process_tool_context := True:
|
|
248
|
-
if each_block["method"] == "GET":
|
|
249
|
-
query_param_filter = get_query_param_filter(each_block["query_params"])
|
|
250
|
-
headers = {"Content-Type": "application/vnd.api+json"}
|
|
251
|
-
if "headers" in each_block:
|
|
252
|
-
headers.update(each_block["headers"])
|
|
253
|
-
mcp_response = requests.get(
|
|
254
|
-
url = each_block["base_url"] + each_block["path"],
|
|
255
|
-
headers=headers,
|
|
256
|
-
params=query_param_filter
|
|
257
|
-
)
|
|
258
|
-
context_data = mcp_response.json()['data'] # result rows...
|
|
259
|
-
print_get_response(query_param_filter, mcp_response)
|
|
260
|
-
elif each_block["method"] in ["POST"]:
|
|
261
|
-
for each_order in context_data:
|
|
262
|
-
url = each_block["base_url"] + each_block["path"]
|
|
263
|
-
json_update_data = { 'data': {"type": "Email", 'attributes': {} } }
|
|
264
|
-
json_update_data_attributes = json_update_data["data"]["attributes"]
|
|
265
|
-
move_fields( src= each_block["body"], dest=json_update_data_attributes, context_data=each_order)
|
|
266
|
-
# eg: POST http://localhost:5656/api/Email {'data': {'type': 'Email', 'attributes': {'customer_id': 5, 'message': {'to': '{{ order.customer_id }}', 'subject': 'Discount for your order', 'body': 'Dear customer, you have a discount for your recent order. Thank you for shopping with us.'}}}}
|
|
267
|
-
headers = {"Content-Type": "application/vnd.api+json"}
|
|
268
|
-
if "headers" in each_block:
|
|
269
|
-
headers.update(each_block["headers"])
|
|
270
|
-
mcp_response = requests.post(
|
|
271
|
-
url=url,
|
|
272
|
-
headers=headers,
|
|
273
|
-
json=json_update_data
|
|
274
|
-
)
|
|
275
|
-
added_rows += 1
|
|
276
|
-
pass
|
|
277
|
-
print("\n3. MCP Server (als) POST Response:\n", mcp_response.text)
|
|
278
|
-
if added_rows > 0:
|
|
279
|
-
print(f"...Added {added_rows} rows to the database; last row (only) shown above.")
|
|
280
|
-
return mcp_response
|
|
101
|
+
server_setup.api_logic_server_setup(flask_app, args)
|
|
281
102
|
|
|
103
|
+
AdminLoader.admin_events(flask_app = flask_app, args = args, validation_error = ValidationError)
|
|
282
104
|
|
|
283
105
|
if __name__ == "__main__":
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
106
|
+
msg = f'API Logic Project loaded (not WSGI), version: 15.00.08\n'
|
|
107
|
+
msg += f'.. startup message: {start_up_message}\n'
|
|
108
|
+
if server_setup.is_docker():
|
|
109
|
+
msg += f' (running from docker container at flask_host: {args.flask_host} - may require refresh)\n'
|
|
110
|
+
else:
|
|
111
|
+
msg += f' (running locally at flask_host: {args.flask_host})\n'
|
|
112
|
+
app_logger.info(f'\n{msg}')
|
|
113
|
+
|
|
114
|
+
if args.create_and_run:
|
|
115
|
+
app_logger.info(f'==> Customizable API Logic Project created and running:\n'
|
|
116
|
+
f'..Open it with your IDE at {project_dir}\n')
|
|
117
|
+
|
|
118
|
+
start_up_message = f'{args.http_scheme}://{args.swagger_host}:{args.port} *'
|
|
119
|
+
if os.getenv('CODESPACES'):
|
|
120
|
+
app_logger.info(f'API Logic Project (name: {project_name}) starting on Codespaces:\n'
|
|
121
|
+
f'..Explore data and API on codespaces, swagger_host: {args.http_scheme}://{args.swagger_host}/\n')
|
|
122
|
+
start_up_message = f'{args.http_scheme}://{args.swagger_host}'
|
|
123
|
+
else:
|
|
124
|
+
app_logger.info(f'API Logic Project (name: {project_name}) starting:\n'
|
|
125
|
+
f'..Explore data and API at http_scheme://swagger_host:port {start_up_message}\n'
|
|
126
|
+
f'.... with flask_host: {args.flask_host}\n'
|
|
127
|
+
f'.... and swagger_port: {args.swagger_port}')
|
|
128
|
+
if logic_alerts:
|
|
129
|
+
app_logger.info(f'\nAlert: These following are **Critical** to unlocking value for project: {project_name}:')
|
|
130
|
+
app_logger.info(f'.. see logic.declare_logic.py -- {server_setup.declare_logic_message}')
|
|
131
|
+
app_logger.info(f'.. see security.declare_security.py -- {server_setup.declare_security_message}\n\n')
|
|
132
|
+
|
|
133
|
+
app_logger.info(f'*************************************************************************')
|
|
134
|
+
app_logger.info(f'* Startup Instructions: Open your Browser at: {start_up_message}')
|
|
135
|
+
app_logger.info(f'*************************************************************************\n')
|
|
136
|
+
|
|
137
|
+
flask_app.run(host=args.flask_host, threaded=True, port=args.port)
|
|
138
|
+
else:
|
|
139
|
+
msg = f'API Logic Project Loaded (WSGI), version 15.00.08\n'
|
|
140
|
+
msg += f'.. startup message: {start_up_message}\n'
|
|
141
|
+
|
|
142
|
+
if server_setup.is_docker():
|
|
143
|
+
msg += f' (running from docker container at {args.flask_host} - may require refresh)\n'
|
|
144
|
+
else:
|
|
145
|
+
msg += f' (running locally at flask_host: {args.flask_host})\n'
|
|
146
|
+
app_logger.info(f'\n{msg}')
|
|
147
|
+
app_logger.info(f'API Logic Project (name: {project_name}) starting:\n'
|
|
148
|
+
f'..Explore data and API at http_scheme://swagger_host:port {args.http_scheme}://{args.swagger_host}:{args.port}\n'
|
|
149
|
+
f'.... with flask_host: {args.flask_host}\n'
|
|
150
|
+
f'.... and swagger_port: {args.swagger_port}')
|