Skip to content

Commit

Permalink
solve #133, 134
Browse files Browse the repository at this point in the history
  • Loading branch information
Ethosa committed Sep 8, 2023
1 parent 1855011 commit bed3612
Show file tree
Hide file tree
Showing 13 changed files with 132 additions and 59 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/language_bindings.yml
Original file line number Diff line number Diff line change
Expand Up @@ -59,9 +59,9 @@ jobs:
cd src
echo "Windows module"
echo "Win Module compiled with"
echo "nim c --app:lib --out:../bindings/python/happyx/happyx.pyd --tlsEmulation:off --passL:-static --t:-flto --l:-flto --opt:speed --threads:on -x:off -c:off -d:debug -d:httpx -d:export2py happyx"
echo "nim c --app:lib --out:../bindings/python/happyx/happyx.pyd --tlsEmulation:off --passL:-static --t:-flto --l:-flto --opt:speed --threads:on -d:ssl -d:debug -d:httpx -d:export2py happyx"
echo "Linux module"
nim c --app:lib --out:../bindings/python/happyx/happyx.so --t:-flto --l:-flto --opt:speed --threads:on -d:debug -x:off -c:off -w:off -d:httpx -d:export2py happyx
nim c --app:lib --out:../bindings/python/happyx/happyx.so -t:-flto -l:-flto --opt:speed --threads:on -d:ssl -d:debug -d:httpx -d:export2py happyx
shell: bash

- name: Build Package 🏗
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
### Macro-oriented asynchronous full-stack web-framework written in Nim with ♥

