mirror of
https://github.com/pocketpy/pocketpy
synced 2025-10-20 19:40:18 +00:00
add requests
module
This commit is contained in:
parent
e5d5f09d83
commit
a04cdb4cad
1
.gitignore
vendored
1
.gitignore
vendored
@ -24,3 +24,4 @@ src/_generated.h
|
|||||||
profile.sh
|
profile.sh
|
||||||
test
|
test
|
||||||
tmp.rar
|
tmp.rar
|
||||||
|
src/httplib.h
|
||||||
|
@ -9,7 +9,7 @@ pipeline = [
|
|||||||
["common.h", "memory.h", "vector.h", "str.h", "tuplelist.h", "namedict.h", "error.h", "lexer.h"],
|
["common.h", "memory.h", "vector.h", "str.h", "tuplelist.h", "namedict.h", "error.h", "lexer.h"],
|
||||||
["obj.h", "codeobject.h", "frame.h"],
|
["obj.h", "codeobject.h", "frame.h"],
|
||||||
["gc.h", "vm.h", "ceval.h", "expr.h", "compiler.h", "repl.h"],
|
["gc.h", "vm.h", "ceval.h", "expr.h", "compiler.h", "repl.h"],
|
||||||
["iter.h", "cffi.h", "io.h", "_generated.h", "pocketpy.h"]
|
["iter.h", "cffi.h", "requests.h", "io.h", "_generated.h", "pocketpy.h"]
|
||||||
]
|
]
|
||||||
|
|
||||||
copied = set()
|
copied = set()
|
||||||
|
@ -74,7 +74,7 @@ class dict:
|
|||||||
def items(self):
|
def items(self):
|
||||||
for kv in self._a:
|
for kv in self._a:
|
||||||
if kv is not None:
|
if kv is not None:
|
||||||
yield kv
|
yield kv[0], kv[1]
|
||||||
|
|
||||||
def clear(self):
|
def clear(self):
|
||||||
self._a = [None] * self._capacity
|
self._a = [None] * self._capacity
|
||||||
|
40
python/requests.py
Normal file
40
python/requests.py
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
class Response:
|
||||||
|
def __init__(self, status_code, reason, content):
|
||||||
|
self.status_code = status_code
|
||||||
|
self.reason = reason
|
||||||
|
self.content = content
|
||||||
|
|
||||||
|
assert type(self.status_code) is int
|
||||||
|
assert type(self.reason) is str
|
||||||
|
assert type(self.content) is bytes
|
||||||
|
|
||||||
|
@property
|
||||||
|
def text(self):
|
||||||
|
return self.content.decode()
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
code = self.status_code
|
||||||
|
return f'<Response [{code}]>'
|
||||||
|
|
||||||
|
def _parse_h(headers):
|
||||||
|
if headers is None:
|
||||||
|
return []
|
||||||
|
if type(headers) is dict:
|
||||||
|
return list(headers.items())
|
||||||
|
raise ValueError('headers must be dict or None')
|
||||||
|
|
||||||
|
def get(url, headers=None):
|
||||||
|
headers = _parse_h(headers)
|
||||||
|
return _request('GET', url, headers, None)
|
||||||
|
|
||||||
|
def post(url, data: bytes, headers=None):
|
||||||
|
headers = _parse_h(headers)
|
||||||
|
return _request('POST', url, headers, data)
|
||||||
|
|
||||||
|
def put(url, data: bytes, headers=None):
|
||||||
|
headers = _parse_h(headers)
|
||||||
|
return _request('PUT', url, headers, data)
|
||||||
|
|
||||||
|
def delete(url, headers=None):
|
||||||
|
headers = _parse_h(headers)
|
||||||
|
return _request('DELETE', url, headers, None)
|
@ -6,6 +6,7 @@
|
|||||||
#include "repl.h"
|
#include "repl.h"
|
||||||
#include "iter.h"
|
#include "iter.h"
|
||||||
#include "cffi.h"
|
#include "cffi.h"
|
||||||
|
#include "requests.h"
|
||||||
#include "io.h"
|
#include "io.h"
|
||||||
#include "_generated.h"
|
#include "_generated.h"
|
||||||
|
|
||||||
@ -920,11 +921,6 @@ inline void VM::post_init(){
|
|||||||
add_module_gc(this);
|
add_module_gc(this);
|
||||||
add_module_random(this);
|
add_module_random(this);
|
||||||
|
|
||||||
if(enable_os){
|
|
||||||
add_module_io(this);
|
|
||||||
add_module_os(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
for(const char* name: {"this", "functools", "collections", "heapq", "bisect"}){
|
for(const char* name: {"this", "functools", "collections", "heapq", "bisect"}){
|
||||||
_lazy_modules[name] = kPythonLibs[name];
|
_lazy_modules[name] = kPythonLibs[name];
|
||||||
}
|
}
|
||||||
@ -969,6 +965,12 @@ inline void VM::post_init(){
|
|||||||
}
|
}
|
||||||
return VAR(MappingProxy(args[0]));
|
return VAR(MappingProxy(args[0]));
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
if(enable_os){
|
||||||
|
add_module_io(this);
|
||||||
|
add_module_os(this);
|
||||||
|
add_module_requests(this);
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
105
src/requests.h
Normal file
105
src/requests.h
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "common.h"
|
||||||
|
#include "obj.h"
|
||||||
|
#include "vm.h"
|
||||||
|
#include "_generated.h"
|
||||||
|
|
||||||
|
#if __has_include("httplib.h")
|
||||||
|
#include "httplib.h"
|
||||||
|
|
||||||
|
namespace pkpy {
|
||||||
|
|
||||||
|
inline void add_module_requests(VM* vm){
|
||||||
|
static StrName m_requests("requests");
|
||||||
|
static StrName m_Response("Response");
|
||||||
|
PyObject* mod = vm->new_module(m_requests);
|
||||||
|
CodeObject_ code = vm->compile(kPythonLibs["requests"], "requests.py", EXEC_MODE);
|
||||||
|
vm->_exec(code, mod);
|
||||||
|
|
||||||
|
vm->bind_func<4>(mod, "_request", [](VM* vm, ArgsView args){
|
||||||
|
Str method = CAST(Str&, args[0]);
|
||||||
|
Str url = CAST(Str&, args[1]);
|
||||||
|
PyObject* headers = args[2]; // a dict object
|
||||||
|
PyObject* body = args[3]; // a bytes object
|
||||||
|
|
||||||
|
if(url.index("http://") != 0){
|
||||||
|
vm->ValueError("url must start with http://");
|
||||||
|
}
|
||||||
|
|
||||||
|
for(char c: url){
|
||||||
|
switch(c){
|
||||||
|
case '.':
|
||||||
|
case '-':
|
||||||
|
case '_':
|
||||||
|
case '~':
|
||||||
|
case ':':
|
||||||
|
case '/':
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
if(!isalnum(c)){
|
||||||
|
vm->ValueError(fmt("invalid character in url: '", c, "'"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int slash = url.index("/", 7);
|
||||||
|
Str path = "/";
|
||||||
|
if(slash != -1){
|
||||||
|
path = url.substr(slash);
|
||||||
|
url = url.substr(0, slash);
|
||||||
|
if(path.empty()) path = "/";
|
||||||
|
}
|
||||||
|
|
||||||
|
httplib::Client client(url.str());
|
||||||
|
|
||||||
|
httplib::Headers h;
|
||||||
|
if(headers != vm->None){
|
||||||
|
List list = CAST(List&, headers);
|
||||||
|
for(auto& item : list){
|
||||||
|
Tuple t = CAST(Tuple&, item);
|
||||||
|
Str key = CAST(Str&, t[0]);
|
||||||
|
Str value = CAST(Str&, t[1]);
|
||||||
|
h.emplace(key.str(), value.str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto _to_resp = [=](const httplib::Result& res){
|
||||||
|
std::vector<char> buf(res->body.size());
|
||||||
|
for(int i=0; i<res->body.size(); i++) buf[i] = res->body[i];
|
||||||
|
return vm->call(
|
||||||
|
vm->_modules[m_requests]->attr(m_Response),
|
||||||
|
VAR(res->status),
|
||||||
|
VAR(res->reason),
|
||||||
|
VAR(Bytes(std::move(buf)))
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
if(method == "GET"){
|
||||||
|
httplib::Result res = client.Get(path.str(), h);
|
||||||
|
return _to_resp(res);
|
||||||
|
}else if(method == "POST"){
|
||||||
|
Bytes b = CAST(Bytes&, body);
|
||||||
|
httplib::Result res = client.Post(path.str(), h, b.data(), b.size(), "application/octet-stream");
|
||||||
|
return _to_resp(res);
|
||||||
|
}else if(method == "PUT"){
|
||||||
|
Bytes b = CAST(Bytes&, body);
|
||||||
|
httplib::Result res = client.Put(path.str(), h, b.data(), b.size(), "application/octet-stream");
|
||||||
|
return _to_resp(res);
|
||||||
|
}else if(method == "DELETE"){
|
||||||
|
httplib::Result res = client.Delete(path.str(), h);
|
||||||
|
return _to_resp(res);
|
||||||
|
}else{
|
||||||
|
vm->ValueError("invalid method");
|
||||||
|
}
|
||||||
|
UNREACHABLE();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace pkpy
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
inline void add_module_requests(VM* vm){ }
|
||||||
|
|
||||||
|
#endif
|
Loading…
x
Reference in New Issue
Block a user