pyedenapi: return a Future of Stats for commitdata

Summary:
Exercises the PyFuture type from cpython-async.

`hg dbsh`:

    In [1]: api._rustclient.commitdata('fbsource', list(repo.nodes('master^^::master')))
    Out[1]:
    ([...], <future at 0x7f7b65d05060>)

    In [2]: f=Out[1][-1]

    In [3]: f.wait()
    Out[3]: <bindings.edenapi.stats at 0x7f7b665e8228>

    In [4]: f.wait()
    ValueError: future was awaited

    In [5]: str(Out[3])
    Out[5]: '2.42 kB downloaded in 172 ms over 1 request (0.01 MB/s; latency: 171 ms)'

Reviewed By: kulshrax

Differential Revision: D23799643

fbshipit-source-id: d4fcef7dca58bc4902bb0809adc065493bb94bd3
This commit is contained in:
Jun Wu 2020-09-21 13:26:13 -07:00 committed by Facebook GitHub Bot
parent 7f1c05dd74
commit cd7f831c6c
5 changed files with 43 additions and 5 deletions

View File

@ -6,6 +6,7 @@ edition = "2018"
[dependencies]
anyhow = "1.0"
bytes = "0.5"
cpython-async = { path = "../../../../lib/cpython-async", default-features = false }
cpython-ext = { path = "../../../../lib/cpython-ext", default-features = false }
cpython = { version = "0.5", default-features = false }
edenapi = { path = "../../../../lib/edenapi" }
@ -16,3 +17,8 @@ pyrevisionstore = { path = "../pyrevisionstore" }
revisionstore = { path = "../../../../lib/revisionstore" }
tokio = { version = "=0.2.13", features = ["full"] }
types = { path = "../../../../lib/types" }
[features]
default = []
python2 = ["cpython/python27-sys", "cpython-ext/python2", "cpython-async/python2"]
python3 = ["cpython/python3-sys", "cpython-ext/python3", "cpython-async/python3"]

View File

@ -9,6 +9,7 @@ use std::sync::Arc;
use cpython::*;
use cpython_async::PyFuture;
use cpython_ext::{ExtractInner, ExtractInnerRef, PyPathBuf, ResultPyErrExt};
use edenapi::{Builder, EdenApi};
use pyconfigparser::config;
@ -101,7 +102,7 @@ py_class!(pub class client |py| {
repo: String,
nodes: Vec<PyBytes>,
progress: Option<PyObject> = None
) -> PyResult<(Vec<(PyBytes, PyBytes)>, stats)> {
) -> PyResult<(Vec<(PyBytes, PyBytes)>, PyFuture)> {
self.inner(py).clone().commit_revlog_data_py(py, repo, nodes, progress)
}

View File

@ -14,6 +14,7 @@ use cpython::*;
mod client;
mod pyext;
mod pytypes;
mod stats;
mod util;

View File

@ -12,11 +12,13 @@ use cpython::*;
use futures::prelude::*;
use tokio::runtime::Runtime;
use cpython_async::PyFuture;
use cpython_ext::{PyPathBuf, ResultPyErrExt};
use edenapi::{EdenApi, EdenApiBlocking, EdenApiError, Fetch, Stats};
use edenapi_types::{CommitRevlogData, FileEntry, HistoryEntry, TreeEntry};
use revisionstore::{HgIdMutableDeltaStore, HgIdMutableHistoryStore};
use crate::pytypes::PyStats;
use crate::stats::stats;
use crate::util::{
as_deltastore, as_historystore, meta_to_dict, to_hgids, to_keys, to_path, wrap_callback,
@ -147,11 +149,11 @@ pub trait EdenApiPyExt: EdenApi {
repo: String,
nodes: Vec<PyBytes>,
progress: Option<PyObject>,
) -> PyResult<(Vec<(PyBytes, PyBytes)>, stats)> {
) -> PyResult<(Vec<(PyBytes, PyBytes)>, PyFuture)> {
let nodes = to_hgids(py, nodes);
let progress = progress.map(wrap_callback);
let (commits, stats): (Vec<CommitRevlogData>, Stats) = py
let (commits, stats): (Vec<CommitRevlogData>, _) = py
.allow_threads(|| {
let mut rt = Runtime::new().context("Failed to initialize Tokio runtime")?;
rt.block_on(async move {
@ -160,7 +162,7 @@ pub trait EdenApiPyExt: EdenApi {
while let Some(entry) = response.entries.try_next().await? {
commits.push(entry);
}
let stats = response.stats.await?;
let stats = response.stats;
Ok::<_, EdenApiError>((commits, stats))
})
})
@ -175,7 +177,7 @@ pub trait EdenApiPyExt: EdenApi {
)
})
.collect();
let stats_py = stats::new(py, stats)?;
let stats_py = PyFuture::new(py, stats.map_ok(PyStats))?;
Ok((commits_py, stats_py))
}
}

View File

@ -0,0 +1,28 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This software may be used and distributed according to the terms of the
* GNU General Public License version 2.
*/
//! Python types that implements `ToPyObject`.
use cpython::*;
use edenapi::Stats;
use crate::stats::stats;
/// Converts `Stats` to Python `stats`.
pub struct PyStats(pub Stats);
impl ToPyObject for PyStats {
type ObjectType = stats;
fn to_py_object(&self, py: Python) -> Self::ObjectType {
stats::new(py, self.0.clone()).unwrap()
}
fn into_py_object(self, py: Python) -> Self::ObjectType {
stats::new(py, self.0).unwrap()
}
}