python_packaging/
interpreter.rs

1// Copyright 2022 Gregory Szorc.
2//
3// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
4// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
5// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
6// option. This file may not be copied, modified, or distributed
7// except according to those terms.
8
9/*! Functionality related to running Python interpreters. */
10
11use {
12    crate::resource::BytecodeOptimizationLevel,
13    std::{ffi::OsString, os::raw::c_ulong, path::PathBuf, str::FromStr},
14};
15
16#[cfg(feature = "serialization")]
17use serde::{Deserialize, Serialize};
18
19/// Defines the profile to use to configure a Python interpreter.
20///
21/// This effectively provides a template for seeding the initial values of
22/// `PyPreConfig` and `PyConfig` C structs.
23///
24/// Serialization type: `string`.
25#[derive(Clone, Copy, Debug, PartialEq, Eq)]
26#[cfg_attr(feature = "serialization", derive(Deserialize, Serialize))]
27#[cfg_attr(feature = "serialization", serde(try_from = "String", into = "String"))]
28pub enum PythonInterpreterProfile {
29    /// Python is isolated from the system.
30    ///
31    /// See <https://docs.python.org/3/c-api/init_config.html#isolated-configuration>.
32    ///
33    /// Serialized value: `isolated`
34    Isolated,
35
36    /// Python interpreter behaves like `python`.
37    ///
38    /// See <https://docs.python.org/3/c-api/init_config.html#python-configuration>.
39    ///
40    /// Serialized value: `python`
41    Python,
42}
43
44impl Default for PythonInterpreterProfile {
45    fn default() -> Self {
46        PythonInterpreterProfile::Isolated
47    }
48}
49
50impl ToString for PythonInterpreterProfile {
51    fn to_string(&self) -> String {
52        match self {
53            Self::Isolated => "isolated",
54            Self::Python => "python",
55        }
56        .to_string()
57    }
58}
59
60impl From<PythonInterpreterProfile> for String {
61    fn from(v: PythonInterpreterProfile) -> Self {
62        v.to_string()
63    }
64}
65
66impl TryFrom<&str> for PythonInterpreterProfile {
67    type Error = String;
68
69    fn try_from(value: &str) -> Result<Self, Self::Error> {
70        match value {
71            "isolated" => Ok(Self::Isolated),
72            "python" => Ok(Self::Python),
73            _ => Err(format!(
74                "{} is not a valid profile; use 'isolated' or 'python'",
75                value
76            )),
77        }
78    }
79}
80
81impl TryFrom<String> for PythonInterpreterProfile {
82    type Error = String;
83
84    fn try_from(value: String) -> Result<Self, Self::Error> {
85        Self::try_from(value.as_str())
86    }
87}
88
89/// Defines `terminfo` database resolution semantics.
90///
91/// Python links against libraries like `readline`, `libedit`, and `ncurses`
92/// which need to utilize a `terminfo` database (a set of files defining
93/// terminals and their capabilities) in order to work properly.
94///
95/// The absolute path to the terminfo database is typically compiled into these
96/// libraries at build time. If the compiled path on the building machine doesn't
97/// match the path on the runtime machine, these libraries cannot find the terminfo
98/// database and terminal interactions won't work correctly because these libraries
99/// don't know how to resolve terminal features. This can result in quirks like
100/// the backspace key not working in prompts.
101///
102/// The `pyembed` Rust crate is able to point libraries at a terminfo database
103/// at runtime, overriding the compiled-in default path. This enum is used
104/// to control that behavior.
105///
106/// Serialization type: `string`.
107#[derive(Clone, Debug, PartialEq, Eq)]
108#[cfg_attr(feature = "serialization", derive(Deserialize, Serialize))]
109#[cfg_attr(feature = "serialization", serde(try_from = "String", into = "String"))]
110pub enum TerminfoResolution {
111    /// Resolve `terminfo` database using appropriate behavior for current OS.
112    ///
113    /// We will look for the terminfo database in paths that are common for the
114    /// current OS / distribution. The terminfo database is present in most systems
115    /// (except the most barebones containers or sandboxes) and this method is
116    /// usually successfully in locating the terminfo database.
117    ///
118    /// Serialized value: `dynamic`
119    Dynamic,
120
121    /// Do not attempt to resolve the `terminfo` database. Basically a no-op.
122    ///
123    /// This is what should be used for applications that don't interact with the
124    /// terminal. Using this option will prevent some I/O syscalls that would
125    /// be incurred by `dynamic`.
126    ///
127    /// Serialized value: `none`
128    None,
129
130    /// Use a specified string as the `TERMINFO_DIRS` value.
131    ///
132    /// Serialized value: `static:<path>`
133    ///
134    /// e.g. `static:/usr/share/terminfo`.
135    Static(String),
136}
137
138impl ToString for TerminfoResolution {
139    fn to_string(&self) -> String {
140        match self {
141            Self::Dynamic => "dynamic".to_string(),
142            Self::None => "none".to_string(),
143            Self::Static(value) => format!("static:{}", value),
144        }
145    }
146}
147
148impl From<TerminfoResolution> for String {
149    fn from(t: TerminfoResolution) -> Self {
150        t.to_string()
151    }
152}
153
154impl TryFrom<&str> for TerminfoResolution {
155    type Error = String;
156
157    fn try_from(value: &str) -> Result<Self, Self::Error> {
158        if value == "dynamic" {
159            Ok(Self::Dynamic)
160        } else if value == "none" {
161            Ok(Self::None)
162        } else if let Some(suffix) = value.strip_prefix("static:") {
163            Ok(Self::Static(suffix.to_string()))
164        } else {
165            Err(format!(
166                "{} is not a valid terminfo resolution value",
167                value
168            ))
169        }
170    }
171}
172
173impl TryFrom<String> for TerminfoResolution {
174    type Error = String;
175
176    fn try_from(value: String) -> Result<Self, Self::Error> {
177        Self::try_from(value.as_str())
178    }
179}
180
181/// Defines a backend for a memory allocator.
182///
183/// This says which memory allocator API / library to configure the Python
184/// interpreter to use.
185///
186/// Not all allocators are available in all program builds.
187///
188/// Serialization type: `string`
189#[derive(Clone, Copy, Debug, PartialEq, Eq)]
190#[cfg_attr(feature = "serialization", derive(Deserialize, Serialize))]
191#[cfg_attr(feature = "serialization", serde(try_from = "String", into = "String"))]
192pub enum MemoryAllocatorBackend {
193    /// The default allocator as configured by Python.
194    ///
195    /// This likely utilizes the system default allocator, normally the
196    /// `malloc()`, `free()`, etc functions from the libc implementation being
197    /// linked against.
198    ///
199    /// Serialized value: `default`
200    Default,
201
202    /// Use the jemalloc allocator.
203    ///
204    /// Requires the binary to be built with jemalloc support.
205    ///
206    /// Never available on Windows.
207    ///
208    /// Serialized value: `jemalloc`
209    Jemalloc,
210
211    /// Use the mimalloc allocator (<https://github.com/microsoft/mimalloc>).
212    ///
213    /// Requires the binary to be built with mimalloc support.
214    ///
215    /// Serialized value: `mimalloc`
216    Mimalloc,
217
218    /// Use the snmalloc allocator (<https://github.com/microsoft/snmalloc>).
219    ///
220    /// Not always available.
221    ///
222    /// Serialized value: `snmalloc`
223    Snmalloc,
224
225    /// Use Rust's global allocator.
226    ///
227    /// The Rust allocator is less efficient than other allocators because of
228    /// overhead tracking allocations. For optimal performance, use the default
229    /// allocator. Or if Rust is using a custom global allocator, use the enum
230    /// variant corresponding to that allocator.
231    ///
232    /// Serialized value: `rust`
233    Rust,
234}
235
236impl Default for MemoryAllocatorBackend {
237    fn default() -> Self {
238        if cfg!(windows) {
239            Self::Default
240        } else {
241            Self::Jemalloc
242        }
243    }
244}
245
246impl ToString for MemoryAllocatorBackend {
247    fn to_string(&self) -> String {
248        match self {
249            Self::Default => "default",
250            Self::Jemalloc => "jemalloc",
251            Self::Mimalloc => "mimalloc",
252            Self::Snmalloc => "snmalloc",
253            Self::Rust => "rust",
254        }
255        .to_string()
256    }
257}
258
259impl From<MemoryAllocatorBackend> for String {
260    fn from(v: MemoryAllocatorBackend) -> Self {
261        v.to_string()
262    }
263}
264
265impl TryFrom<&str> for MemoryAllocatorBackend {
266    type Error = String;
267
268    fn try_from(value: &str) -> Result<Self, Self::Error> {
269        match value {
270            "default" => Ok(Self::Default),
271            "jemalloc" => Ok(Self::Jemalloc),
272            "mimalloc" => Ok(Self::Mimalloc),
273            "snmalloc" => Ok(Self::Snmalloc),
274            "rust" => Ok(Self::Rust),
275            _ => Err(format!("{} is not a valid memory allocator backend", value)),
276        }
277    }
278}
279
280impl TryFrom<String> for MemoryAllocatorBackend {
281    type Error = String;
282
283    fn try_from(value: String) -> Result<Self, Self::Error> {
284        Self::try_from(value.as_str())
285    }
286}
287
288/// Holds values for `coerce_c_locale`.
289///
290/// See <https://docs.python.org/3/c-api/init_config.html#c.PyPreConfig.coerce_c_locale>.
291///
292/// Serialization type: `string`
293#[derive(Clone, Copy, Debug, PartialEq, Eq)]
294#[cfg_attr(feature = "serialization", derive(Deserialize, Serialize))]
295#[cfg_attr(feature = "serialization", serde(try_from = "String", into = "String"))]
296pub enum CoerceCLocale {
297    /// Read the LC_CTYPE locale to decide if it should be coerced.
298    ///
299    /// Serialized value: `LC_CTYPE`
300    #[allow(clippy::upper_case_acronyms)]
301    LCCtype = 1,
302
303    /// Coerce the C locale.
304    ///
305    /// Serialized value: `C`
306    C = 2,
307}
308
309impl ToString for CoerceCLocale {
310    fn to_string(&self) -> String {
311        match self {
312            Self::LCCtype => "LC_CTYPE",
313            Self::C => "C",
314        }
315        .to_string()
316    }
317}
318
319impl From<CoerceCLocale> for String {
320    fn from(v: CoerceCLocale) -> Self {
321        v.to_string()
322    }
323}
324
325impl TryFrom<&str> for CoerceCLocale {
326    type Error = String;
327
328    fn try_from(value: &str) -> Result<Self, Self::Error> {
329        match value {
330            "LC_CTYPE" => Ok(Self::LCCtype),
331            "C" => Ok(Self::C),
332            _ => Err(format!("{} is not a valid C locale coercion value", value)),
333        }
334    }
335}
336
337impl TryFrom<String> for CoerceCLocale {
338    type Error = String;
339
340    fn try_from(value: String) -> Result<Self, Self::Error> {
341        Self::try_from(value.as_str())
342    }
343}
344
345/// Defines what to do when comparing `bytes` or `bytesarray` with `str` or comparing `bytes` with `int`.
346///
347/// See <https://docs.python.org/3/c-api/init_config.html#c.PyConfig.bytes_warning>.
348///
349/// Serialization type: `string`
350#[derive(Clone, Copy, Debug, PartialEq, Eq)]
351#[cfg_attr(feature = "serialization", derive(Deserialize, Serialize))]
352#[cfg_attr(feature = "serialization", serde(try_from = "String", into = "String"))]
353pub enum BytesWarning {
354    /// Do nothing.
355    ///
356    /// Serialization value: `none`
357    None = 0,
358
359    /// Issue a warning.
360    ///
361    /// Serialization value: `warn`
362    Warn = 1,
363
364    /// Raise a `BytesWarning`.
365    ///
366    /// Serialization value: `raise`
367    Raise = 2,
368}
369
370impl ToString for BytesWarning {
371    fn to_string(&self) -> String {
372        match self {
373            Self::None => "none",
374            Self::Warn => "warn",
375            Self::Raise => "raise",
376        }
377        .to_string()
378    }
379}
380
381impl From<BytesWarning> for String {
382    fn from(v: BytesWarning) -> Self {
383        v.to_string()
384    }
385}
386
387impl TryFrom<&str> for BytesWarning {
388    type Error = String;
389
390    fn try_from(value: &str) -> Result<Self, Self::Error> {
391        match value {
392            "none" => Ok(Self::None),
393            "warn" => Ok(Self::Warn),
394            "raise" => Ok(Self::Raise),
395            _ => Err(format!("{} is not a valid bytes warning value", value)),
396        }
397    }
398}
399
400impl TryFrom<String> for BytesWarning {
401    type Error = String;
402
403    fn try_from(value: String) -> Result<Self, Self::Error> {
404        Self::try_from(value.as_str())
405    }
406}
407
408impl From<i32> for BytesWarning {
409    fn from(value: i32) -> BytesWarning {
410        match value {
411            0 => Self::None,
412            1 => Self::Warn,
413            _ => Self::Raise,
414        }
415    }
416}
417
418/// Control the validation behavior of hash-based .pyc files.
419///
420/// See <https://docs.python.org/3/c-api/init_config.html#c.PyConfig.check_hash_pycs_mode>.
421///
422/// Serialization type: `string`
423#[derive(Clone, Copy, Debug, PartialEq, Eq)]
424#[cfg_attr(feature = "serialization", derive(Deserialize, Serialize))]
425#[cfg_attr(feature = "serialization", serde(try_from = "String", into = "String"))]
426pub enum CheckHashPycsMode {
427    /// Hash the source file for invalidation regardless of value of the `check_source` flag.
428    ///
429    /// Serialized value: `always`
430    Always,
431
432    /// Assume that hash-based pycs always are valid.
433    ///
434    /// Serialized value: `never`
435    Never,
436
437    /// The `check_source` flag in hash-based pycs determines invalidation.
438    ///
439    /// Serialized value: `default`
440    Default,
441}
442
443impl ToString for CheckHashPycsMode {
444    fn to_string(&self) -> String {
445        match self {
446            Self::Always => "always",
447            Self::Never => "never",
448            Self::Default => "default",
449        }
450        .to_string()
451    }
452}
453
454impl From<CheckHashPycsMode> for String {
455    fn from(v: CheckHashPycsMode) -> Self {
456        v.to_string()
457    }
458}
459
460impl TryFrom<&str> for CheckHashPycsMode {
461    type Error = String;
462
463    fn try_from(value: &str) -> Result<Self, Self::Error> {
464        match value {
465            "always" => Ok(Self::Always),
466            "never" => Ok(Self::Never),
467            "default" => Ok(Self::Default),
468            _ => Err(format!(
469                "{} is not a valid check hash pycs mode value",
470                value
471            )),
472        }
473    }
474}
475
476impl TryFrom<String> for CheckHashPycsMode {
477    type Error = String;
478
479    fn try_from(value: String) -> Result<Self, Self::Error> {
480        Self::try_from(value.as_str())
481    }
482}
483
484/// Name of the Python memory allocators.
485///
486/// See <https://docs.python.org/3/c-api/init_config.html#c.PyPreConfig.allocator>.
487///
488/// Serialization type: `string`
489#[derive(Clone, Copy, Debug, PartialEq, Eq)]
490#[cfg_attr(feature = "serialization", derive(Deserialize, Serialize))]
491#[cfg_attr(feature = "serialization", serde(try_from = "String", into = "String"))]
492pub enum Allocator {
493    /// Don’t change memory allocators (use defaults).
494    ///
495    /// Serialized value: `not-set`
496    NotSet = 0,
497
498    /// Default memory allocators.
499    ///
500    /// Serialized value: `default`
501    Default = 1,
502
503    /// Default memory allocators with debug hooks.
504    ///
505    /// Serialized value: `debug`
506    Debug = 2,
507
508    /// Use `malloc()` from the C library.
509    ///
510    /// Serialized value: `malloc`
511    Malloc = 3,
512
513    /// Force usage of `malloc()` with debug hooks.
514    ///
515    /// Serialized value: `malloc-debug`
516    MallocDebug = 4,
517
518    /// Python `pymalloc` allocator.
519    ///
520    /// Serialized value: `py-malloc`
521    PyMalloc = 5,
522
523    /// Python `pymalloc` allocator with debug hooks.
524    ///
525    /// Serialized value: `py-malloc-debug`
526    PyMallocDebug = 6,
527}
528
529impl ToString for Allocator {
530    fn to_string(&self) -> String {
531        match self {
532            Self::NotSet => "not-set",
533            Self::Default => "default",
534            Self::Debug => "debug",
535            Self::Malloc => "malloc",
536            Self::MallocDebug => "malloc-debug",
537            Self::PyMalloc => "py-malloc",
538            Self::PyMallocDebug => "py-malloc-debug",
539        }
540        .to_string()
541    }
542}
543
544impl From<Allocator> for String {
545    fn from(v: Allocator) -> Self {
546        v.to_string()
547    }
548}
549
550impl TryFrom<&str> for Allocator {
551    type Error = String;
552
553    fn try_from(value: &str) -> Result<Self, Self::Error> {
554        match value {
555            "not-set" => Ok(Self::NotSet),
556            "default" => Ok(Self::Default),
557            "debug" => Ok(Self::Debug),
558            "malloc" => Ok(Self::Malloc),
559            "malloc-debug" => Ok(Self::MallocDebug),
560            "py-malloc" => Ok(Self::PyMalloc),
561            "py-malloc-debug" => Ok(Self::PyMallocDebug),
562            _ => Err(format!("{} is not a valid allocator value", value)),
563        }
564    }
565}
566
567impl TryFrom<String> for Allocator {
568    type Error = String;
569
570    fn try_from(value: String) -> Result<Self, Self::Error> {
571        Self::try_from(value.as_str())
572    }
573}
574
575/// Defines how to call `multiprocessing.set_start_method()` when `multiprocessing` is imported.
576///
577/// When set to a value that is not `none`, when `oxidized_importer.OxidizedFinder` services
578/// an import of the `multiprocessing` module, it will automatically call
579/// `multiprocessing.set_start_method()` to configure how worker processes are created.
580///
581/// If the `multiprocessing` module is not imported by `oxidized_importer.OxidizedFinder`,
582/// this setting has no effect.
583///
584/// Serialization type: `string`
585#[derive(Clone, Debug, PartialEq, Eq)]
586#[cfg_attr(feature = "serialization", derive(Deserialize, Serialize))]
587#[cfg_attr(feature = "serialization", serde(try_from = "String", into = "String"))]
588pub enum MultiprocessingStartMethod {
589    /// Do not call `multiprocessing.set_start_method()`.
590    ///
591    /// This mode is what Python programs do by default.
592    ///
593    /// Serialized value: `none`
594    None,
595
596    /// Call with value `fork`.
597    ///
598    /// Serialized value: `fork`
599    Fork,
600
601    /// Call with value `forkserver`
602    ///
603    /// Serialized value: `forkserver`
604    ForkServer,
605
606    /// Call with value `spawn`
607    ///
608    /// Serialized value: `spawn`
609    Spawn,
610
611    /// Call with a valid appropriate for the given environment.
612    ///
613    /// This likely maps to `spawn` on Windows and `fork` on non-Windows.
614    ///
615    /// Serialized value: `auto`
616    Auto,
617}
618
619impl ToString for MultiprocessingStartMethod {
620    fn to_string(&self) -> String {
621        match self {
622            Self::None => "none",
623            Self::Fork => "fork",
624            Self::ForkServer => "forkserver",
625            Self::Spawn => "spawn",
626            Self::Auto => "auto",
627        }
628        .to_string()
629    }
630}
631
632impl From<MultiprocessingStartMethod> for String {
633    fn from(v: MultiprocessingStartMethod) -> Self {
634        v.to_string()
635    }
636}
637
638impl FromStr for MultiprocessingStartMethod {
639    type Err = String;
640
641    fn from_str(s: &str) -> Result<Self, Self::Err> {
642        match s {
643            "none" => Ok(Self::None),
644            "fork" => Ok(Self::Fork),
645            "forkserver" => Ok(Self::ForkServer),
646            "spawn" => Ok(Self::Spawn),
647            "auto" => Ok(Self::Auto),
648            _ => Err(format!("{} is not a valid multiprocessing start method", s)),
649        }
650    }
651}
652
653impl TryFrom<&str> for MultiprocessingStartMethod {
654    type Error = String;
655
656    fn try_from(v: &str) -> Result<Self, Self::Error> {
657        Self::from_str(v)
658    }
659}
660
661impl TryFrom<String> for MultiprocessingStartMethod {
662    type Error = String;
663
664    fn try_from(value: String) -> Result<Self, Self::Error> {
665        Self::try_from(value.as_str())
666    }
667}
668
669/// Holds configuration of a Python interpreter.
670///
671/// This struct holds fields that are exposed by `PyPreConfig` and
672/// `PyConfig` in the CPython API.
673///
674/// Other than the profile (which is used to initialize instances of
675/// `PyPreConfig` and `PyConfig`), all fields are optional. Only fields
676/// with `Some(T)` will be updated from the defaults.
677#[derive(Clone, Debug, Default, PartialEq, Eq)]
678#[cfg_attr(feature = "serialization", derive(Deserialize, Serialize))]
679#[cfg_attr(feature = "serialization", serde(default))]
680pub struct PythonInterpreterConfig {
681    /// Profile to use to initialize pre-config and config state of interpreter.
682    pub profile: PythonInterpreterProfile,
683
684    // The following fields are from PyPreConfig or are shared with PyConfig.
685    /// Name of the memory allocator.
686    ///
687    /// See <https://docs.python.org/3/c-api/init_config.html#c.PyPreConfig.allocator>.
688    pub allocator: Option<Allocator>,
689
690    /// Whether to set the LC_CTYPE locale to the user preferred locale.
691    ///
692    /// See <https://docs.python.org/3/c-api/init_config.html#c.PyPreConfig.configure_locale>.
693    pub configure_locale: Option<bool>,
694
695    /// How to coerce the locale settings.
696    ///
697    /// See <https://docs.python.org/3/c-api/init_config.html#c.PyPreConfig.coerce_c_locale>.
698    pub coerce_c_locale: Option<CoerceCLocale>,
699
700    /// Whether to emit a warning if the C locale is coerced.
701    ///
702    /// See <https://docs.python.org/3/c-api/init_config.html#c.PyPreConfig.coerce_c_locale_warn>.
703    pub coerce_c_locale_warn: Option<bool>,
704
705    /// Whether to enable Python development mode.
706    ///
707    /// See <https://docs.python.org/3/c-api/init_config.html#c.PyConfig.dev_mode>.
708    pub development_mode: Option<bool>,
709
710    /// Isolated mode.
711    ///
712    /// See <https://docs.python.org/3/c-api/init_config.html#c.PyPreConfig.isolated>.
713    pub isolated: Option<bool>,
714
715    /// Whether to use legacy filesystem encodings on Windows.
716    ///
717    /// See <https://docs.python.org/3/c-api/init_config.html#c.PyPreConfig.legacy_windows_fs_encoding>.
718    pub legacy_windows_fs_encoding: Option<bool>,
719
720    /// Whether argv should be parsed the way `python` parses them.
721    ///
722    /// See <https://docs.python.org/3/c-api/init_config.html#c.PyPreConfig.parse_argv>.
723    pub parse_argv: Option<bool>,
724
725    /// Whether environment variables are read to control the interpreter configuration.
726    ///
727    /// See <https://docs.python.org/3/c-api/init_config.html#c.PyConfig.use_environment>.
728    pub use_environment: Option<bool>,
729
730    /// Controls Python UTF-8 mode.
731    ///
732    /// See <https://docs.python.org/3/c-api/init_config.html#c.PyPreConfig.utf8_mode>.
733    pub utf8_mode: Option<bool>,
734    // The following fields are from PyConfig.
735    /// Command line arguments.
736    ///
737    /// These will become `sys.argv`.
738    ///
739    /// See <https://docs.python.org/3/c-api/init_config.html#c.PyConfig.argv>.
740    pub argv: Option<Vec<OsString>>,
741
742    /// Controls `sys.base_exec_prefix`.
743    ///
744    /// See <https://docs.python.org/3/c-api/init_config.html#c.PyConfig.base_exec_prefix>.
745    pub base_exec_prefix: Option<PathBuf>,
746
747    /// Controls `sys._base_executable`.
748    ///
749    /// See <https://docs.python.org/3/c-api/init_config.html#c.PyConfig.base_executable>.
750    pub base_executable: Option<PathBuf>,
751
752    /// Controls `sys.base_prefix`.
753    ///
754    /// See <https://docs.python.org/3/c-api/init_config.html#c.PyConfig.base_prefix>.
755    pub base_prefix: Option<PathBuf>,
756
757    /// Controls buffering on `stdout` and `stderr`.
758    ///
759    /// See <https://docs.python.org/3/c-api/init_config.html#c.PyConfig.buffered_stdio>.
760    pub buffered_stdio: Option<bool>,
761
762    /// Controls warnings/errors for some bytes type coercions.
763    ///
764    /// See <https://docs.python.org/3/c-api/init_config.html#c.PyConfig.bytes_warning>.
765    pub bytes_warning: Option<BytesWarning>,
766
767    /// Validation mode for `.pyc` files.
768    ///
769    /// See <https://docs.python.org/3/c-api/init_config.html#c.PyConfig.check_hash_pycs_mode>.
770    pub check_hash_pycs_mode: Option<CheckHashPycsMode>,
771
772    /// Controls binary mode and buffering on C standard streams.
773    ///
774    /// See <https://docs.python.org/3/c-api/init_config.html#c.PyConfig.configure_c_stdio>.
775    pub configure_c_stdio: Option<bool>,
776
777    /// Dump Python references.
778    ///
779    /// See <https://docs.python.org/3/c-api/init_config.html#c.PyConfig.dump_refs>.
780    pub dump_refs: Option<bool>,
781
782    /// Controls `sys.exec_prefix`.
783    ///
784    /// See <https://docs.python.org/3/c-api/init_config.html#c.PyConfig.exec_prefix>.
785    pub exec_prefix: Option<PathBuf>,
786
787    /// Controls `sys.executable`.
788    ///
789    /// See <https://docs.python.org/3/c-api/init_config.html#c.PyConfig.executable>.
790    pub executable: Option<PathBuf>,
791
792    /// Enable `faulthandler`.
793    ///
794    /// See <https://docs.python.org/3/c-api/init_config.html#c.PyConfig.faulthandler>.
795    pub fault_handler: Option<bool>,
796
797    /// Controls the encoding to use for filesystems/paths.
798    ///
799    /// See <https://docs.python.org/3/c-api/init_config.html#c.PyConfig.filesystem_encoding>.
800    pub filesystem_encoding: Option<String>,
801
802    /// Filesystem encoding error handler.
803    ///
804    /// See <https://docs.python.org/3/c-api/init_config.html#c.PyConfig.filesystem_errors>.
805    pub filesystem_errors: Option<String>,
806
807    /// Randomized hash function seed.
808    ///
809    /// See <https://docs.python.org/3/c-api/init_config.html#c.PyConfig.hash_seed>.
810    pub hash_seed: Option<c_ulong>,
811
812    /// Python home directory.
813    ///
814    /// See <https://docs.python.org/3/c-api/init_config.html#c.PyConfig.home>.
815    pub home: Option<PathBuf>,
816
817    /// Whether to profile `import` time.
818    ///
819    /// See <https://docs.python.org/3/c-api/init_config.html#c.PyConfig.import_time>.
820    pub import_time: Option<bool>,
821
822    /// Enter interactive mode after executing a script or a command.
823    ///
824    /// See <https://docs.python.org/3/c-api/init_config.html#c.PyConfig.inspect>.
825    pub inspect: Option<bool>,
826
827    /// Whether to install Python signal handlers.
828    ///
829    /// See <https://docs.python.org/3/c-api/init_config.html#c.PyConfig.install_signal_handlers>.
830    pub install_signal_handlers: Option<bool>,
831
832    /// Whether to enable the interactive REPL mode.
833    ///
834    /// See <https://docs.python.org/3/c-api/init_config.html#c.PyConfig.interactive>.
835    pub interactive: Option<bool>,
836
837    /// Controls legacy stdio behavior on Windows.
838    ///
839    /// See <https://docs.python.org/3/c-api/init_config.html#c.PyConfig.legacy_windows_stdio>.
840    pub legacy_windows_stdio: Option<bool>,
841
842    /// Whether to dump statistics from the `pymalloc` allocator on exit.
843    ///
844    /// See <https://docs.python.org/3/c-api/init_config.html#c.PyConfig.malloc_stats>.
845    pub malloc_stats: Option<bool>,
846
847    /// Defines `sys.path`.
848    ///
849    /// See <https://docs.python.org/3/c-api/init_config.html#c.PyConfig.module_search_paths>.
850    ///
851    /// This value effectively controls the initial value of `sys.path`.
852    ///
853    /// The special string `$ORIGIN` in values will be expanded to the absolute path of the
854    /// directory of the executable at run-time. For example, if the executable is
855    /// `/opt/my-application/pyapp`, `$ORIGIN` will expand to `/opt/my-application` and the
856    /// value `$ORIGIN/lib` will expand to `/opt/my-application/lib`.
857    pub module_search_paths: Option<Vec<PathBuf>>,
858
859    /// Bytecode optimization level.
860    ///
861    /// See <https://docs.python.org/3/c-api/init_config.html#c.PyConfig.optimization_level>.
862    ///
863    /// This setting is only relevant if `write_bytecode` is true and Python modules are
864    /// being imported from the filesystem using Python’s standard filesystem importer.
865    pub optimization_level: Option<BytecodeOptimizationLevel>,
866
867    /// Parser debug mode.
868    ///
869    /// See <https://docs.python.org/3/c-api/init_config.html#c.PyConfig.parser_debug>.
870    pub parser_debug: Option<bool>,
871
872    /// Whether calculating the Python path configuration can emit warnings.
873    ///
874    /// See <https://docs.python.org/3/c-api/init_config.html#c.PyConfig.pathconfig_warnings>.
875    pub pathconfig_warnings: Option<bool>,
876
877    /// Defines `sys.prefix`.
878    ///
879    /// See <https://docs.python.org/3/c-api/init_config.html#c.PyConfig.prefix>.
880    pub prefix: Option<PathBuf>,
881
882    /// Program named used to initialize state during path configuration.
883    ///
884    /// See <https://docs.python.org/3/c-api/init_config.html#c.PyConfig.program_name>.
885    pub program_name: Option<PathBuf>,
886
887    /// Directory where `.pyc` files are written.
888    ///
889    /// See <https://docs.python.org/3/c-api/init_config.html#c.PyConfig.pycache_prefix>.
890    pub pycache_prefix: Option<PathBuf>,
891
892    /// See <https://docs.python.org/3/c-api/init_config.html#c.PyConfig.pythonpath_env>.
893    pub python_path_env: Option<String>,
894
895    /// Quiet mode.
896    ///
897    /// See <https://docs.python.org/3/c-api/init_config.html#c.PyConfig.quiet>.
898    pub quiet: Option<bool>,
899
900    /// Value of the `-c` command line option.
901    ///
902    /// Effectively defines Python code to evaluate in `Py_RunMain()`.
903    ///
904    /// See <https://docs.python.org/3/c-api/init_config.html#c.PyConfig.run_command>.
905    pub run_command: Option<String>,
906
907    /// Filename passed on the command line.
908    ///
909    /// Effectively defines the Python file to run in `Py_RunMain()`.
910    ///
911    /// See <https://docs.python.org/3/c-api/init_config.html#c.PyConfig.run_filename>.
912    pub run_filename: Option<PathBuf>,
913
914    /// Value of the `-m` command line option.
915    ///
916    /// Effectively defines the Python module to run as `__main__` in `Py_RunMain()`.
917    ///
918    /// See <https://docs.python.org/3/c-api/init_config.html#c.PyConfig.run_module>.
919    pub run_module: Option<String>,
920
921    /// Whether to show the total reference count at exit.
922    ///
923    /// See <https://docs.python.org/3/c-api/init_config.html#c.PyConfig.show_ref_count>.
924    pub show_ref_count: Option<bool>,
925
926    /// Whether to import the `site` module at startup.
927    ///
928    /// See <https://docs.python.org/3/c-api/init_config.html#c.PyConfig.site_import>.
929    ///
930    /// The `site` module is typically not needed for standalone applications and disabling
931    /// it can reduce application startup time.
932    pub site_import: Option<bool>,
933
934    /// Whether to skip the first line of [Self::run_filename].
935    ///
936    /// See <https://docs.python.org/3/c-api/init_config.html#c.PyConfig.skip_source_first_line>.
937    pub skip_first_source_line: Option<bool>,
938
939    /// Encoding of `sys.stdout`, `sys.stderr`, and `sys.stdin`.
940    ///
941    /// See <https://docs.python.org/3/c-api/init_config.html#c.PyConfig.stdio_encoding>.
942    pub stdio_encoding: Option<String>,
943
944    /// Encoding error handler for `sys.stdout` and `sys.stdin`.
945    ///
946    /// See <https://docs.python.org/3/c-api/init_config.html#c.PyConfig.stdio_errors>.
947    pub stdio_errors: Option<String>,
948
949    /// Whether to enable `tracemalloc`.
950    ///
951    /// See <https://docs.python.org/3/c-api/init_config.html#c.PyConfig.tracemalloc>.
952    pub tracemalloc: Option<bool>,
953
954    /// Whether to add the user site directory to `sys.path`.
955    ///
956    /// See <https://docs.python.org/3/c-api/init_config.html#c.PyConfig.user_site_directory>.
957    pub user_site_directory: Option<bool>,
958
959    /// Verbose mode.
960    ///
961    /// See <https://docs.python.org/3/c-api/init_config.html#c.PyConfig.verbose>.
962    pub verbose: Option<bool>,
963
964    /// Options of the `warning` module to control behavior.
965    ///
966    /// See <https://docs.python.org/3/c-api/init_config.html#c.PyConfig.warnoptions>.
967    pub warn_options: Option<Vec<String>>,
968
969    /// Controls `sys.dont_write_bytecode`.
970    ///
971    /// See <https://docs.python.org/3/c-api/init_config.html#c.PyConfig.write_bytecode>.
972    pub write_bytecode: Option<bool>,
973
974    /// Values of the `-X` command line options / `sys._xoptions`.
975    ///
976    /// See <https://docs.python.org/3/c-api/init_config.html#c.PyConfig.xoptions>.
977    pub x_options: Option<Vec<String>>,
978}