ApiLogicServer 15.2.0__py3-none-any.whl → 15.2.7__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/api_logic_server.py +3 -2
- api_logic_server_cli/prototypes/base/.github/.copilot-instructions.md +115 -31
- api_logic_server_cli/prototypes/base/docs/training/testing.md +116 -18
- api_logic_server_cli/prototypes/base/test/api_logic_server_behave/behave_logic_report.py +55 -29
- api_logic_server_cli/prototypes/base/test/api_logic_server_behave/behave_logic_report.py.bak +285 -0
- api_logic_server_cli/prototypes/{base/.github/.copilot-instructionsZ.mdx → basic_demo/.github/.copilot-instructions.md} +111 -30
- api_logic_server_cli/prototypes/basic_demo/customizations/test/api_logic_server_behave/reports/Behave Logic Report Intro micro.md +35 -0
- api_logic_server_cli/prototypes/basic_demo/customizations/test/api_logic_server_behave/reports/Behave Logic Report Intro.md +35 -0
- api_logic_server_cli/prototypes/basic_demo/readme.md +12 -4
- api_logic_server_cli/prototypes/basic_demo/tutor.md +1196 -0
- api_logic_server_cli/prototypes/manager/.github/.copilot-instructions.md +50 -23
- api_logic_server_cli/prototypes/manager/samples/basic_demo_sample/.github/.copilot-instructions.md +3 -0
- api_logic_server_cli/prototypes/manager/samples/basic_demo_sample/docs/training/testing.md +305 -21
- api_logic_server_cli/prototypes/manager/samples/basic_demo_sample/test/api_logic_server_behave/behave_logic_report.py +13 -84
- api_logic_server_cli/prototypes/manager/samples/basic_demo_sample/test/api_logic_server_behave/behave_logic_report.py.bak +282 -0
- api_logic_server_cli/prototypes/manager/samples/basic_demo_sample/test/api_logic_server_behave/features/order_processing.feature +59 -50
- api_logic_server_cli/prototypes/manager/samples/basic_demo_sample/test/api_logic_server_behave/features/steps/order_processing_steps.py +395 -248
- api_logic_server_cli/prototypes/manager/samples/basic_demo_sample/test/api_logic_server_behave/logs/behave.log +66 -62
- api_logic_server_cli/prototypes/manager/samples/basic_demo_sample/test/api_logic_server_behave/logs/scenario_logic_logs/Carbon_Neutral_Discount_A.log +51 -41
- api_logic_server_cli/prototypes/manager/samples/basic_demo_sample/test/api_logic_server_behave/logs/scenario_logic_logs/Change_Order_Customer.log +29 -0
- api_logic_server_cli/prototypes/manager/samples/basic_demo_sample/test/api_logic_server_behave/logs/scenario_logic_logs/Change_Product_in_Item.log +35 -0
- api_logic_server_cli/prototypes/manager/samples/basic_demo_sample/test/api_logic_server_behave/logs/scenario_logic_logs/Delete_Item_Reduces_Order.log +39 -19
- api_logic_server_cli/prototypes/manager/samples/basic_demo_sample/test/api_logic_server_behave/logs/scenario_logic_logs/Exceed_Credit_Limit_Rejec.log +36 -45
- api_logic_server_cli/prototypes/manager/samples/basic_demo_sample/test/api_logic_server_behave/logs/scenario_logic_logs/Good_Order_Placed_via_B2B.log +50 -40
- api_logic_server_cli/prototypes/manager/samples/basic_demo_sample/test/api_logic_server_behave/logs/scenario_logic_logs/Item_Quantity_Change.log +33 -0
- api_logic_server_cli/prototypes/manager/samples/basic_demo_sample/test/api_logic_server_behave/logs/scenario_logic_logs/Multi-Item_Order_via_B2B_.log +67 -0
- api_logic_server_cli/prototypes/manager/samples/basic_demo_sample/test/api_logic_server_behave/logs/scenario_logic_logs/Ship_Order_Excludes_from_.log +24 -14
- api_logic_server_cli/prototypes/manager/samples/basic_demo_sample/test/api_logic_server_behave/logs/scenario_logic_logs/Transaction_Processing.log +26 -17
- api_logic_server_cli/prototypes/manager/samples/basic_demo_sample/test/api_logic_server_behave/logs/scenario_logic_logs/Unship_Order_Includes_in_.log +24 -14
- api_logic_server_cli/prototypes/manager/samples/basic_demo_sample/test/api_logic_server_behave/reports/Behave Logic Report.md +361 -146
- api_logic_server_cli/prototypes/manager/system/ApiLogicServer-Internal-Dev/copilot-dev-context.md +275 -4
- api_logic_server_cli/prototypes/manager/system/app_model_editor/test/api_logic_server_behave/behave_logic_report.py +13 -75
- api_logic_server_cli/prototypes/manager/system/app_model_editor/test/api_logic_server_behave/behave_logic_report.py.bak +256 -0
- api_logic_server_cli/prototypes/manager/system/genai/examples/genai_demo/genai_demo_docs_logic/test/api_logic_server_behave/behave_logic_report.py +13 -75
- api_logic_server_cli/prototypes/manager/system/genai/examples/genai_demo/genai_demo_docs_logic/test/api_logic_server_behave/behave_logic_report.py.bak +256 -0
- api_logic_server_cli/prototypes/nw/test/api_logic_server_behave/reports/Behave Logic Report Intro micro.md +17 -0
- api_logic_server_cli/prototypes/nw/test/api_logic_server_behave/reports/Behave Logic Report Intro.md +17 -0
- {apilogicserver-15.2.0.dist-info → apilogicserver-15.2.7.dist-info}/METADATA +103 -23
- {apilogicserver-15.2.0.dist-info → apilogicserver-15.2.7.dist-info}/RECORD +43 -30
- {apilogicserver-15.2.0.dist-info → apilogicserver-15.2.7.dist-info}/WHEEL +0 -0
- {apilogicserver-15.2.0.dist-info → apilogicserver-15.2.7.dist-info}/entry_points.txt +0 -0
- {apilogicserver-15.2.0.dist-info → apilogicserver-15.2.7.dist-info}/licenses/LICENSE +0 -0
- {apilogicserver-15.2.0.dist-info → apilogicserver-15.2.7.dist-info}/top_level.txt +0 -0
api_logic_server_cli/prototypes/manager/system/ApiLogicServer-Internal-Dev/copilot-dev-context.md
CHANGED
|
@@ -1,3 +1,15 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Context Restoration for BLT Manager Workspace
|
|
3
|
+
Description: Re-establishes AI assistant context after BLT regenerates workspace
|
|
4
|
+
Source: ApiLogicServer-src/prototypes/manager/system/ApiLogicServer-Internal-Dev/copilot-dev-context.md
|
|
5
|
+
Propagation: BLT process → Manager workspace
|
|
6
|
+
Usage: AI assistants read this to understand project structure, development workflow, and recent additions
|
|
7
|
+
version: 2.0
|
|
8
|
+
changelog:
|
|
9
|
+
- 2.0 (Oct 2025) - Added AI-Guided Training section (tutor.md v2.0, OBX improvements, design philosophy)
|
|
10
|
+
- 1.0 (Initial) - Established workspace structure, GenAI prompt engineering, development workflow
|
|
11
|
+
---
|
|
12
|
+
|
|
1
13
|
# Context Restoration: BLT Manager Workspace
|
|
2
14
|
|
|
3
15
|
**Purpose:** This file re-establishes AI assistant context after BLT runs regenerate this workspace.
|
|
@@ -75,10 +87,33 @@ This document contains **everything** you need to understand the system:
|
|
|
75
87
|
|
|
76
88
|
### For Creating New Projects:
|
|
77
89
|
- **Manager-level `.copilot-instructions.md`** - How to CREATE projects (in workspace root)
|
|
78
|
-
-
|
|
90
|
+
- **Location:** `prototypes/manager/.github/.copilot-instructions.md`
|
|
91
|
+
- **Size:** ~86 lines
|
|
92
|
+
- **Scope:** Creating projects ONLY (3 methods: existing DB, GenAI, new DB)
|
|
93
|
+
- **Purpose:** Instructions for creating new projects with `genai-logic create` commands
|
|
94
|
+
- **Does NOT contain:** Project customization, logic patterns, testing, security, etc.
|
|
79
95
|
|
|
80
96
|
### For Working Within Created Projects:
|
|
81
97
|
- **Project-level `.copilot-instructions.md`** - How to EXTEND/CUSTOMIZE projects (auto-generated in each project)
|
|
98
|
+
- **Location:** `prototypes/base/.github/.copilot-instructions.md` (template)
|
|
99
|
+
- **Size:** ~740 lines
|
|
100
|
+
- **Scope:** Complete architecture guide for EACH created project
|
|
101
|
+
- **Purpose:** 13 Main Services (what AI can do in a project):
|
|
102
|
+
1. **Run Project** - F5 debug, `api_logic_server_run.py`
|
|
103
|
+
2. **Adding Business Logic** - Translate NL → LogicBank rules (sums, formulas, constraints, events)
|
|
104
|
+
3. **Discovery Systems** - Auto-load logic from `logic/logic_discovery/*.py`, APIs from `api/api_discovery/*.py`
|
|
105
|
+
4. **Automated Testing** - Behave tests with BLT reports (requirements traceability)
|
|
106
|
+
5. **Adding MCP** - Enable MCP client UI with `genai-logic genai-add-mcp-client`
|
|
107
|
+
6. **Configuring Admin UI** - Edit `ui/admin/admin.yaml` for customization
|
|
108
|
+
7. **Create React Apps** - `genai-logic genai-add-app` for custom UIs
|
|
109
|
+
8. **Security - RBAC** - `als add-auth` for SQL/Keycloak, `security/declare_security.py` for grants
|
|
110
|
+
9. **Custom API Endpoints** - Add routes in `api/customize_api.py`
|
|
111
|
+
10. **B2B Integration APIs** - Complex endpoints with Row Dict Mappers for partner integration
|
|
112
|
+
11. **Customize Models** - Add tables, attributes, derived fields
|
|
113
|
+
12. **Adding Events** - Row events for integrations (Kafka, webhooks, etc.)
|
|
114
|
+
13. **Critical Patterns** - React component best practices, null-safe constraints, test repeatability
|
|
115
|
+
- ⚠️ **CRITICAL:** These are TWO DIFFERENT FILES - never replace the per-project version with the manager version!
|
|
116
|
+
- 🚨 **PROPAGATION PROBLEM:** Changes to project-level instructions must be carefully copied to `prototypes/base/.github/.copilot-instructions.md`
|
|
82
117
|
- **`docs/training/logic_bank_api.prompt`** - LogicBank API reference (Rosetta Stone for rules)
|
|
83
118
|
- **`docs/training/testing.md`** - Behave testing guide (1755 lines, read BEFORE creating tests)
|
|
84
119
|
|
|
@@ -87,6 +122,50 @@ This document contains **everything** you need to understand the system:
|
|
|
87
122
|
- **[Installation Guide](https://apilogicserver.github.io/Docs/Install/)** - Setup procedures
|
|
88
123
|
- **[Tutorial](https://apilogicserver.github.io/Docs/Tutorial/)** - Step-by-step learning
|
|
89
124
|
|
|
125
|
+
### For AI-Guided Training (New Feature):
|
|
126
|
+
- **`basic_demo/tutor.md`** - AI assistant guide for conducting 30-45 min hands-on tour
|
|
127
|
+
- **Version:** 2.0 (762 lines, October 2025)
|
|
128
|
+
- **Purpose:** "Message in a bottle" for AI assistants - enables guided discovery learning
|
|
129
|
+
- **Method:** Provocation-based (e.g., "how did it know ORDER has a foreign key to Customer?")
|
|
130
|
+
- **Philosophy:** Users learn by DOING (hands-on tour), not reading docs or taking quizzes (Versata approach)
|
|
131
|
+
- **Structure:** 9 sections with timing checkpoints (15 min, 35 min), concrete metrics (48 vs 200+ lines)
|
|
132
|
+
- **Key Additions in v2.0:** Spreadsheet analogy, procedural comparison (BUG FIX examples), context for schema commands, three ways to add logic (Discovery/IDE/Chat), MCP server integration
|
|
133
|
+
- **Location:** `prototypes/basic_demo/tutor.md` (template), propagates to created `basic_demo` projects
|
|
134
|
+
- **Invocation:** User says "Guide me through basic_demo" → AI reads tutor.md → conducts tour
|
|
135
|
+
|
|
136
|
+
- **Design Philosophy - Why Provocation Over Instruction:**
|
|
137
|
+
- **Problem with traditional training:** PowerPoint → quiz/assessment approach tests memorization, not understanding
|
|
138
|
+
- **Versata insight:** "Stop killing people with PowerPoint; identify critical skills, design lab to DO it"
|
|
139
|
+
- **Discovery learning:** Ask provocative questions that force pattern recognition ("How did it know ORDER references CUSTOMER?")
|
|
140
|
+
- **"Aha moments" over rote learning:** User discovers foreign keys exist, then learns they're essential for multi-table logic
|
|
141
|
+
- **Spreadsheet analogy:** Excel user understands formulas → multi-table database is "Excel for related tables"
|
|
142
|
+
- **AI as training partner DURING the lab:** Not quiz after, not docs before - real-time guidance while doing
|
|
143
|
+
- **Result:** 30-45 min hands-on experience creates deeper understanding than hours of documentation reading
|
|
144
|
+
|
|
145
|
+
- **v1.0 → v2.0 Evolution (Battle-Tested Refinements):**
|
|
146
|
+
- **v1.0 (595 lines):** Initial design based on architecture understanding
|
|
147
|
+
- **Live testing:** User spent "several hours with your cousin testing and revising" actual tours
|
|
148
|
+
- **v2.0 (+506 net lines):** Added based on what users actually needed during tours:
|
|
149
|
+
- **Spreadsheet analogy** - Non-technical users needed familiar mental model
|
|
150
|
+
- **Procedural comparison** - Show 48 vs 200+ lines WITH concrete BUG FIX examples (not just line counts)
|
|
151
|
+
- **Context for commands** - Why `add-cust` exists (schema variability, new users discover structure)
|
|
152
|
+
- **Three ways to add logic** - Discovery file (recommended), IDE autocomplete, or Chat
|
|
153
|
+
- **Timing checkpoints** - 15 min at Security, 35 min at Q&A (helps pace the tour)
|
|
154
|
+
- **MCP server mention** - Claude Desktop integration for external AI access
|
|
155
|
+
- **Best practices** - `logic/logic_discovery/` organization pattern
|
|
156
|
+
- **Short response guidance** - "One idea per interaction" prevents overwhelming new users
|
|
157
|
+
- **Key learning:** Initial version was too instruction-heavy, v2.0 adds more context and concrete examples
|
|
158
|
+
|
|
159
|
+
- **OBX (Out-of-Box Experience) Design** - Manager → Project flow optimization (October 2025):
|
|
160
|
+
- **Manager README:** "🚀 First Time Here? Start with basic_demo" section (clear default path)
|
|
161
|
+
- **Manager .copilot-instructions.md:** "CRITICAL: ALWAYS start" directive (no choices, single path)
|
|
162
|
+
- **Project README:** "🤖 Ready to Explore? Recommended: Guide me through" (guided tour as primary option)
|
|
163
|
+
- **Project .copilot-instructions.md:** "🎯 Most Common Next Steps" (5 succinct items at top)
|
|
164
|
+
- **Goal:** Eliminate friction/choice paralysis, make basic_demo → guided tour the clear default
|
|
165
|
+
- **Problem addressed:** Users didn't automatically know to start with basic_demo, didn't default to guided tour
|
|
166
|
+
- **Solution:** Strengthen every touch point in the journey to push toward the optimal path
|
|
167
|
+
- **Flow:** Install → Open Manager → Create basic_demo → Auto-opens → "Guide me through" → 30-45 min tour
|
|
168
|
+
|
|
90
169
|
|
|
91
170
|
|
|
92
171
|
## 👤 Current Maintainer
|
|
@@ -110,11 +189,14 @@ This document contains **everything** you need to understand the system:
|
|
|
110
189
|
1. **Read [Architecture-Internals.md](https://apilogicserver.github.io/Docs/Architecture-Internals/)** for complete technical context
|
|
111
190
|
2. Identify which documentation to consult based on task:
|
|
112
191
|
- Framework development → Architecture-Internals.md
|
|
113
|
-
- Project creation → Manager-level `.copilot-instructions.md`
|
|
114
|
-
- Project customization → Project-level `.copilot-instructions.md`
|
|
192
|
+
- Project creation → Manager-level `.copilot-instructions.md` (86 lines, in prototypes/manager/)
|
|
193
|
+
- Project customization → Project-level `.copilot-instructions.md` (740 lines, in prototypes/base/)
|
|
115
194
|
- Adding logic → `docs/training/logic_bank_api.prompt`
|
|
116
195
|
- Creating tests → `docs/training/testing.md`
|
|
117
|
-
3.
|
|
196
|
+
3. **CRITICAL:** Never confuse the two `.copilot-instructions.md` files:
|
|
197
|
+
- Manager version = how to CREATE projects (small, workspace-level)
|
|
198
|
+
- Project version = how to CUSTOMIZE projects (large, per-project with architecture details)
|
|
199
|
+
4. When role unclear, ask: "Are you testing as a user or working on internals?"
|
|
118
200
|
|
|
119
201
|
### Key Principles:
|
|
120
202
|
- **Assume deep technical expertise** - Technology refined over 40+ years
|
|
@@ -122,6 +204,195 @@ This document contains **everything** you need to understand the system:
|
|
|
122
204
|
- **Respect the architecture** - Patterns represent battle-tested solutions from thousands of deployments
|
|
123
205
|
- **Check training materials** - `logic_bank_api.prompt` and `testing.md` prevent common AI mistakes
|
|
124
206
|
|
|
207
|
+
### Communication Tone Guidelines:
|
|
208
|
+
- **Confident but NEVER hyperbolic** - Make only claims backed by specific, measurable evidence
|
|
209
|
+
- **Cite concrete metrics** - "200 lines → 5 rules (40X)" not "transforms years into days"
|
|
210
|
+
- **Reference historical facts** - "40+ years, 6,000+ deployments" establishes credibility
|
|
211
|
+
- **Avoid unfounded superlatives** - No "revolutionary", "game-changing", or time-compression claims without data
|
|
212
|
+
- **Be specific** - "Creates working API in 5 seconds" vs "drastically reduces development time"
|
|
213
|
+
- **NEVER claim** - Time compression like "30-40 years → 3-4 days" - these are unmeasurable and unfounded
|
|
214
|
+
- **DO claim** - Specific productivity gains with evidence: "40X code reduction", "instant API from database"
|
|
215
|
+
|
|
216
|
+
|
|
217
|
+
|
|
218
|
+
## 🤖 GenAI Prompt Engineering Architecture
|
|
219
|
+
|
|
220
|
+
### Overview: ChatGPT Project Creation Pipeline
|
|
221
|
+
|
|
222
|
+
The `genai-logic create` command uses **fine-tuned ChatGPT** to translate natural language requirements into complete working projects. The system uses **prompt engineering** to surround user input with structured instructions.
|
|
223
|
+
|
|
224
|
+
### Key Locations
|
|
225
|
+
|
|
226
|
+
**Prompt Templates:** `system/genai/prompt_inserts/`
|
|
227
|
+
```
|
|
228
|
+
├── sqlite_inserts.prompt # Main orchestrator for DB creation
|
|
229
|
+
├── sqlite_inserts_model_test_hints.prompt # SQLAlchemy class generation rules
|
|
230
|
+
├── logic_inserts.prompt # LogicBank rule generation
|
|
231
|
+
├── logic_translate.prompt # NL → LogicBank translation (existing DB)
|
|
232
|
+
├── graphics.prompt # Dashboard chart generation
|
|
233
|
+
├── response_format.prompt # WGResult Pydantic schema
|
|
234
|
+
└── web_genai.prompt # WebGenAI-specific (15+ tables)
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
**Training Examples:** `org_git/ApiLogicServer-src/tests/genai_tests/logic_training/`
|
|
238
|
+
```
|
|
239
|
+
├── genai_demo.prompt # Check Credit + No Empty Orders
|
|
240
|
+
├── ready_flag.prompt # Ready Flag pattern (3 use cases)
|
|
241
|
+
├── emp_depts.prompt # Chain Up: sum salaries, constrain budget
|
|
242
|
+
├── graduate.prompt # Cardinality: counts with thresholds
|
|
243
|
+
├── products.prompt # Qualified Any: severity checks
|
|
244
|
+
├── honor_society.prompt # Complex cardinality with qualified counts
|
|
245
|
+
└── *.txt / *_corrected_prompt.txt # Expected outputs and corrections
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
**Test Examples:** `system/genai/examples/`
|
|
249
|
+
```
|
|
250
|
+
├── genai_demo/ # Complete example with iterations
|
|
251
|
+
├── airport/ # Complex 10+ table system
|
|
252
|
+
├── emp_depts/ # Simple aggregation pattern
|
|
253
|
+
└── time_tracking_billing/ # Real-world scenario
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
### The Prompt Assembly Process
|
|
257
|
+
|
|
258
|
+
**User Input:**
|
|
259
|
+
```
|
|
260
|
+
Create a system with customers, orders, items and products.
|
|
261
|
+
|
|
262
|
+
Use case: Check Credit
|
|
263
|
+
1. Customer.balance <= credit_limit
|
|
264
|
+
2. Customer.balance = Sum(Order.amount_total where date_shipped is null)
|
|
265
|
+
3. Order.amount_total = Sum(Item.amount)
|
|
266
|
+
4. Item.amount = quantity * unit_price
|
|
267
|
+
5. Item.unit_price = copy from Product.unit_price
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
**System Surrounds With:**
|
|
271
|
+
|
|
272
|
+
1. **Model Generation Instructions** (`sqlite_inserts_model_test_hints.prompt`):
|
|
273
|
+
- Use autonum keys for ALL tables (including junction tables)
|
|
274
|
+
- Create classes, never tables (Class names singular, capitalized)
|
|
275
|
+
- **CRITICAL:** "If you create sum, count or formula Logic Bank rules, then you MUST create a corresponding column in the data model"
|
|
276
|
+
- No check constraints (logic uses rules instead)
|
|
277
|
+
- Foreign key columns (not relationship names) for test data
|
|
278
|
+
|
|
279
|
+
2. **Logic Generation Instructions** (`logic_inserts.prompt`):
|
|
280
|
+
- "Use LogicBank to enforce these requirements (do not generate check constraints)"
|
|
281
|
+
- "be sure to update the data model and *all* test data with any attributes used in the logic"
|
|
282
|
+
|
|
283
|
+
3. **Response Structure** (`response_format.prompt`):
|
|
284
|
+
```python
|
|
285
|
+
class WGResult(BaseModel):
|
|
286
|
+
models: List[Model] # SQLAlchemy classes
|
|
287
|
+
rules: List[Rule] # LogicBank declarations
|
|
288
|
+
test_data: str # Python test data creation
|
|
289
|
+
test_data_rows: List[TestDataRow]
|
|
290
|
+
test_data_sqlite: str # INSERT statements
|
|
291
|
+
graphics: List[Graphic] # Dashboard queries
|
|
292
|
+
name: str # Suggested project name
|
|
293
|
+
```
|
|
294
|
+
|
|
295
|
+
**Result:** ChatGPT returns structured JSON with models, rules, and test data that:
|
|
296
|
+
- Has `Customer.balance`, `Order.amount_total`, `Order.item_count` columns created automatically
|
|
297
|
+
- Contains LogicBank rules for all derivations
|
|
298
|
+
- Includes test data with derived attributes pre-initialized
|
|
299
|
+
|
|
300
|
+
### Key Insight: Model + Logic Co-Generation
|
|
301
|
+
|
|
302
|
+
**Unlike existing database projects**, GenAI creation can **modify the data model** to support logic:
|
|
303
|
+
|
|
304
|
+
- **Derived attributes materialize:** `Customer.balance`, `Order.amount_total`, `Product.total_ordered`
|
|
305
|
+
- **Count columns appear:** `Order.item_count` for existence checks
|
|
306
|
+
- **Qualified counts split:** `Product.notice_count` + `Product.severity_five_count`
|
|
307
|
+
|
|
308
|
+
This is why the training examples emphasize:
|
|
309
|
+
> "If you create sum, count or formula Logic Bank rules, then you MUST create a corresponding column in the data model."
|
|
310
|
+
|
|
311
|
+
### Training Pattern Categories
|
|
312
|
+
|
|
313
|
+
The `logic_training/` examples teach ChatGPT these patterns:
|
|
314
|
+
|
|
315
|
+
1. **Chain Up (Aggregation → Constraint)**
|
|
316
|
+
- `emp_depts`: Department.total_salary = sum(Employee.salary); salary <= budget
|
|
317
|
+
- `genai_demo`: Customer.balance = sum(orders); balance <= credit_limit
|
|
318
|
+
|
|
319
|
+
2. **Counts as Existence Checks**
|
|
320
|
+
- `genai_demo`: Order.item_count = count(Items); can't ship if == 0
|
|
321
|
+
- Creates both derivation AND validation
|
|
322
|
+
|
|
323
|
+
3. **Cardinality Patterns (Qualified Any)**
|
|
324
|
+
- `products`: Total notices + severity 5 notices; constraint if orderable
|
|
325
|
+
- `graduate`: Probation count + sick days; constraint for graduation
|
|
326
|
+
- Pattern: Multiple counts (total + qualified) with complex conditions
|
|
327
|
+
|
|
328
|
+
4. **Ready Flag**
|
|
329
|
+
- `ready_flag`: Multi-use-case with conditional aggregations
|
|
330
|
+
- Customer.balance only sums orders where `ready == True AND date_shipped is None`
|
|
331
|
+
- Product.total_ordered only sums items where `ready == True`
|
|
332
|
+
|
|
333
|
+
5. **Chain Down (Copy/Formula)**
|
|
334
|
+
- Item.unit_price = copy(Product.unit_price)
|
|
335
|
+
- Item.ready = Order.ready (formula propagation)
|
|
336
|
+
|
|
337
|
+
### CLI Commands Using This System
|
|
338
|
+
|
|
339
|
+
**Create from natural language:**
|
|
340
|
+
```bash
|
|
341
|
+
genai-logic create --project-name=my_system --using="<natural language>"
|
|
342
|
+
# Internally: assembles prompts → ChatGPT → parses WGResult → generates project
|
|
343
|
+
```
|
|
344
|
+
|
|
345
|
+
**Translate logic (existing DB):**
|
|
346
|
+
```bash
|
|
347
|
+
genai-logic logic-translate --project-name=. --using-file=docs/logic
|
|
348
|
+
# Uses logic_translate.prompt to convert NL in docs/logic → rules in logic/logic_discovery/
|
|
349
|
+
```
|
|
350
|
+
|
|
351
|
+
### Fine-Tuning Files
|
|
352
|
+
|
|
353
|
+
**Training Data:** `logic_training/ft.jsonl`
|
|
354
|
+
- JSONL format for ChatGPT fine-tuning
|
|
355
|
+
- Generated from prompt/response pairs
|
|
356
|
+
- ~374KB with all pattern examples
|
|
357
|
+
|
|
358
|
+
**Script:** `logic_training/create_json_l.py`
|
|
359
|
+
- Converts `*.prompt` + `*.txt` → JSONL entries
|
|
360
|
+
- Format: system message, user message (prompt), assistant message (response)
|
|
361
|
+
|
|
362
|
+
### Common Pitfalls (Why Corrections Exist)
|
|
363
|
+
|
|
364
|
+
Several `*_corrected_prompt.txt` files show typical AI mistakes:
|
|
365
|
+
|
|
366
|
+
1. **Wrong cardinality:**
|
|
367
|
+
- `airport.prompt`: Asked for "airplane's passengers" but meant "flight's passengers"
|
|
368
|
+
- AI can't count passengers on an Airplane (no direct relationship)
|
|
369
|
+
- Correction: Count passengers on Flight, constrain by Airplane.seating_capacity
|
|
370
|
+
|
|
371
|
+
2. **Constraint depends on derived flag:**
|
|
372
|
+
- `products.prompt` initially: "product is orderable IF no severity 5 notices"
|
|
373
|
+
- Problem: Makes orderable a derived value, then uses it in constraint
|
|
374
|
+
- Correction: "RAISE ERROR if orderable == True AND has severity 5 notices"
|
|
375
|
+
- Pattern: Flag is input, constraint uses it (not derived from constraint conditions)
|
|
376
|
+
|
|
377
|
+
3. **Negative condition logic:**
|
|
378
|
+
- Must use: `not(row.flag and bad_condition)`
|
|
379
|
+
- Not: `row.flag → requires good_condition` (harder for AI to translate)
|
|
380
|
+
|
|
381
|
+
### Why This Architecture?
|
|
382
|
+
|
|
383
|
+
**Traditional GenAI code generation problems:**
|
|
384
|
+
- Generates 200+ lines of procedural code
|
|
385
|
+
- Misses corner cases (foreign key changes, cascading updates)
|
|
386
|
+
- Creates technical debt (unmaintainable spaghetti)
|
|
387
|
+
|
|
388
|
+
**Declarative GenAI solution:**
|
|
389
|
+
- Generates **specifications** (5 rules), not code (200 lines)
|
|
390
|
+
- Rules executed by proven engine (40+ years, 6,000+ deployments)
|
|
391
|
+
- Engine handles ALL change paths automatically (no corner cases missed)
|
|
392
|
+
- Natural language → DSL → Runtime engine (not NL → procedural code)
|
|
393
|
+
|
|
394
|
+
**Critical difference:** The AI doesn't need to "think through" all possible change paths. It translates requirements to rules, and the engine provides correctness guarantee through automatic dependency analysis and chaining.
|
|
395
|
+
|
|
125
396
|
|
|
126
397
|
|
|
127
398
|
## 🔄 Development Workflow
|
|
@@ -176,81 +176,19 @@ def main(behave_log: str, scenario_logs: str, wiki: str, prepend_wiki: str):
|
|
|
176
176
|
wiki_data.append(" ")
|
|
177
177
|
each_line = "## " + each_line
|
|
178
178
|
if each_line.startswith(" Scenario"):
|
|
179
|
-
|
|
180
|
-
if each_line.startswith(" Given") or \
|
|
181
|
-
each_line.startswith(" When") or \
|
|
182
|
-
each_line.startswith(" Then"):
|
|
183
|
-
if each_line.startswith(" Then"):
|
|
184
|
-
just_saw_then = True
|
|
185
|
-
each_line = tab + tab + each_line
|
|
186
|
-
|
|
187
|
-
each_line = each_line[:-1]
|
|
188
|
-
debug_loc = each_line.find(behave_debug_info)
|
|
189
|
-
if debug_loc > 0:
|
|
190
|
-
each_line = each_line[0 : debug_loc]
|
|
191
|
-
each_line = each_line.rstrip()
|
|
192
|
-
if "Scenario" in each_line:
|
|
179
|
+
# Extract scenario name for logic lookup
|
|
193
180
|
current_scenario = each_line[18:]
|
|
194
181
|
wiki_data.append(" ")
|
|
195
182
|
wiki_data.append(" ")
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
def print_args(args, msg):
|
|
210
|
-
print(msg)
|
|
211
|
-
for each_arg in args:
|
|
212
|
-
print(f' {each_arg}')
|
|
213
|
-
print(" ")
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
@click.group()
|
|
217
|
-
@click.pass_context
|
|
218
|
-
def cli(ctx):
|
|
219
|
-
"""
|
|
220
|
-
Combine behave.log and scenario_logic_logs to create Behave Logic Report
|
|
221
|
-
|
|
222
|
-
"""
|
|
223
|
-
pass
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
@cli.command("run")
|
|
227
|
-
@click.pass_context
|
|
228
|
-
@click.option('--behave_log',
|
|
229
|
-
default=f'logs/behave.log', # cwd set to test/api_logic_server_behave
|
|
230
|
-
# prompt="Log from behave test suite run [behave.log]",
|
|
231
|
-
help="Help")
|
|
232
|
-
@click.option('--scenario_logs',
|
|
233
|
-
default=f'logs/scenario_logic_logs',
|
|
234
|
-
# prompt="Logic Log directory from ",
|
|
235
|
-
help="Help")
|
|
236
|
-
@click.option('--wiki',
|
|
237
|
-
default=f'reports/Behave Logic Report.md',
|
|
238
|
-
# prompt="Log from behave test suite run [api_logic_server_behave]",
|
|
239
|
-
help="Help")
|
|
240
|
-
@click.option('--prepend_wiki',
|
|
241
|
-
default=f'reports/Behave Logic Report Intro micro.md',
|
|
242
|
-
# prompt="Log from behave test suite run [Behave Logic Report Intro]",
|
|
243
|
-
help="Help")
|
|
244
|
-
def run(ctx, behave_log: str, scenario_logs: str, wiki: str, prepend_wiki: str):
|
|
245
|
-
main(behave_log = behave_log, scenario_logs = scenario_logs, wiki = wiki, prepend_wiki = prepend_wiki)
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
if __name__ == '__main__': # debugger & python command line start here
|
|
249
|
-
# eg: python api_logic_server_cli/cli.py create --project_name=~/Desktop/test_project
|
|
250
|
-
# unix: python api_logic_server_cli/cli.py create --project_name=/home/ApiLogicProject
|
|
251
|
-
|
|
252
|
-
print(f'\nBehave Logic Report 1.1, started at {os.getcwd()}')
|
|
253
|
-
commands = sys.argv
|
|
254
|
-
if len(sys.argv) > 1:
|
|
255
|
-
print_args(commands, f'\n\nCommand Line Arguments:')
|
|
256
|
-
cli()
|
|
183
|
+
# Remove the debug info (# features/...) from the scenario name
|
|
184
|
+
debug_loc = current_scenario.find(behave_debug_info)
|
|
185
|
+
if debug_loc > 0:
|
|
186
|
+
current_scenario = current_scenario[0:debug_loc].strip()
|
|
187
|
+
wiki_data.append(" ")
|
|
188
|
+
wiki_data.append(" ")
|
|
189
|
+
# Remove debug info from header line too
|
|
190
|
+
header_line = each_line[2:]
|
|
191
|
+
debug_loc = header_line.find(behave_debug_info)
|
|
192
|
+
if debug_loc > 0:
|
|
193
|
+
header_line = header_line[0:debug_loc].rstrip()
|
|
194
|
+
wiki_data.append("### " + header_line) # Add scenario header
|
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
import requests
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
import os
|
|
4
|
+
import ast
|
|
5
|
+
import sys
|
|
6
|
+
import click
|
|
7
|
+
|
|
8
|
+
"""
|
|
9
|
+
Creates wiki file from test/behave/behave.log, with rule use.
|
|
10
|
+
|
|
11
|
+
Tips
|
|
12
|
+
* use 2 spaces (at end) for newline
|
|
13
|
+
* for tab: & emsp;
|
|
14
|
+
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
tab = " "
|
|
18
|
+
behave_debug_info = " # "
|
|
19
|
+
wiki_data = []
|
|
20
|
+
debug_scenario = "XXGood Order Custom Service"
|
|
21
|
+
|
|
22
|
+
scenario_doc_strings = {}
|
|
23
|
+
""" dict of scenario_name, array of strings """
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def remove_trailer(line: str) -> str:
|
|
27
|
+
""" remove everything after the ## """
|
|
28
|
+
end_here = line.find("\t\t##")
|
|
29
|
+
result = line[0:end_here]
|
|
30
|
+
return result
|
|
31
|
+
|
|
32
|
+
def line_spacer():
|
|
33
|
+
wiki_data.append("\n")
|
|
34
|
+
wiki_data.append(" ")
|
|
35
|
+
wiki_data.append(" ")
|
|
36
|
+
wiki_data.append("\n")
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def get_current_readme(prepend_wiki: str):
|
|
40
|
+
""" initialize wiki_data with readme up to {report_name} """
|
|
41
|
+
report_name = "Behave Logic Report"
|
|
42
|
+
with open(prepend_wiki) as readme:
|
|
43
|
+
readme_lines = readme.readlines()
|
|
44
|
+
need_spacer = True
|
|
45
|
+
for each_readme_line in readme_lines:
|
|
46
|
+
if '# ' + report_name in each_readme_line:
|
|
47
|
+
need_spacer = False
|
|
48
|
+
break
|
|
49
|
+
wiki_data.append(each_readme_line[0:-1])
|
|
50
|
+
if need_spacer:
|
|
51
|
+
line_spacer()
|
|
52
|
+
wiki_data.append(f'# {report_name}')
|
|
53
|
+
|
|
54
|
+
def get_truncated_scenario_name(scenario_name: str) -> str:
|
|
55
|
+
""" address max file length (chop at 26), illegal characters """
|
|
56
|
+
scenario_trunc = scenario_name
|
|
57
|
+
if scenario_trunc is not None and len(scenario_trunc) >= 26:
|
|
58
|
+
scenario_trunc = scenario_name[0:25]
|
|
59
|
+
scenario_trunc = f'{str(scenario_trunc).replace(" ", "_")}'
|
|
60
|
+
return scenario_trunc
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def show_logic(scenario: str, logic_logs_dir: str):
|
|
64
|
+
""" insert s{logic_logs_dir}/scenario.log into wiki_data as disclosure area """
|
|
65
|
+
scenario_trunc = get_truncated_scenario_name(scenario)
|
|
66
|
+
logic_file_name = f'{logic_logs_dir}/{scenario_trunc}.log'
|
|
67
|
+
logic_file_name_path = Path(logic_file_name)
|
|
68
|
+
if not logic_file_name_path.is_file(): # debug code
|
|
69
|
+
# wiki_data.append(f'unable to find Logic Log file: {logic_file_name}')
|
|
70
|
+
if scenario == debug_scenario:
|
|
71
|
+
print(f'RELATIVE: {logic_file_name} in {os.getcwd()}')
|
|
72
|
+
full_name = f'{os.getcwd()}/{logic_file_name}'
|
|
73
|
+
print(f'..FULL: {os.getcwd()}/{logic_file_name}')
|
|
74
|
+
logic_file_name = '{logic_logs_dir}/test.log'
|
|
75
|
+
with open(logic_file_name) as logic:
|
|
76
|
+
logic_lines = logic.readlines()
|
|
77
|
+
else:
|
|
78
|
+
logic_log = []
|
|
79
|
+
rules_used = []
|
|
80
|
+
wiki_data.append("<details markdown>")
|
|
81
|
+
wiki_data.append("<summary>Tests - and their logic - are transparent.. click to see Logic</summary>")
|
|
82
|
+
line_spacer()
|
|
83
|
+
scenario_trunc = get_truncated_scenario_name(scenario)
|
|
84
|
+
if scenario_trunc in scenario_doc_strings:
|
|
85
|
+
wiki_data.append(f'**Logic Doc** for scenario: {scenario}')
|
|
86
|
+
wiki_data.append(" ")
|
|
87
|
+
for each_doc_string_line in scenario_doc_strings[scenario_trunc]:
|
|
88
|
+
wiki_data.append(each_doc_string_line[0: -1])
|
|
89
|
+
line_spacer()
|
|
90
|
+
wiki_data.append(f'**Rules Used** in Scenario: {scenario}')
|
|
91
|
+
wiki_data.append("```")
|
|
92
|
+
with open(logic_file_name) as logic:
|
|
93
|
+
logic_lines = logic.readlines()
|
|
94
|
+
is_logic_log = True
|
|
95
|
+
for each_logic_line in logic_lines:
|
|
96
|
+
each_logic_line = remove_trailer(each_logic_line)
|
|
97
|
+
if is_logic_log:
|
|
98
|
+
if "Rules Fired" in each_logic_line:
|
|
99
|
+
is_logic_log = False
|
|
100
|
+
continue
|
|
101
|
+
else:
|
|
102
|
+
logic_log.append(each_logic_line)
|
|
103
|
+
else:
|
|
104
|
+
if 'logic_logger - INFO' in each_logic_line:
|
|
105
|
+
pass
|
|
106
|
+
break
|
|
107
|
+
wiki_data.append(each_logic_line + " ")
|
|
108
|
+
wiki_data.append("```")
|
|
109
|
+
wiki_data.append(f'**Logic Log** in Scenario: {scenario}')
|
|
110
|
+
wiki_data.append("```")
|
|
111
|
+
for each_logic_log in logic_log:
|
|
112
|
+
each_line = remove_trailer(each_logic_log)
|
|
113
|
+
wiki_data.append(each_line)
|
|
114
|
+
wiki_data.append("```")
|
|
115
|
+
wiki_data.append("</details>")
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
def get_docStrings(steps_dir: str):
|
|
119
|
+
steps_dir_files = os.listdir(steps_dir)
|
|
120
|
+
indent = 4 # skip leading blanks
|
|
121
|
+
for each_steps_dir_file in steps_dir_files:
|
|
122
|
+
each_steps_dir_file_path = Path(steps_dir).joinpath(each_steps_dir_file)
|
|
123
|
+
if each_steps_dir_file_path.is_file():
|
|
124
|
+
with open(each_steps_dir_file_path) as f:
|
|
125
|
+
step_code = f.readlines()
|
|
126
|
+
# print(f'Found File: {str(each_steps_dir_file_path)}')
|
|
127
|
+
for index, each_step_code_line in enumerate(step_code):
|
|
128
|
+
if each_step_code_line.startswith('@when'):
|
|
129
|
+
comment_start = index + 2
|
|
130
|
+
if '"""' in step_code[comment_start]:
|
|
131
|
+
# print(".. found doc string")
|
|
132
|
+
doc_string_line = comment_start+1
|
|
133
|
+
doc_string = []
|
|
134
|
+
while (True):
|
|
135
|
+
if '"""' in step_code[doc_string_line]:
|
|
136
|
+
break
|
|
137
|
+
doc_string.append(step_code[doc_string_line][indent:])
|
|
138
|
+
doc_string_line += 1
|
|
139
|
+
scenario_line = doc_string_line+1
|
|
140
|
+
if 'scenario_name' not in step_code[scenario_line]:
|
|
141
|
+
print(f'\n** Warning - scenario_name not found '\
|
|
142
|
+
f'in file {str(each_steps_dir_file_path)}, '\
|
|
143
|
+
f'after line {scenario_line} -- skipped')
|
|
144
|
+
else:
|
|
145
|
+
scenario_code_line = step_code[scenario_line]
|
|
146
|
+
scenario_name_start = scenario_code_line.find("'") + 1
|
|
147
|
+
scenario_name_end = scenario_code_line[scenario_name_start+1:].find("'")
|
|
148
|
+
scenario_name = scenario_code_line[scenario_name_start:
|
|
149
|
+
scenario_name_end + scenario_name_start+1]
|
|
150
|
+
if scenario_name == debug_scenario:
|
|
151
|
+
print(f'got {debug_scenario}')
|
|
152
|
+
scenario_trunc = get_truncated_scenario_name(scenario_name)
|
|
153
|
+
# print(f'.... truncated scenario_name: {scenario_trunc} in {scenario_code_line}')
|
|
154
|
+
scenario_doc_strings[scenario_trunc] = doc_string
|
|
155
|
+
# print("that's all, folks")
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
def main(behave_log: str, scenario_logs: str, wiki: str, prepend_wiki: str):
|
|
159
|
+
""" main driver """
|
|
160
|
+
get_docStrings(steps_dir="features/steps")
|
|
161
|
+
|
|
162
|
+
get_current_readme(prepend_wiki=prepend_wiki)
|
|
163
|
+
|
|
164
|
+
contents = None
|
|
165
|
+
with open(behave_log) as f:
|
|
166
|
+
contents = f.readlines()
|
|
167
|
+
|
|
168
|
+
just_saw_then = False
|
|
169
|
+
current_scenario = ""
|
|
170
|
+
for each_line in contents:
|
|
171
|
+
if just_saw_then and each_line == "\n":
|
|
172
|
+
show_logic(scenario=current_scenario, logic_logs_dir=scenario_logs)
|
|
173
|
+
just_saw_then = False
|
|
174
|
+
if each_line.startswith("Feature"):
|
|
175
|
+
wiki_data.append(" ")
|
|
176
|
+
wiki_data.append(" ")
|
|
177
|
+
each_line = "## " + each_line
|
|
178
|
+
if each_line.startswith(" Scenario"):
|
|
179
|
+
each_line = tab + each_line
|
|
180
|
+
if each_line.startswith(" Given") or \
|
|
181
|
+
each_line.startswith(" When") or \
|
|
182
|
+
each_line.startswith(" Then"):
|
|
183
|
+
if each_line.startswith(" Then"):
|
|
184
|
+
just_saw_then = True
|
|
185
|
+
each_line = tab + tab + each_line
|
|
186
|
+
|
|
187
|
+
each_line = each_line[:-1]
|
|
188
|
+
debug_loc = each_line.find(behave_debug_info)
|
|
189
|
+
if debug_loc > 0:
|
|
190
|
+
each_line = each_line[0 : debug_loc]
|
|
191
|
+
each_line = each_line.rstrip()
|
|
192
|
+
if "Scenario" in each_line:
|
|
193
|
+
current_scenario = each_line[18:]
|
|
194
|
+
wiki_data.append(" ")
|
|
195
|
+
wiki_data.append(" ")
|
|
196
|
+
wiki_data.append("### " + each_line[8:])
|
|
197
|
+
|
|
198
|
+
each_line = each_line + " " # wiki for "new line"
|
|
199
|
+
|
|
200
|
+
wiki_data.append(each_line)
|
|
201
|
+
|
|
202
|
+
with open(wiki, 'w') as rpt:
|
|
203
|
+
rpt.write('\n'.join(wiki_data))
|
|
204
|
+
wiki_full_path = Path(wiki).absolute()
|
|
205
|
+
print(f'Wiki Output: {wiki_full_path}\n\n')
|
|
206
|
+
|
|
207
|
+
|
|
208
|
+
|
|
209
|
+
def print_args(args, msg):
|
|
210
|
+
print(msg)
|
|
211
|
+
for each_arg in args:
|
|
212
|
+
print(f' {each_arg}')
|
|
213
|
+
print(" ")
|
|
214
|
+
|
|
215
|
+
|
|
216
|
+
@click.group()
|
|
217
|
+
@click.pass_context
|
|
218
|
+
def cli(ctx):
|
|
219
|
+
"""
|
|
220
|
+
Combine behave.log and scenario_logic_logs to create Behave Logic Report
|
|
221
|
+
|
|
222
|
+
"""
|
|
223
|
+
pass
|
|
224
|
+
|
|
225
|
+
|
|
226
|
+
@cli.command("run")
|
|
227
|
+
@click.pass_context
|
|
228
|
+
@click.option('--behave_log',
|
|
229
|
+
default=f'logs/behave.log', # cwd set to test/api_logic_server_behave
|
|
230
|
+
# prompt="Log from behave test suite run [behave.log]",
|
|
231
|
+
help="Help")
|
|
232
|
+
@click.option('--scenario_logs',
|
|
233
|
+
default=f'logs/scenario_logic_logs',
|
|
234
|
+
# prompt="Logic Log directory from ",
|
|
235
|
+
help="Help")
|
|
236
|
+
@click.option('--wiki',
|
|
237
|
+
default=f'reports/Behave Logic Report.md',
|
|
238
|
+
# prompt="Log from behave test suite run [api_logic_server_behave]",
|
|
239
|
+
help="Help")
|
|
240
|
+
@click.option('--prepend_wiki',
|
|
241
|
+
default=f'reports/Behave Logic Report Intro micro.md',
|
|
242
|
+
# prompt="Log from behave test suite run [Behave Logic Report Intro]",
|
|
243
|
+
help="Help")
|
|
244
|
+
def run(ctx, behave_log: str, scenario_logs: str, wiki: str, prepend_wiki: str):
|
|
245
|
+
main(behave_log = behave_log, scenario_logs = scenario_logs, wiki = wiki, prepend_wiki = prepend_wiki)
|
|
246
|
+
|
|
247
|
+
|
|
248
|
+
if __name__ == '__main__': # debugger & python command line start here
|
|
249
|
+
# eg: python api_logic_server_cli/cli.py create --project_name=~/Desktop/test_project
|
|
250
|
+
# unix: python api_logic_server_cli/cli.py create --project_name=/home/ApiLogicProject
|
|
251
|
+
|
|
252
|
+
print(f'\nBehave Logic Report 1.1, started at {os.getcwd()}')
|
|
253
|
+
commands = sys.argv
|
|
254
|
+
if len(sys.argv) > 1:
|
|
255
|
+
print_args(commands, f'\n\nCommand Line Arguments:')
|
|
256
|
+
cli()
|