![Nim language](https://img.shields.io/badge/>=1.6.14-1b1e2b?style=for-the-badge&logo=nim&logoColor=f1fa8c&label=Nim&labelColor=2b2e3b)
![Python language](https://img.shields.io/badge/>=3.9.x-1b1e2b?style=for-the-badge&logo=python&logoColor=f1fa8c&label=Python&labelColor=2b2e3b)
![Python language](https://img.shields.io/badge/>=3.7.x-1b1e2b?style=for-the-badge&logo=python&logoColor=f1fa8c&label=Python&labelColor=2b2e3b)

[![wakatime](https://wakatime.com/badge/user/eaf11f95-5e2a-4b60-ae6a-38cd01ed317b/project/bbd13748-36e6-4383-ac40-9c4e72c060d1.svg?style=for-the-badge)](https://wakatime.com/badge/user/eaf11f95-5e2a-4b60-ae6a-38cd01ed317b/project/bbd13748-36e6-4383-ac40-9c4e72c060d1)
[![Testing](https://img.shields.io/github/actions/workflow/status/HapticX/HappyX/tests.yml?label=Testing&logo=github&style=for-the-badge)](https://github.com/HapticX/happyx/actions/workflows/tests.yml)
Expand Down
12 changes: 6 additions & 6 deletions bindings/python/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,23 +4,23 @@

### Python Bindings For HappyX Web Framework 🔥

![Python language](https://img.shields.io/badge/>=3.10.x-1b1e2b?style=for-the-badge&logo=python&logoColor=f1fa8c&label=Python&labelColor=2b2e3b)
![Python language](https://img.shields.io/badge/>=3.7.x-1b1e2b?style=for-the-badge&logo=python&logoColor=f1fa8c&label=Python&labelColor=2b2e3b)

</div>


## Get Started
## Getting Started

### Install
### Installing 📥

You can install HappyX via `pypi`:
```bash
pip install happyx
```

## Usage
## Usage 🔌

### Hello World
### Hello World 👋

```py
from happyx import new_server
Expand All @@ -38,7 +38,7 @@ app.start()
```


### JSON/HTML/File Responses
### JSON/HTML/File Responses 🛠

```py
from happyx import new_server, JsonResponse, HtmlResponse, FileResponse
Expand Down
Binary file modified bindings/python/happyx/happyx.pyd
Binary file not shown.
4 changes: 3 additions & 1 deletion bindings/python/setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
author_email='social.ethosa@gmail.com',
maintainer='HapticX',
maintainer_email='hapticx.company@gmail.com',
url='https://github.com/HapticX/happyx',
url='https://github.com/HapticX/happyx/tree/master/bindings/python',
version=happyx.happyx_version(),
packages=find_packages(),
include_package_data=True,
Expand All @@ -33,6 +33,8 @@
'Topic :: Software Development :: Libraries :: Application Frameworks',
'License :: OSI Approved :: MIT License',
'Operating System :: OS Independent',
'Programming Language :: Python :: 3.7',
'Programming Language :: Python :: 3.8',
'Programming Language :: Python :: 3.9',
'Programming Language :: Python :: 3.10',
'Programming Language :: Python :: 3.11',
Expand Down
2 changes: 1 addition & 1 deletion build_py.cmd
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
echo "Build Python Win Bindings"
cd src
nim c --app:lib --out:../bindings/python/happyx/happyx.pyd --tlsEmulation:off -t:-flto -l:-flto --opt:speed --passL:-static --threads:on -x:off -c:off -d:debug -d:httpx -d:export2py happyx
nim c --app:lib --out:../bindings/python/happyx/happyx.pyd --tlsEmulation:off -t:-flto -l:-flto --opt:speed -d:ssl --passL:-static --threads:on -d:debug -d:httpx -d:export2py happyx
cd ../
2 changes: 1 addition & 1 deletion examples/website/src/docs/introduction.nim
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ component Introduction:
tA(href = "https://nim-lang.org"):
tImg(alt = "Nim 👑", src = "https://img.shields.io/badge/>=1.6.14-1b1e2b?style=for-the-badge&logo=nim&logoColor=f1fa8c&label=Nim&labelColor=2b2e3b")
tA(href = "https://python.org"):
tImg(alt = "Python 🐍", src = "https://img.shields.io/badge/>=3.9.x-1b1e2b?style=for-the-badge&logo=python&logoColor=f1fa8c&label=Python&labelColor=2b2e3b")
tImg(alt = "Python 🐍", src = "https://img.shields.io/badge/>=3.7.x-1b1e2b?style=for-the-badge&logo=python&logoColor=f1fa8c&label=Python&labelColor=2b2e3b")
tTr:
tTd: "Wakatime Stats"
tTd:
Expand Down
2 changes: 1 addition & 1 deletion happyx.nimble
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

description = "Macro-oriented asynchronous web-framework written with ♥"
author = "HapticX"
version = "2.9.4"
version = "2.9.7"
license = "MIT"
srcDir = "src"
installExt = @["nim"]
Expand Down
8 changes: 7 additions & 1 deletion src/happyx/core/constants.nim
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,10 @@
## | `-d:compDebug` | enables debug logging for components | ❌ |
## | `-d:ssrDebug` | enables debug logging for SSR | ❌ |
## | `-d:spaDebug` | enables debug logging for SPA | ❌ |
## | `-d:reqModelDebug` | enables debug logging for request models | ❌ |
## | `-d:routingDebug` | enables debug logging for routing | ❌ |
## | `-d:componentDebugTarget` | after this component program will terminated | ✅ |
## | `-d:reqModelDebugTarget` | after this request model program will terminated | ✅ |
##
import strformat
when not defined(js) and defined(debug):
Expand All @@ -45,7 +48,10 @@ const
enableDebugSsrMacro* = defined(ssrDebug) or defined(happyxSsrDebug) or defined(hpxSsrDebug)
enableDebugSpaMacro* = defined(spaDebug) or defined(happyxSpaDebug) or defined(hpxSpaDebug)
enableUseCompDebugMacro* = defined(useCompDebug) or defined(happyxUseCompDebug) or defined(hpxUseCompDebug)
enableRequestModelDebugMacro* = defined(reqModelDebug) or defined(happyxReqModelDebug) or defined(hpxReqModelDebug)
enableRoutingDebugMacro* = defined(routingDebug) or defined(happyxRoutingDebug) or defined(hpxRoutingDebug)
componentDebugTarget* {.strdefine.} = ""
reqModelDebugTarget* {.strdefine.} = ""
# Language bindings
exportPython* = defined(export2py) or defined(happyxExport2py) or defined(hpxExport2py)
# Framework features
Expand All @@ -66,7 +72,7 @@ const
# Framework version
HpxMajor* = 2
HpxMinor* = 9
HpxPatch* = 5
HpxPatch* = 7
HpxVersion* = $HpxMajor & "." & $HpxMinor & "." & $HpxPatch


Expand Down
8 changes: 8 additions & 0 deletions src/happyx/routing/routing.nim
Original file line number Diff line number Diff line change
Expand Up @@ -421,6 +421,12 @@ proc exportRouteArgs*(urlPath, routePath, body: NimNode): NimNode =
newCall("echo", newCall("fmt", newStrLitNode("json parse error: {getCurrentExceptionMsg()}")))
else:
newEmptyNode(),
newCall(
"answerJson",
ident"req",
parseExpr"""{"response": "Incorrect JSON structure"}""",
ident"Http400"
),
newCall("jsonTo" & i.typeName, newCall("newJObject"))
)
))
Expand All @@ -446,6 +452,8 @@ proc exportRouteArgs*(urlPath, routePath, body: NimNode): NimNode =
)
)
)
when enableRoutingDebugMacro:
echo elifBranch.toStrLit
return elifBranch
return newEmptyNode()

Expand Down
115 changes: 70 additions & 45 deletions src/happyx/ssr/request_models.nim
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ import
strutils,
strformat,
# Happyx
../core/[exceptions]
../core/[exceptions, constants]


var modelFields* {.compileTime.} = newTable[string, StringTableRef]()
Expand All @@ -103,6 +103,15 @@ macro model*(modelName, body: untyped): untyped =
## - [x] Form-Data
## - [x] x-www-form-urlencoded
##
var
options: seq[string] = @[]
enableOptions = false
modelName = modelName
if modelName.kind == nnkBracketExpr:
enableOptions = true
for i in 1..<modelName.len:
options.add ($modelName[i].toStrLit).toLower()
modelName = modelName[0]
if modelName.kind != nnkIdent:
throwDefect(
HpxModelSyntaxDefect,
Expand All @@ -125,16 +134,16 @@ macro model*(modelName, body: untyped): untyped =
modelFields[$modelName] = newStringTable()

for i in body:
if i.kind == nnkCall and i.len == 2 :
if i.kind == nnkCall and i.len == 2 and i[1].kind == nnkStmtList and i[1].len == 1:
let argName = i[0]
# arg: type
if i[1][0].kind in [nnkIdent, nnkBracketExpr]:
if i[1][0].kind != nnkAsgn:
let argType = i[1][0]
params.add(newIdentDefs(
postfix(argName, "*"), argType
))
modelFields[$modelName][$argName.toStrLit] = $argType.toStrLit
if ($argType).toLower() != "formdataitem":
if ($argType.toStrLit).toLower() != "formdataitem":
# JSON raw data
asgnStmt.add(newNimNode(nnkIfStmt).add(
newNimNode(nnkElifBranch).add(
Expand All @@ -156,7 +165,7 @@ macro model*(modelName, body: untyped): untyped =
newCall("hasKey", ident"dataTable", newStrLitNode($argName)),
newAssignment(
newDotExpr(ident"result", argName),
case ($argType).toLower()
case ($argType.toStrLit).toLower()
of "int":
newCall("parseInt", newCall("[]", ident"dataTable", newStrLitNode($argName)))
of "float":
Expand Down Expand Up @@ -203,13 +212,13 @@ macro model*(modelName, body: untyped): untyped =
)
# form-data
asgnFormData.add(
if ($argType).toLower() != "formdataitem":
if ($argType.toStrLit).toLower() != "formdataitem":
newNimNode(nnkIfStmt).add(
newNimNode(nnkElifBranch).add(
newCall("hasKey", ident"dataTable", newStrLitNode($argName)),
newAssignment(
newDotExpr(ident"result", argName),
case ($argType).toLower()
case ($argType.toStrLit).toLower()
of "int":
newCall("parseInt", newCall("[]", ident"dataTable", newStrLitNode($argName)))
of "float":
Expand Down Expand Up @@ -244,15 +253,15 @@ macro model*(modelName, body: untyped): untyped =
)
continue
# arg: type = default
elif i[1][0].kind == nnkAsgn and i[1][0][0].kind == nnkIdent:
else:
let
argType = i[1][0][0]
argDefault = i[1][0][1]
params.add(newIdentDefs(
postfix(argName, "*"), argType
))
modelFields[$modelName][$argName.toStrLit] = $argType.toStrLit
if ($argType).toLower() != "formdataitem":
if ($argType.toStrLit).toLower() != "formdataitem":
# JSON raw data
asgnStmt.add(newNimNode(nnkIfStmt).add(
newNimNode(nnkElifBranch).add(
Expand All @@ -274,7 +283,7 @@ macro model*(modelName, body: untyped): untyped =
newCall("hasKey", ident"dataTable", newStrLitNode($argName)),
newAssignment(
newDotExpr(ident"result", argName),
case ($argType).toLower()
case ($argType.toStrLit).toLower()
of "int":
newCall("parseInt", newCall("[]", ident"dataTable", newStrLitNode($argName)))
of "float":
Expand Down Expand Up @@ -321,7 +330,7 @@ macro model*(modelName, body: untyped): untyped =
)
# form-data
asgnFormData.add(
if ($argType).toLower() != "formdataitem":
if ($argType.toStrLit).toLower() != "formdataitem":
newNimNode(nnkIfStmt).add(
newNimNode(nnkElifBranch).add(
newCall("hasKey", ident"dataTable", newStrLitNode($argName)),
Expand Down Expand Up @@ -369,42 +378,58 @@ macro model*(modelName, body: untyped): untyped =
)
)
),
newProc(
postfix(ident("jsonTo" & $modelName), "*"),
[modelName, newIdentDefs(ident"node", ident"JsonNode")],
newStmtList(
newAssignment(ident"result", newNimNode(nnkObjConstr).add(ident($modelName))),
if asgnStmt.len > 0: asgnStmt else: newStmtList()
if not enableOptions or (enableOptions and "json" in options):
newProc(
postfix(ident("jsonTo" & $modelName), "*"),
[modelName, newIdentDefs(ident"node", ident"JsonNode")],
newStmtList(
newAssignment(ident"result", newNimNode(nnkObjConstr).add(ident($modelName))),
if asgnStmt.len > 0: asgnStmt else: newStmtList()
)
)
),
newProc(
postfix(ident("xWwwUrlencodedTo" & $modelName), "*"),
[modelName, newIdentDefs(ident"formData", ident"string")],
newStmtList(
newAssignment(ident"result", newNimNode(nnkObjConstr).add(ident($modelName))),
newLetStmt(ident"dataTable", newCall("parseXWwwFormUrlencoded", ident"formData")),
if asgnStmt.len > 0: asgnUrlencoded else: newStmtList()
else:
newEmptyNode(),
if not enableOptions or (enableOptions and "xwwwformurlencoded" in options):
newProc(
postfix(ident("xWwwUrlencodedTo" & $modelName), "*"),
[modelName, newIdentDefs(ident"formData", ident"string")],
newStmtList(
newAssignment(ident"result", newNimNode(nnkObjConstr).add(ident($modelName))),
newLetStmt(ident"dataTable", newCall("parseXWwwFormUrlencoded", ident"formData")),
if asgnStmt.len > 0: asgnUrlencoded else: newStmtList()
)
)
),
newProc(
postfix(ident("xmlBodyTo" & $modelName), "*"),
[modelName, newIdentDefs(ident"data", ident"string")],
newStmtList(
newAssignment(ident"result", newNimNode(nnkObjConstr).add(ident($modelName))),
newLetStmt(ident"xmlBody", newCall("parseXmlBody", ident"data")),
if asgnStmt.len > 0: asgnXml else: newStmtList()
else:
newEmptyNode(),
if not enableOptions or (enableOptions and "xml" in options):
newProc(
postfix(ident("xmlBodyTo" & $modelName), "*"),
[modelName, newIdentDefs(ident"data", ident"string")],
newStmtList(
newAssignment(ident"result", newNimNode(nnkObjConstr).add(ident($modelName))),
newLetStmt(ident"xmlBody", newCall("parseXmlBody", ident"data")),
if asgnStmt.len > 0: asgnXml else: newStmtList()
)
)
),
newProc(
postfix(ident("formDataTo" & $modelName), "*"),
[modelName, newIdentDefs(ident"data", ident"string")],
newStmtList(
newAssignment(ident"result", newNimNode(nnkObjConstr).add(ident($modelName))),
newNimNode(nnkLetSection).add(newNimNode(nnkVarTuple).add(
ident"dataTable", ident"formDataItemsTable", newEmptyNode(),
newCall("parseFormData", ident"data")
)),
if asgnStmt.len > 0: asgnFormData else: newStmtList()
else:
newEmptyNode(),
if not enableOptions or (enableOptions and "formdata" in options):
newProc(
postfix(ident("formDataTo" & $modelName), "*"),
[modelName, newIdentDefs(ident"data", ident"string")],
newStmtList(
newAssignment(ident"result", newNimNode(nnkObjConstr).add(ident($modelName))),
newNimNode(nnkLetSection).add(newNimNode(nnkVarTuple).add(
ident"dataTable", ident"formDataItemsTable", newEmptyNode(),
newCall("parseFormData", ident"data")
)),
if asgnStmt.len > 0: asgnFormData else: newStmtList()
)
)
),
else:
newEmptyNode(),
)
when enableRequestModelDebugMacro:
echo result.toStrLit
if reqModelDebugTarget == $modelName:
quit(QuitSuccess)
2 changes: 2 additions & 0 deletions src/happyx/ssr/server.nim
Original file line number Diff line number Diff line change
Expand Up @@ -1541,6 +1541,8 @@ macro routes*(server: Server, body: untyped): untyped =
immutableVars.add(newIdentDefs(ident"inCookies", newEmptyNode(), cookiesInVar))
if stmtList.isIdentUsed(ident"reqMethod"):
immutableVars.add(newIdentDefs(ident"reqMethod", newEmptyNode(), reqMethod))
when enableDebugSsrMacro:
echo result.toStrLit


macro initServer*(body: untyped): untyped =
Expand Down
30 changes: 30 additions & 0 deletions tests/testc18.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import ../src/happyx
import times
import std/jsonutils


# json serialize DateTime
proc toJsonHook(dt: DateTime, opt = initToJsonOptions()): JsonNode =
newJString($dt)

# json deserialize DateTime
proc initFromJson(dt: var DateTime, jsonNode: JsonNode, jsonPath: var string) =
dt = parse(jsonNode.getStr, initTimeFormat("yyyy-MM-dd HH:mm:ss"))


model FighterCreate:
name: string
skill: string
test: seq[string]
createdAt: DateTime


serve "127.0.0.1", 5000:
post "/fighter[o:FighterCreate:json]":
echo "new fighter: ", o
return {"response": {
"name": o.name,
"skill": o.skill,
"test": o.test,
"createdAt": $o.createdAt
}}

0 comments on commit bed3612

Please sign in to comment.