Skip to content

Commit

Permalink
improve python bindings
Browse files Browse the repository at this point in the history
  • Loading branch information
Ethosa committed Dec 4, 2023
1 parent eada184 commit 22f880c
Show file tree
Hide file tree
Showing 5 changed files with 59 additions and 42 deletions.
Binary file modified bindings/python/happyx/happyx.pyd
Binary file not shown.
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 = "3.6.2"
version = "3.6.3"
license = "MIT"
srcDir = "src"
installExt = @["nim"]
Expand Down
60 changes: 42 additions & 18 deletions src/happyx/bindings/python_types.nim
Original file line number Diff line number Diff line change
Expand Up @@ -45,15 +45,18 @@ type
data*: string
statusCode*: int
headers*: PyObject
HandlerParam* = object
name*, paramType*: string
Route* = ref object of PyNimObjectExperimental
path*: string
purePath*: string
httpMethod*: seq[string]
pattern*: Regex2
handler*: PyObject
locals*: PyObject
HandlerParam* = object
name*, paramType*: string
posArgs*: seq[string]
params*: JsonNode
handlerParams*: seq[HandlerParam]
RequestModelData* = object
name*: string
pyClass*: PyObject
Expand Down Expand Up @@ -104,10 +107,46 @@ proc toHttpHeaders*(headers: PyObject): HttpHeaders =
headersObj


proc newHandlerParams*(args: openarray[string], annotations: JsonNode): seq[HandlerParam] =
result = @[]
for arg in args:
if annotations.hasKey(arg):
result.add(HandlerParam(name: arg, paramType: annotations[arg].str))
else:
result.add(HandlerParam(name: arg, paramType: "any"))


proc newAnnotations*(data: PyObject): JsonNode =
result = newJObject()
for key in data.keys():
result[$key] = newJString($data[$key].getAttr("__name__"))


proc initRoute*(path, purePath: string, httpMethod: seq[string], pattern: Regex2, handler: PyObject): Route =
result = Route(path: path, purePath: purePath, httpMethod: httpMethod, pattern: pattern, handler: handler)
result = Route(
path: path,
purePath: purePath,
httpMethod: httpMethod,
pattern: pattern,
handler: handler,
posArgs: @[]
)
result.locals = pyDict()
result.locals["func"] = handler
# fetch __defaults__
if not handler.isNil:
var defaults: JsonNode
var argcount = handler.getAttr("__code__").getAttr("co_argcount").to(int)
var varnames = handler.getAttr("__code__").getAttr("co_varnames").to(seq[string])
pyValueToNim(privateRawPyObj(handler.getAttr("__defaults__")), defaults)
# fetch pos only arguments
for i in 0..<(argcount - defaults.len):
result.posArgs.add(varnames[i])
# fetch handler params with __defaults__ and __annotations__
result.handlerParams = newHandlerParams(
result.posArgs,
newAnnotations(result.handler.getAttr("__annotations__"))
)

proc hasHttpMethod*(self: Route, httpMethod: string | seq[string] | openarray[string]): bool =
when httpMethod is string:
Expand All @@ -122,21 +161,6 @@ proc initHttpRequest*(path, httpMethod: string, headers: HttpHeaders, body: stri
HttpRequest(path: path, httpMethod: httpMethod, headers: headers.toPPyObject(), body: body)


proc newAnnotations*(data: PyObject): JsonNode =
result = newJObject()
for key in data.keys():
result[$key] = newJString($data[$key].getAttr("__name__"))


proc newHandlerParams*(args: openarray[string], annotations: JsonNode): seq[HandlerParam] =
result = @[]
for arg in args:
if annotations.hasKey(arg):
result.add(HandlerParam(name: arg, paramType: annotations[arg].str))
else:
result.add(HandlerParam(name: arg, paramType: "any"))


proc contains*(params: seq[HandlerParam], key: string): bool =
for param in params:
if param.name == key:
Expand Down
2 changes: 1 addition & 1 deletion src/happyx/core/constants.nim
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ const
# Framework version
HpxMajor* = 3
HpxMinor* = 6
HpxPatch* = 2
HpxPatch* = 3
HpxVersion* = $HpxMajor & "." & $HpxMinor & "." & $HpxPatch


Expand Down
37 changes: 15 additions & 22 deletions src/happyx/ssr/handlers.nim
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,10 @@ elif exportPython:
import nimpy

template handlePythonRequest*(self: server.Server, req: Request, urlPath: string) =
var reqResponded = false
var
reqResponded = false
pyNone: PyObject
newPyNone().pyValueToNim(pyNone)
for route in self.routes:
if (
(@["NOTFOUND"] == route.httpMethod and not(reqResponded)) or
Expand Down Expand Up @@ -250,30 +253,20 @@ elif exportPython:
routeData = handleRoute(route.path)
# Declare Python Object (for function params)
pyFuncParams: PyObject
pyNone: PyObject
# Declare JsonNode (for length of keyword arguments)
keywordArguments: JsonNode
# Unpack route path params
let founded_regexp_matches = urlPath.findAll(route.pattern)
var
# handle callback data
variables = newSeq[string]()
argcount = route.handler.getAttr("__code__").getAttr("co_argcount")
varnames = route.handler.getAttr("__code__").getAttr("co_varnames")
pDefaults = route.handler.getAttr("__defaults__")
# Create Python Object
pyValueToNim(privateRawPyObj(pDefaults), keywordArguments)
let annotations = newAnnotations(route.handler.getAttr("__annotations__"))
# Extract function arguments from Python
for i in 0..<(argcount.to(int) - keywordArguments.len):
variables.add(varnames[i].to(string))
variables = route.posArgs
# Unpack route path params
let
# Match function parameters with annotations (or without)
handlerParams = newHandlerParams(variables, annotations)
founded_regexp_matches = urlPath.findAll(route.pattern)
# Load path params into function parameters
funcParams = getRouteParams(routeData, founded_regexp_matches, urlPath, handlerParams, req.body.get())
none = newPyNone()
none.pyValueToNim(pyNone)
handlerParams = route.handlerParams
funcParams = getRouteParams(
routeData,
founded_regexp_matches,
urlPath,
handlerParams,
req.body.get()
)
# Add queries to function parameters
for param in handlerParams:
if not (pyNone != callMethod(funcParams, "get", param.name)) and not (param.paramType in @["HttpRequest", "WebSocket"]):
Expand Down

0 comments on commit 22f880c

Please sign in to comment.