Skip to content

Commit

Permalink
files: take file paths instead of contents; post files as streams
Browse files Browse the repository at this point in the history
  • Loading branch information
deedy5 committed Jan 7, 2025
1 parent 5a7928d commit 0f44b47
Show file tree
Hide file tree
Showing 4 changed files with 26 additions and 16 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,15 @@ rquest = { version = "1.3", features = [
"zstd",
"deflate",
"multipart",
"stream",
"impersonate_str",
"impersonate_settings",
] }
encoding_rs = { version = "0.8" }
foldhash = "0.1"
indexmap = { version = "2", features = ["serde"] }
tokio = { version = "1", features = ["full"] }
tokio-util = { version = "0.7", features = ["codec"] } # for multipart
html2text = "0.13"
bytes = "1"
pythonize = "0.23"
Expand Down
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ def post(
content: Optional[bytes] = None,
data: Optional[Dict[str, str]] = None,
json: Any = None,
files: Optional[Dict[str, bytes]] = None,
files: Optional[Dict[str, str]] = None,
auth: Optional[Tuple[str, Optional[str]]] = None,
auth_bearer: Optional[str] = None,
timeout: Optional[float] = 30,
Expand All @@ -122,7 +122,7 @@ def post(
content (Optional[bytes]): The content to send in the request body as bytes. Default is None.
data (Optional[Dict[str, str]]): The form data to send in the request body. Default is None.
json (Any): A JSON serializable object to send in the request body. Default is None.
files (Optional[Dict[str, bytes]]): A map of file fields to file contents to be sent as multipart/form-data. Default is None.
files (Optional[Dict[str, str]]): A map of file fields to file paths to be sent as multipart/form-data. Default is None.
auth (Optional[Tuple[str, Optional[str]]]): A tuple containing the username and an optional password
for basic authentication. Default is None.
auth_bearer (Optional[str]): A string representing the bearer token for bearer token authentication. Default is None.
Expand Down Expand Up @@ -190,7 +190,7 @@ resp = client.post(url="https://httpbin.org/anything", json=json)
print(r.text)

# POST Multipart-Encoded Files
files = {'file1': open('file1.txt'), 'file2': open('file2.txt')}
files = {'file1': '/home/root/file1.txt', 'file2': 'home/root/file2.txt'}
r = client.post("https://httpbin.org/post", files=files)
print(r.text)

Expand Down
33 changes: 20 additions & 13 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,14 @@ use rquest::{
multipart,
redirect::Policy,
tls::Impersonate,
Method,
Body, Method,
};
use serde_json::Value;
use tokio::runtime::{self, Runtime};
use tokio::{
fs::File,
runtime::{self, Runtime},
};
use tokio_util::codec::{BytesCodec, FramedRead};

mod response;
use response::Response;
Expand Down Expand Up @@ -289,7 +293,7 @@ impl Client {
/// * `content` - The content to send in the request body as bytes. Default is None.
/// * `data` - The form data to send in the request body. Default is None.
/// * `json` - A JSON serializable object to send in the request body. Default is None.
/// * `files` - A map of file fields to file contents as bytes to be sent as multipart/form-data. Default is None.
/// * `files` - A map of file fields to file paths to be sent as multipart/form-data. Default is None.
/// * `auth` - A tuple containing the username and an optional password for basic authentication. Default is None.
/// * `auth_bearer` - A string representing the bearer token for bearer token authentication. Default is None.
/// * `timeout` - The timeout for the request in seconds. Default is 30.
Expand All @@ -314,7 +318,7 @@ impl Client {
content: Option<Vec<u8>>,
data: Option<&Bound<'_, PyAny>>,
json: Option<&Bound<'_, PyAny>>,
files: Option<IndexMap<String, Vec<u8>>>,
files: Option<IndexMap<String, String>>,
auth: Option<(String, Option<String>)>,
auth_bearer: Option<String>,
timeout: Option<f64>,
Expand Down Expand Up @@ -366,8 +370,11 @@ impl Client {
// Files
if let Some(files) = files {
let mut form = multipart::Form::new();
for (file_name, file_buf) in files {
let part = multipart::Part::stream(file_buf).file_name(file_name.clone());
for (file_name, file_path) in files {
let file = File::open(file_path).await?;
let stream = FramedRead::new(file, BytesCodec::new());
let file_body = Body::wrap_stream(stream);
let part = multipart::Part::stream(file_body).file_name(file_name.clone());
form = form.part(file_name, part);
}
request_builder = request_builder.multipart(form);
Expand Down Expand Up @@ -555,7 +562,7 @@ impl Client {
content: Option<Vec<u8>>,
data: Option<&Bound<'_, PyAny>>,
json: Option<&Bound<'_, PyAny>>,
files: Option<IndexMap<String, Vec<u8>>>,
files: Option<IndexMap<String, String>>,
auth: Option<(String, Option<String>)>,
auth_bearer: Option<String>,
timeout: Option<f64>,
Expand Down Expand Up @@ -589,7 +596,7 @@ impl Client {
content: Option<Vec<u8>>,
data: Option<&Bound<'_, PyAny>>,
json: Option<&Bound<'_, PyAny>>,
files: Option<IndexMap<String, Vec<u8>>>,
files: Option<IndexMap<String, String>>,
auth: Option<(String, Option<String>)>,
auth_bearer: Option<String>,
timeout: Option<f64>,
Expand Down Expand Up @@ -623,7 +630,7 @@ impl Client {
content: Option<Vec<u8>>,
data: Option<&Bound<'_, PyAny>>,
json: Option<&Bound<'_, PyAny>>,
files: Option<IndexMap<String, Vec<u8>>>,
files: Option<IndexMap<String, String>>,
auth: Option<(String, Option<String>)>,
auth_bearer: Option<String>,
timeout: Option<f64>,
Expand Down Expand Up @@ -661,7 +668,7 @@ fn request(
content: Option<Vec<u8>>,
data: Option<&Bound<'_, PyAny>>,
json: Option<&Bound<'_, PyAny>>,
files: Option<IndexMap<String, Vec<u8>>>,
files: Option<IndexMap<String, String>>,
auth: Option<(String, Option<String>)>,
auth_bearer: Option<String>,
timeout: Option<f64>,
Expand Down Expand Up @@ -901,7 +908,7 @@ fn post(
content: Option<Vec<u8>>,
data: Option<&Bound<'_, PyAny>>,
json: Option<&Bound<'_, PyAny>>,
files: Option<IndexMap<String, Vec<u8>>>,
files: Option<IndexMap<String, String>>,
auth: Option<(String, Option<String>)>,
auth_bearer: Option<String>,
timeout: Option<f64>,
Expand Down Expand Up @@ -956,7 +963,7 @@ fn put(
content: Option<Vec<u8>>,
data: Option<&Bound<'_, PyAny>>,
json: Option<&Bound<'_, PyAny>>,
files: Option<IndexMap<String, Vec<u8>>>,
files: Option<IndexMap<String, String>>,
auth: Option<(String, Option<String>)>,
auth_bearer: Option<String>,
timeout: Option<f64>,
Expand Down Expand Up @@ -1011,7 +1018,7 @@ fn patch(
content: Option<Vec<u8>>,
data: Option<&Bound<'_, PyAny>>,
json: Option<&Bound<'_, PyAny>>,
files: Option<IndexMap<String, Vec<u8>>>,
files: Option<IndexMap<String, String>>,
auth: Option<(String, Option<String>)>,
auth_bearer: Option<String>,
timeout: Option<f64>,
Expand Down

0 comments on commit 0f44b47

Please sign in to comment.