functiontrace 0.5.1__tar.gz → 0.5.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {functiontrace-0.5.1 → functiontrace-0.5.2}/Cargo.toml +6 -6
- {functiontrace-0.5.1/functiontrace.egg-info → functiontrace-0.5.2}/PKG-INFO +3 -3
- {functiontrace-0.5.1 → functiontrace-0.5.2}/README.rst +1 -1
- {functiontrace-0.5.1 → functiontrace-0.5.2/functiontrace.egg-info}/PKG-INFO +3 -3
- {functiontrace-0.5.1 → functiontrace-0.5.2}/functiontrace.py +18 -4
- {functiontrace-0.5.1 → functiontrace-0.5.2}/pyproject.toml +8 -8
- {functiontrace-0.5.1 → functiontrace-0.5.2}/rust/lib.rs +30 -42
- {functiontrace-0.5.1 → functiontrace-0.5.2}/LICENSE.md +0 -0
- {functiontrace-0.5.1 → functiontrace-0.5.2}/MANIFEST.in +0 -0
- {functiontrace-0.5.1 → functiontrace-0.5.2}/build.rs +0 -0
- {functiontrace-0.5.1 → functiontrace-0.5.2}/functiontrace.egg-info/SOURCES.txt +0 -0
- {functiontrace-0.5.1 → functiontrace-0.5.2}/functiontrace.egg-info/dependency_links.txt +0 -0
- {functiontrace-0.5.1 → functiontrace-0.5.2}/functiontrace.egg-info/entry_points.txt +0 -0
- {functiontrace-0.5.1 → functiontrace-0.5.2}/functiontrace.egg-info/top_level.txt +0 -0
- {functiontrace-0.5.1 → functiontrace-0.5.2}/setup.cfg +0 -0
- {functiontrace-0.5.1 → functiontrace-0.5.2}/setup.py +0 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
[package]
|
|
2
2
|
name = "_functiontrace_rs"
|
|
3
3
|
version = "0.1.0"
|
|
4
|
-
edition = "
|
|
4
|
+
edition = "2024"
|
|
5
5
|
|
|
6
6
|
[dependencies]
|
|
7
7
|
color-eyre = { version = "0.6", default-features = false }
|
|
@@ -10,17 +10,17 @@ functiontrace-server = { version = "0.8.4", default-features = false, features =
|
|
|
10
10
|
jiff = { version = "0.2", default-features = false, features = ["std", "serde"] }
|
|
11
11
|
libc = "0.2"
|
|
12
12
|
owo-colors = "4.2"
|
|
13
|
-
pyo3 = { version = "0.
|
|
14
|
-
reqwest = { version = "0.
|
|
13
|
+
pyo3 = { version = "0.29", features = ["eyre"] }
|
|
14
|
+
reqwest = { version = "0.13", default-features = false, features = ["blocking", "json", "rustls"] }
|
|
15
15
|
rmp-serde = "1.3"
|
|
16
16
|
serde = "1"
|
|
17
|
-
toml = "
|
|
17
|
+
toml = "1.1"
|
|
18
18
|
tracing = { version = "0.1", features = ["log"] }
|
|
19
19
|
tracing-subscriber = { version = "0.3", default-features = false, features = ["ansi", "env-filter", "fmt", "std"] }
|
|
20
20
|
|
|
21
21
|
[build-dependencies]
|
|
22
|
-
toml = { version = "
|
|
23
|
-
pyo3-build-config = { version = "0.
|
|
22
|
+
toml = { version = "1.1", default-features = false, features = ["parse", "serde"] }
|
|
23
|
+
pyo3-build-config = { version = "0.29" }
|
|
24
24
|
|
|
25
25
|
[lib]
|
|
26
26
|
# See https://github.com/PyO3/pyo3 for details
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: functiontrace
|
|
3
|
-
Version: 0.5.
|
|
3
|
+
Version: 0.5.2
|
|
4
4
|
Summary: A profiling tool that traces your application's execution
|
|
5
5
|
Author: Alistair Dobke
|
|
6
6
|
Author-email: Matt Bryant <functiontrace@programsareproofs.com>
|
|
@@ -15,7 +15,7 @@ Classifier: Environment :: Console
|
|
|
15
15
|
Classifier: Programming Language :: Python :: 3
|
|
16
16
|
Classifier: Programming Language :: Python :: 3 :: Only
|
|
17
17
|
Classifier: Programming Language :: Python :: Implementation :: CPython
|
|
18
|
-
Requires-Python: >=3.
|
|
18
|
+
Requires-Python: >=3.10
|
|
19
19
|
Description-Content-Type: text/x-rst
|
|
20
20
|
License-File: LICENSE.md
|
|
21
21
|
Dynamic: license-file
|
|
@@ -28,7 +28,7 @@ Dependencies
|
|
|
28
28
|
------------
|
|
29
29
|
|
|
30
30
|
The FunctionTrace server must be installed for this package to work.
|
|
31
|
-
See installation instructions at https://functiontrace.com
|
|
31
|
+
See installation instructions at https://functiontrace.com/installation/.
|
|
32
32
|
|
|
33
33
|
Usage
|
|
34
34
|
-----
|
|
@@ -6,7 +6,7 @@ Dependencies
|
|
|
6
6
|
------------
|
|
7
7
|
|
|
8
8
|
The FunctionTrace server must be installed for this package to work.
|
|
9
|
-
See installation instructions at https://functiontrace.com
|
|
9
|
+
See installation instructions at https://functiontrace.com/installation/.
|
|
10
10
|
|
|
11
11
|
Usage
|
|
12
12
|
-----
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: functiontrace
|
|
3
|
-
Version: 0.5.
|
|
3
|
+
Version: 0.5.2
|
|
4
4
|
Summary: A profiling tool that traces your application's execution
|
|
5
5
|
Author: Alistair Dobke
|
|
6
6
|
Author-email: Matt Bryant <functiontrace@programsareproofs.com>
|
|
@@ -15,7 +15,7 @@ Classifier: Environment :: Console
|
|
|
15
15
|
Classifier: Programming Language :: Python :: 3
|
|
16
16
|
Classifier: Programming Language :: Python :: 3 :: Only
|
|
17
17
|
Classifier: Programming Language :: Python :: Implementation :: CPython
|
|
18
|
-
Requires-Python: >=3.
|
|
18
|
+
Requires-Python: >=3.10
|
|
19
19
|
Description-Content-Type: text/x-rst
|
|
20
20
|
License-File: LICENSE.md
|
|
21
21
|
Dynamic: license-file
|
|
@@ -28,7 +28,7 @@ Dependencies
|
|
|
28
28
|
------------
|
|
29
29
|
|
|
30
30
|
The FunctionTrace server must be installed for this package to work.
|
|
31
|
-
See installation instructions at https://functiontrace.com
|
|
31
|
+
See installation instructions at https://functiontrace.com/installation/.
|
|
32
32
|
|
|
33
33
|
Usage
|
|
34
34
|
-----
|
|
@@ -19,7 +19,12 @@ exec $(which {python}) -m functiontrace "$@"
|
|
|
19
19
|
|
|
20
20
|
|
|
21
21
|
def setup_dependencies():
|
|
22
|
-
|
|
22
|
+
if f"{tempfile.gettempdir()}/py-functiontrace" in os.environ["PATH"]:
|
|
23
|
+
# We've already set up dependencies. This only needs to happen once, since otherwise we'll
|
|
24
|
+
# just make a bunch of useless temp directories.
|
|
25
|
+
return
|
|
26
|
+
|
|
27
|
+
# Generate a temp directory to store our wrappers in. We'll temporarily
|
|
23
28
|
# add this directory to our path.
|
|
24
29
|
tempdir = tempfile.mkdtemp(prefix="py-functiontrace")
|
|
25
30
|
os.environ["PATH"] = tempdir + os.pathsep + os.environ["PATH"]
|
|
@@ -89,10 +94,19 @@ def main():
|
|
|
89
94
|
# below, which needs to operate in the context of our new module.
|
|
90
95
|
# NOTE: We use SourceFileLoader, rather than allowing importlib to infer
|
|
91
96
|
# the proper loader, in order to support files without a .py extension.
|
|
92
|
-
|
|
93
|
-
|
|
97
|
+
mod = util.module_from_spec(
|
|
98
|
+
util.spec_from_loader(
|
|
99
|
+
"__main__", machinery.SourceFileLoader("__main__", target_file)
|
|
100
|
+
)
|
|
94
101
|
)
|
|
95
|
-
|
|
102
|
+
|
|
103
|
+
# Clear __spec__ to match Python's standard `python foo.py` loading
|
|
104
|
+
mod.__spec__ = None
|
|
105
|
+
# Record the file we're using so `multiprocessing` can load it (in a non-forked context).
|
|
106
|
+
# Without this, `multiprocessing` in `forkserver` contexts is asked to load functions that
|
|
107
|
+
# it can't find.
|
|
108
|
+
mod.__file__ = target_file
|
|
109
|
+
|
|
96
110
|
sys.modules.update({"__main__": mod})
|
|
97
111
|
|
|
98
112
|
# Ensure we're setup to be able to run.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "functiontrace"
|
|
3
|
-
version = "0.5.
|
|
3
|
+
version = "0.5.2"
|
|
4
4
|
description = "A profiling tool that traces your application's execution"
|
|
5
5
|
authors = [
|
|
6
6
|
{ name = "Matt Bryant", email = "functiontrace@programsareproofs.com"},
|
|
@@ -9,13 +9,13 @@ authors = [
|
|
|
9
9
|
license = "LicenseRef-Prosperity-Public-License-3.0.0"
|
|
10
10
|
license-files = ["LICENSE.md"]
|
|
11
11
|
readme = "README.rst"
|
|
12
|
-
# NOTE: Actively tested on Python 3.
|
|
13
|
-
# versions due to C extension hacks.
|
|
14
|
-
# new Python versions to simply install very old versions of
|
|
15
|
-
# didn't have the `requires-python` annotation on them and
|
|
16
|
-
# work.
|
|
17
|
-
# with new Python releases.
|
|
18
|
-
requires-python = ">=3.
|
|
12
|
+
# NOTE: Actively tested on Python 3.10 - 3.14 and may plausibly break on
|
|
13
|
+
# greater versions due to C extension hacks. However, setting a maximum version
|
|
14
|
+
# causes new Python versions to simply install very old versions of
|
|
15
|
+
# Functiontrace that didn't have the `requires-python` annotation on them and
|
|
16
|
+
# are also unlikely to work. Best to only set the minimum and let bug reports
|
|
17
|
+
# notify us of issues with new Python releases.
|
|
18
|
+
requires-python = ">=3.10"
|
|
19
19
|
keywords = [
|
|
20
20
|
"profiler",
|
|
21
21
|
"debugger"
|
|
@@ -7,7 +7,7 @@ mod _functiontrace_rs {
|
|
|
7
7
|
use serde::{Deserialize, Serialize};
|
|
8
8
|
use std::borrow::Cow;
|
|
9
9
|
use std::cell::Cell;
|
|
10
|
-
use std::ffi::{CStr, OsString
|
|
10
|
+
use std::ffi::{CStr, OsString};
|
|
11
11
|
use std::io::Write;
|
|
12
12
|
use std::os::unix::net::UnixStream;
|
|
13
13
|
use std::sync::atomic::{AtomicBool, Ordering};
|
|
@@ -148,7 +148,7 @@ mod _functiontrace_rs {
|
|
|
148
148
|
let state = THREAD_STATE.get();
|
|
149
149
|
|
|
150
150
|
if state.is_null() {
|
|
151
|
-
// We shouldn't be asked to reset
|
|
151
|
+
// We shouldn't be asked to reset a thread that hasn't yet been registered.
|
|
152
152
|
return None;
|
|
153
153
|
}
|
|
154
154
|
|
|
@@ -206,7 +206,7 @@ mod _functiontrace_rs {
|
|
|
206
206
|
.wrap_err("Failed to convert MIN_PYTHON_VERSION to int")?,
|
|
207
207
|
)
|
|
208
208
|
.wrap_err("Failed to expose _min_python_version")?;
|
|
209
|
-
m.add("_max_python_version",
|
|
209
|
+
m.add("_max_python_version", 14)
|
|
210
210
|
.wrap_err("Failed to expose _max_python_version")?;
|
|
211
211
|
|
|
212
212
|
color_eyre::install().wrap_err("Failed to install color_eyre")?;
|
|
@@ -259,20 +259,20 @@ mod _functiontrace_rs {
|
|
|
259
259
|
// Parse args out of `sys.argv`, since it excludes the Python executable and shows the
|
|
260
260
|
// script's path first. This is much more complicated than using `std::env::args`, but
|
|
261
261
|
// is more practical.
|
|
262
|
-
Python::
|
|
262
|
+
Python::attach(|py| -> Result<String> {
|
|
263
263
|
let argv = py
|
|
264
264
|
.import("sys")
|
|
265
265
|
.and_then(|sys| sys.getattr("argv"))
|
|
266
266
|
.wrap_err("Failed to access sys.argv")?;
|
|
267
267
|
|
|
268
268
|
let args = argv
|
|
269
|
-
.
|
|
269
|
+
.cast::<pyo3::types::PyList>()
|
|
270
270
|
.map_err(|e| eyre!("Failed to read sys.argv as list: {}", e))?;
|
|
271
271
|
|
|
272
272
|
let mut full_args = args.iter().fold(String::new(), |s, arg| {
|
|
273
273
|
// Fetch the next arg as a string if possible.
|
|
274
274
|
let arg = arg
|
|
275
|
-
.
|
|
275
|
+
.cast::<pyo3::types::PyString>()
|
|
276
276
|
.map_err(|e| eyre!("Failed to read sys.argv[x] as string: {}", e))
|
|
277
277
|
.and_then(|arg| {
|
|
278
278
|
arg.to_str()
|
|
@@ -327,7 +327,7 @@ mod _functiontrace_rs {
|
|
|
327
327
|
Err(err) if err.kind() == std::io::ErrorKind::NotFound => {
|
|
328
328
|
eprintln!("Unable to find `functiontrace-server` in the current $PATH.");
|
|
329
329
|
eprintln!(
|
|
330
|
-
"See https://functiontrace.com
|
|
330
|
+
"See https://functiontrace.com/installation/ for installation instructions."
|
|
331
331
|
);
|
|
332
332
|
|
|
333
333
|
// Exit here rather than returning an error, since that'll emit a confusing
|
|
@@ -340,12 +340,12 @@ mod _functiontrace_rs {
|
|
|
340
340
|
format!("/tmp/functiontrace-server.sock.{}", server.id()).into()
|
|
341
341
|
};
|
|
342
342
|
|
|
343
|
-
Python::
|
|
343
|
+
Python::attach(|_| {
|
|
344
344
|
// Register an env var so subprocesses know how to connect to our
|
|
345
345
|
// profile.
|
|
346
346
|
unsafe {
|
|
347
347
|
// SAFETY: `set_var` can only be done while no one else is reading or writing to the
|
|
348
|
-
// environment.
|
|
348
|
+
// environment. We're holding the GIL, so this _should_ be true, but there's no real
|
|
349
349
|
// way to enforce this.
|
|
350
350
|
//
|
|
351
351
|
// This doesn't seem to blow up in C even when we don't have the GIL, so
|
|
@@ -362,7 +362,7 @@ mod _functiontrace_rs {
|
|
|
362
362
|
// Send an initialization message to the server with some information about us. This will
|
|
363
363
|
// only be sent once, and all future threads/subprocesses will be associated underneath us.
|
|
364
364
|
let init = {
|
|
365
|
-
let python_version = Python::
|
|
365
|
+
let python_version = Python::attach(|py| {
|
|
366
366
|
let version = py.version_info();
|
|
367
367
|
|
|
368
368
|
format!(
|
|
@@ -371,14 +371,14 @@ mod _functiontrace_rs {
|
|
|
371
371
|
)
|
|
372
372
|
});
|
|
373
373
|
|
|
374
|
-
let platform = Python::
|
|
374
|
+
let platform = Python::attach(|py| -> Result<String> {
|
|
375
375
|
let platform = py
|
|
376
376
|
.import("sys")
|
|
377
377
|
.and_then(|sys| sys.getattr("platform"))
|
|
378
378
|
.wrap_err("Failed to access sys.platform")?;
|
|
379
379
|
|
|
380
380
|
Ok(platform
|
|
381
|
-
.
|
|
381
|
+
.cast::<pyo3::types::PyString>()
|
|
382
382
|
.map_err(|e| eyre!("Failed to read sys.platform as string: {}", e))?
|
|
383
383
|
.to_str()
|
|
384
384
|
.wrap_err("Failed to read Rust string out of PyString")?
|
|
@@ -433,7 +433,7 @@ mod _functiontrace_rs {
|
|
|
433
433
|
//
|
|
434
434
|
// NOTE: We specifically do this rather than `Py_AtExit` since we want to run before all
|
|
435
435
|
// the Python teardown occurs.
|
|
436
|
-
Python::
|
|
436
|
+
Python::attach(|py| -> Result<()> {
|
|
437
437
|
py.import("atexit")
|
|
438
438
|
.and_then(|atexit| atexit.getattr("register"))
|
|
439
439
|
.wrap_err("Failed to access atexit.register")?
|
|
@@ -460,12 +460,13 @@ mod _functiontrace_rs {
|
|
|
460
460
|
|
|
461
461
|
// Register our tracing functions with Python - both the normal one and the multithreaded
|
|
462
462
|
// setup trampoline.
|
|
463
|
+
// TODO: PyEval_SetProfileAllThreads in >=3.12 should simplify this.
|
|
463
464
|
unsafe {
|
|
464
465
|
// SAFETY: both parameters are of the proper type.
|
|
465
466
|
pyo3::ffi::PyEval_SetProfile(Some(functiontrace), std::ptr::null_mut())
|
|
466
467
|
};
|
|
467
468
|
|
|
468
|
-
Python::
|
|
469
|
+
Python::attach(|py| -> Result<()> {
|
|
469
470
|
py.import("threading")
|
|
470
471
|
.and_then(|threading| threading.getattr("setprofile"))
|
|
471
472
|
.wrap_err("Failed to access threading.setprofile")?
|
|
@@ -561,23 +562,6 @@ mod _functiontrace_rs {
|
|
|
561
562
|
Ok(())
|
|
562
563
|
}
|
|
563
564
|
|
|
564
|
-
#[unsafe(no_mangle)]
|
|
565
|
-
extern "C" fn c_thread_teardown(state: *mut c_void) {
|
|
566
|
-
if state.is_null() {
|
|
567
|
-
// We never fully initialized this thread, so skip teardown.
|
|
568
|
-
return;
|
|
569
|
-
}
|
|
570
|
-
|
|
571
|
-
let writer = unsafe {
|
|
572
|
-
// SAFETY: writer is a valid pointer to an initialized `ThreadState`.
|
|
573
|
-
&mut (state as *mut ThreadState)
|
|
574
|
-
.as_mut()
|
|
575
|
-
.expect("state is non-null")
|
|
576
|
-
};
|
|
577
|
-
|
|
578
|
-
thread_teardown(writer).expect("Failed to tear down FunctionTrace thread")
|
|
579
|
-
}
|
|
580
|
-
|
|
581
565
|
/// Tear down the given thread by flushing any outstanding messages.
|
|
582
566
|
///
|
|
583
567
|
/// This is called when the thread has shut down, including in multithread/process situations.
|
|
@@ -636,7 +620,11 @@ mod _functiontrace_rs {
|
|
|
636
620
|
/// thread state, before replacing itself with the normal Fprofile_FunctionTrace handler.
|
|
637
621
|
#[pyfunction]
|
|
638
622
|
#[pyo3(name = "_thread_trace_trampoline")]
|
|
639
|
-
fn thread_trace_trampoline(
|
|
623
|
+
fn thread_trace_trampoline(
|
|
624
|
+
_frame: Py<PyAny>,
|
|
625
|
+
_event: Py<PyAny>,
|
|
626
|
+
_arg: Py<PyAny>,
|
|
627
|
+
) -> Result<()> {
|
|
640
628
|
// Register the current thread for tracing
|
|
641
629
|
thread_register().wrap_err("Failed to register new FunctionTrace thread")?;
|
|
642
630
|
|
|
@@ -787,7 +775,7 @@ mod _functiontrace_rs {
|
|
|
787
775
|
pyo3::ffi::PyFrame_GetCode(frame) as *mut pyo3::ffi::PyObject
|
|
788
776
|
};
|
|
789
777
|
|
|
790
|
-
Python::
|
|
778
|
+
Python::attach(|py| {
|
|
791
779
|
let code = unsafe {
|
|
792
780
|
// SAFETY: code is guaranteed to be a valid PyCodeObject since it
|
|
793
781
|
// came from `PyFrame_GetCode`.
|
|
@@ -799,7 +787,7 @@ mod _functiontrace_rs {
|
|
|
799
787
|
let unicode_converter = |pyobj: PyResult<Bound<'_, PyAny>>| {
|
|
800
788
|
pyobj
|
|
801
789
|
.map(|obj| {
|
|
802
|
-
if let Ok(filename) = obj.
|
|
790
|
+
if let Ok(filename) = obj.cast::<pyo3::types::PyString>() {
|
|
803
791
|
Cow::from(filename.to_string_lossy().into_owned())
|
|
804
792
|
} else {
|
|
805
793
|
Cow::Borrowed("<UNKNOWN>")
|
|
@@ -856,13 +844,13 @@ mod _functiontrace_rs {
|
|
|
856
844
|
if !func.m_module.is_null() {
|
|
857
845
|
// NOTE: _Typically_ `m_module` is a PyModule, but there are no requirements on
|
|
858
846
|
// what type it needs to be! In practice, we only see PyModules and PyStrings.
|
|
859
|
-
Python::
|
|
847
|
+
Python::attach(|py| {
|
|
860
848
|
let m_module = unsafe {
|
|
861
849
|
// SAFETY: m_module is a non-NULL pointer to a valid Python object.
|
|
862
850
|
Bound::from_borrowed_ptr(py, func.m_module)
|
|
863
851
|
};
|
|
864
852
|
|
|
865
|
-
if let Ok(module) = m_module.
|
|
853
|
+
if let Ok(module) = m_module.cast::<pyo3::types::PyModule>() {
|
|
866
854
|
// This is a PyModule, so get its name if possible.
|
|
867
855
|
let name = module.name();
|
|
868
856
|
let module_name = if let Ok(name) = &name {
|
|
@@ -879,7 +867,7 @@ mod _functiontrace_rs {
|
|
|
879
867
|
.serialize(&mut rmp_serde::encode::Serializer::new(&mut writer))
|
|
880
868
|
} else {
|
|
881
869
|
let module_name =
|
|
882
|
-
if let Ok(module) = m_module.
|
|
870
|
+
if let Ok(module) = m_module.cast::<pyo3::types::PyString>() {
|
|
883
871
|
module.to_cow().unwrap_or(Cow::Borrowed("<invalid string>"))
|
|
884
872
|
} else {
|
|
885
873
|
if let Ok(typ) = m_module.get_type().qualname().map(|x| x.to_string()) {
|
|
@@ -1125,7 +1113,7 @@ mod _functiontrace_rs {
|
|
|
1125
1113
|
if let Some(result) = parser(&input) {
|
|
1126
1114
|
return Ok(result);
|
|
1127
1115
|
}
|
|
1128
|
-
Python::
|
|
1116
|
+
Python::attach(|py| {
|
|
1129
1117
|
// We need to check with the Python interpreter during loops, otherwise we
|
|
1130
1118
|
// might not receive ctrl-c events.
|
|
1131
1119
|
py.check_signals()
|
|
@@ -1507,7 +1495,7 @@ mod hooks {
|
|
|
1507
1495
|
/// function, then attaching enough information about the original function to call it.
|
|
1508
1496
|
pub fn install() -> Result<()> {
|
|
1509
1497
|
for hook in HOOKS.iter() {
|
|
1510
|
-
Python::
|
|
1498
|
+
Python::attach(|py| -> Result<()> {
|
|
1511
1499
|
let (module_name, method_name) = hook
|
|
1512
1500
|
.target
|
|
1513
1501
|
.rsplit_once(".")
|
|
@@ -1649,14 +1637,14 @@ mod hooks {
|
|
|
1649
1637
|
.get()
|
|
1650
1638
|
.expect("Wrapper functions can't be called until hooked");
|
|
1651
1639
|
|
|
1652
|
-
let proxied = Python::
|
|
1640
|
+
let proxied = Python::attach(|py| -> Result<()> {
|
|
1653
1641
|
if let Some(mut writer) = crate::_functiontrace_rs::thread_state() {
|
|
1654
1642
|
let args = unsafe {
|
|
1655
1643
|
// SAFETY: `args` represents a valid argument tuple
|
|
1656
1644
|
Bound::from_borrowed_ptr(py, args)
|
|
1657
1645
|
};
|
|
1658
1646
|
let args = args
|
|
1659
|
-
.
|
|
1647
|
+
.cast()
|
|
1660
1648
|
.map_err(Into::<PyErr>::into)
|
|
1661
1649
|
.wrap_err("Python args must be a tuple")?;
|
|
1662
1650
|
|
|
@@ -1733,7 +1721,7 @@ mod hooks {
|
|
|
1733
1721
|
// `import` takes rather complicated arguments, but in practice we only care about
|
|
1734
1722
|
// the first argument (name)
|
|
1735
1723
|
let module = if let Ok(arg) = args.get_item(0) {
|
|
1736
|
-
arg.
|
|
1724
|
+
arg.cast()
|
|
1737
1725
|
.map_err(Into::into)
|
|
1738
1726
|
.and_then(|module| module.to_str())
|
|
1739
1727
|
.map(|module| Cow::Owned(module.to_string()))
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|