pyoxidizerlib/starlark/
python_interpreter_config.rs

1// This Source Code Form is subject to the terms of the Mozilla Public
2// License, v. 2.0. If a copy of the MPL was not distributed with this
3// file, You can obtain one at https://mozilla.org/MPL/2.0/.
4
5use {
6    super::util::ToValue,
7    crate::py_packaging::config::PyembedPythonInterpreterConfig,
8    python_packaging::{
9        interpreter::{
10            Allocator, BytesWarning, CheckHashPycsMode, CoerceCLocale, MemoryAllocatorBackend,
11            MultiprocessingStartMethod, PythonInterpreterProfile, TerminfoResolution,
12        },
13        resource::BytecodeOptimizationLevel,
14    },
15    starlark::values::{
16        error::{
17            RuntimeError, UnsupportedOperation, ValueError, INCORRECT_PARAMETER_TYPE_ERROR_CODE,
18        },
19        none::NoneType,
20        {Mutable, TypedValue, Value, ValueResult},
21    },
22    starlark_dialect_build_targets::{ToOptional, TryToOptional},
23    std::{
24        str::FromStr,
25        sync::{Arc, Mutex, MutexGuard},
26    },
27};
28
29impl ToValue for PythonInterpreterProfile {
30    fn to_value(&self) -> Value {
31        Value::from(self.to_string())
32    }
33}
34
35impl ToValue for TerminfoResolution {
36    fn to_value(&self) -> Value {
37        Value::from(self.to_string())
38    }
39}
40
41impl ToValue for Option<CoerceCLocale> {
42    fn to_value(&self) -> Value {
43        match self {
44            Some(value) => Value::from(value.to_string()),
45            None => Value::from(NoneType::None),
46        }
47    }
48}
49
50impl ToValue for Option<BytesWarning> {
51    fn to_value(&self) -> Value {
52        match self {
53            Some(value) => Value::from(value.to_string()),
54            None => Value::from(NoneType::None),
55        }
56    }
57}
58
59impl ToValue for Option<CheckHashPycsMode> {
60    fn to_value(&self) -> Value {
61        match self {
62            Some(value) => Value::from(value.to_string()),
63            None => Value::from(NoneType::None),
64        }
65    }
66}
67
68impl ToValue for Option<Allocator> {
69    fn to_value(&self) -> Value {
70        match self {
71            Some(value) => Value::from(value.to_string()),
72            None => Value::from(NoneType::None),
73        }
74    }
75}
76
77impl ToValue for Option<BytecodeOptimizationLevel> {
78    fn to_value(&self) -> Value {
79        match self {
80            Some(value) => Value::from(*value as i32),
81            None => Value::from(NoneType::None),
82        }
83    }
84}
85
86impl ToValue for MemoryAllocatorBackend {
87    fn to_value(&self) -> Value {
88        Value::from(self.to_string())
89    }
90}
91
92fn bytecode_optimization_level_try_to_optional(
93    v: Value,
94) -> Result<Option<BytecodeOptimizationLevel>, ValueError> {
95    if v.get_type() == "NoneType" {
96        Ok(None)
97    } else {
98        match v.to_int()? {
99            0 => Ok(Some(BytecodeOptimizationLevel::Zero)),
100            1 => Ok(Some(BytecodeOptimizationLevel::One)),
101            2 => Ok(Some(BytecodeOptimizationLevel::Two)),
102            _ => Err(ValueError::from(RuntimeError {
103                code: INCORRECT_PARAMETER_TYPE_ERROR_CODE,
104                message: "invalid Python bytecode integer value".to_string(),
105                label: "PythonInterpreterConfig.optimization_level".to_string(),
106            })),
107        }
108    }
109}
110
111#[derive(Debug, Clone)]
112pub struct PythonInterpreterConfigValue {
113    pub inner: Arc<Mutex<PyembedPythonInterpreterConfig>>,
114}
115
116impl PythonInterpreterConfigValue {
117    pub fn new(inner: PyembedPythonInterpreterConfig) -> Self {
118        Self {
119            inner: Arc::new(Mutex::new(inner)),
120        }
121    }
122
123    pub fn inner(
124        &self,
125        label: &str,
126    ) -> Result<MutexGuard<PyembedPythonInterpreterConfig>, ValueError> {
127        self.inner.try_lock().map_err(|e| {
128            ValueError::Runtime(RuntimeError {
129                code: "PYTHON_INTERPRETER_CONFIG",
130                message: format!("error obtaining lock: {}", e),
131                label: label.to_string(),
132            })
133        })
134    }
135}
136
137impl TypedValue for PythonInterpreterConfigValue {
138    type Holder = Mutable<PythonInterpreterConfigValue>;
139    const TYPE: &'static str = "PythonInterpreterConfig";
140
141    fn values_for_descendant_check_and_freeze(&self) -> Box<dyn Iterator<Item = Value>> {
142        Box::new(std::iter::empty())
143    }
144
145    fn to_str(&self) -> String {
146        format!("PythonInterpreterConfig<{:#?}>", self.inner)
147    }
148
149    fn to_repr(&self) -> String {
150        self.to_str()
151    }
152
153    fn get_attr(&self, attribute: &str) -> ValueResult {
154        let inner = self.inner(&format!("PythonInterpreterConfig.{}", attribute))?;
155
156        let v = match attribute {
157            "config_profile" => inner.config.profile.to_value(),
158            "allocator" => inner.config.allocator.to_value(),
159            "configure_locale" => inner.config.configure_locale.to_value(),
160            "coerce_c_locale" => inner.config.coerce_c_locale.to_value(),
161            "coerce_c_locale_warn" => inner.config.coerce_c_locale_warn.to_value(),
162            "development_mode" => inner.config.development_mode.to_value(),
163            "isolated" => inner.config.isolated.to_value(),
164            "legacy_windows_fs_encoding" => inner.config.legacy_windows_fs_encoding.to_value(),
165            "parse_argv" => inner.config.parse_argv.to_value(),
166            "use_environment" => inner.config.use_environment.to_value(),
167            "utf8_mode" => inner.config.utf8_mode.to_value(),
168            "base_exec_prefix" => inner.config.base_exec_prefix.to_value(),
169            "base_executable" => inner.config.base_executable.to_value(),
170            "base_prefix" => inner.config.base_prefix.to_value(),
171            "buffered_stdio" => inner.config.buffered_stdio.to_value(),
172            "bytes_warning" => inner.config.bytes_warning.to_value(),
173            "check_hash_pycs_mode" => inner.config.check_hash_pycs_mode.to_value(),
174            "configure_c_stdio" => inner.config.configure_c_stdio.to_value(),
175            "dump_refs" => inner.config.dump_refs.to_value(),
176            "exec_prefix" => inner.config.exec_prefix.to_value(),
177            "executable" => inner.config.executable.to_value(),
178            "fault_handler" => inner.config.fault_handler.to_value(),
179            "filesystem_encoding" => inner.config.filesystem_encoding.to_value(),
180            "filesystem_errors" => inner.config.filesystem_errors.to_value(),
181            "hash_seed" => inner.config.hash_seed.to_value(),
182            "home" => inner.config.home.to_value(),
183            "import_time" => inner.config.import_time.to_value(),
184            "inspect" => inner.config.inspect.to_value(),
185            "install_signal_handlers" => inner.config.install_signal_handlers.to_value(),
186            "interactive" => inner.config.interactive.to_value(),
187            "legacy_windows_stdio" => inner.config.legacy_windows_stdio.to_value(),
188            "malloc_stats" => inner.config.malloc_stats.to_value(),
189            "module_search_paths" => inner.config.module_search_paths.to_value(),
190            "optimization_level" => inner.config.optimization_level.to_value(),
191            "parser_debug" => inner.config.parser_debug.to_value(),
192            "pathconfig_warnings" => inner.config.pathconfig_warnings.to_value(),
193            "prefix" => inner.config.prefix.to_value(),
194            "program_name" => inner.config.program_name.to_value(),
195            "pycache_prefix" => inner.config.pycache_prefix.to_value(),
196            "python_path_env" => inner.config.python_path_env.to_value(),
197            "quiet" => inner.config.quiet.to_value(),
198            "run_command" => inner.config.run_command.to_value(),
199            "run_filename" => inner.config.run_filename.to_value(),
200            "run_module" => inner.config.run_module.to_value(),
201            "show_ref_count" => inner.config.show_ref_count.to_value(),
202            "site_import" => inner.config.site_import.to_value(),
203            "skip_first_source_line" => inner.config.skip_first_source_line.to_value(),
204            "stdio_encoding" => inner.config.stdio_encoding.to_value(),
205            "stdio_errors" => inner.config.stdio_errors.to_value(),
206            "tracemalloc" => inner.config.tracemalloc.to_value(),
207            "user_site_directory" => inner.config.user_site_directory.to_value(),
208            "verbose" => inner.config.verbose.to_value(),
209            "warn_options" => inner.config.warn_options.to_value(),
210            "write_bytecode" => inner.config.write_bytecode.to_value(),
211            "x_options" => inner.config.x_options.to_value(),
212            "allocator_backend" => inner.allocator_backend.to_value(),
213            "allocator_raw" => Value::from(inner.allocator_raw),
214            "allocator_mem" => Value::from(inner.allocator_mem),
215            "allocator_obj" => Value::from(inner.allocator_obj),
216            "allocator_pymalloc_arena" => Value::from(inner.allocator_pymalloc_arena),
217            "allocator_debug" => Value::from(inner.allocator_debug),
218            "oxidized_importer" => Value::from(inner.oxidized_importer),
219            "filesystem_importer" => Value::from(inner.filesystem_importer),
220            "argvb" => Value::from(inner.argvb),
221            "multiprocessing_auto_dispatch" => Value::from(inner.multiprocessing_auto_dispatch),
222            "multiprocessing_start_method" => {
223                Value::from(inner.multiprocessing_start_method.to_string())
224            }
225            "sys_frozen" => Value::from(inner.sys_frozen),
226            "sys_meipass" => Value::from(inner.sys_meipass),
227            "terminfo_resolution" => inner.terminfo_resolution.to_value(),
228            "write_modules_directory_env" => inner.write_modules_directory_env.to_value(),
229            attr => {
230                return Err(ValueError::OperationNotSupported {
231                    op: UnsupportedOperation::GetAttr(attr.to_string()),
232                    left: Self::TYPE.to_owned(),
233                    right: None,
234                })
235            }
236        };
237
238        Ok(v)
239    }
240
241    fn has_attr(&self, attribute: &str) -> Result<bool, ValueError> {
242        Ok(matches!(
243            attribute,
244            "config_profile"
245                | "allocator"
246                | "configure_locale"
247                | "coerce_c_locale"
248                | "coerce_c_locale_warn"
249                | "development_mode"
250                | "isolated"
251                | "legacy_windows_fs_encoding"
252                | "parse_argv"
253                | "use_environment"
254                | "utf8_mode"
255                | "base_exec_prefix"
256                | "base_executable"
257                | "base_prefix"
258                | "buffered_stdio"
259                | "bytes_warning"
260                | "check_hash_pycs_mode"
261                | "configure_c_stdio"
262                | "dump_refs"
263                | "exec_prefix"
264                | "executable"
265                | "fault_handler"
266                | "filesystem_encoding"
267                | "filesystem_errors"
268                | "hash_seed"
269                | "home"
270                | "import_time"
271                | "inspect"
272                | "install_signal_handlers"
273                | "interactive"
274                | "legacy_windows_stdio"
275                | "malloc_stats"
276                | "module_search_paths"
277                | "optimization_level"
278                | "parser_debug"
279                | "pathconfig_warnings"
280                | "prefix"
281                | "program_name"
282                | "pycache_prefix"
283                | "python_path_env"
284                | "quiet"
285                | "run_command"
286                | "run_filename"
287                | "run_module"
288                | "show_ref_count"
289                | "site_import"
290                | "skip_first_source_line"
291                | "stdio_encoding"
292                | "stdio_errors"
293                | "tracemalloc"
294                | "user_site_directory"
295                | "verbose"
296                | "warn_options"
297                | "write_bytecode"
298                | "x_options"
299                | "allocator_backend"
300                | "allocator_raw"
301                | "allocator_mem"
302                | "allocator_obj"
303                | "allocator_pymalloc_arena"
304                | "allocator_debug"
305                | "oxidized_importer"
306                | "filesystem_importer"
307                | "argvb"
308                | "multiprocessing_auto_dispatch"
309                | "multiprocessing_start_method"
310                | "sys_frozen"
311                | "sys_meipass"
312                | "terminfo_resolution"
313                | "write_modules_directory_env"
314        ))
315    }
316
317    fn set_attr(&mut self, attribute: &str, value: Value) -> Result<(), ValueError> {
318        let mut inner = self.inner(&format!("PythonInterpreterConfig.{}", attribute))?;
319
320        match attribute {
321            "config_profile" => {
322                inner.config.profile = PythonInterpreterProfile::try_from(
323                    value.to_string().as_str(),
324                )
325                .map_err(|e| {
326                    ValueError::from(RuntimeError {
327                        code: INCORRECT_PARAMETER_TYPE_ERROR_CODE,
328                        message: e,
329                        label: format!("{}.{}", Self::TYPE, attribute),
330                    })
331                })?;
332            }
333            "allocator" => {
334                inner.config.allocator = if value.get_type() == "NoneType" {
335                    None
336                } else {
337                    Some(
338                        Allocator::try_from(value.to_string().as_str()).map_err(|e| {
339                            ValueError::from(RuntimeError {
340                                code: INCORRECT_PARAMETER_TYPE_ERROR_CODE,
341                                message: e,
342                                label: format!("{}.{}", Self::TYPE, attribute),
343                            })
344                        })?,
345                    )
346                };
347            }
348            "configure_locale" => {
349                inner.config.configure_locale = value.to_optional();
350            }
351            "coerce_c_locale" => {
352                inner.config.coerce_c_locale = if value.get_type() == "NoneType" {
353                    None
354                } else {
355                    Some(
356                        CoerceCLocale::try_from(value.to_string().as_str()).map_err(|e| {
357                            ValueError::from(RuntimeError {
358                                code: INCORRECT_PARAMETER_TYPE_ERROR_CODE,
359                                message: e,
360                                label: format!("{}.{}", Self::TYPE, attribute),
361                            })
362                        })?,
363                    )
364                };
365            }
366            "coerce_c_locale_warn" => {
367                inner.config.coerce_c_locale_warn = value.to_optional();
368            }
369            "development_mode" => {
370                inner.config.development_mode = value.to_optional();
371            }
372            "isolated" => {
373                inner.config.isolated = value.to_optional();
374            }
375            "legacy_windows_fs_encoding" => {
376                inner.config.legacy_windows_fs_encoding = value.to_optional();
377            }
378            "parse_argv" => {
379                inner.config.parse_argv = value.to_optional();
380            }
381            "use_environment" => {
382                inner.config.use_environment = value.to_optional();
383            }
384            "utf8_mode" => {
385                inner.config.utf8_mode = value.to_optional();
386            }
387            "base_exec_prefix" => {
388                inner.config.base_exec_prefix = value.to_optional();
389            }
390            "base_executable" => {
391                inner.config.base_executable = value.to_optional();
392            }
393            "base_prefix" => {
394                inner.config.base_prefix = value.to_optional();
395            }
396            "buffered_stdio" => {
397                inner.config.buffered_stdio = value.to_optional();
398            }
399            "bytes_warning" => {
400                inner.config.bytes_warning = if value.get_type() == "NoneType" {
401                    None
402                } else {
403                    Some(
404                        BytesWarning::try_from(value.to_string().as_str()).map_err(|e| {
405                            ValueError::from(RuntimeError {
406                                code: INCORRECT_PARAMETER_TYPE_ERROR_CODE,
407                                message: e,
408                                label: format!("{}.{}", Self::TYPE, attribute),
409                            })
410                        })?,
411                    )
412                };
413            }
414            "check_hash_pycs_mode" => {
415                inner.config.check_hash_pycs_mode = if value.get_type() == "NoneType" {
416                    None
417                } else {
418                    Some(
419                        CheckHashPycsMode::try_from(value.to_string().as_str()).map_err(|e| {
420                            ValueError::from(RuntimeError {
421                                code: INCORRECT_PARAMETER_TYPE_ERROR_CODE,
422                                message: e,
423                                label: format!("{}.{}", Self::TYPE, attribute),
424                            })
425                        })?,
426                    )
427                };
428            }
429            "configure_c_stdio" => {
430                inner.config.configure_c_stdio = value.to_optional();
431            }
432            "dump_refs" => {
433                inner.config.dump_refs = value.to_optional();
434            }
435            "exec_prefix" => {
436                inner.config.exec_prefix = value.to_optional();
437            }
438            "executable" => {
439                inner.config.executable = value.to_optional();
440            }
441            "fault_handler" => {
442                inner.config.fault_handler = value.to_optional();
443            }
444            "filesystem_encoding" => {
445                inner.config.filesystem_encoding = value.to_optional();
446            }
447            "filesystem_errors" => {
448                inner.config.filesystem_errors = value.to_optional();
449            }
450            "hash_seed" => {
451                inner.config.hash_seed = value.try_to_optional()?;
452            }
453            "home" => {
454                inner.config.home = value.to_optional();
455            }
456            "import_time" => {
457                inner.config.import_time = value.to_optional();
458            }
459            "inspect" => {
460                inner.config.inspect = value.to_optional();
461            }
462            "install_signal_handlers" => {
463                inner.config.install_signal_handlers = value.to_optional();
464            }
465            "interactive" => {
466                inner.config.interactive = value.to_optional();
467            }
468            "legacy_windows_stdio" => {
469                inner.config.legacy_windows_stdio = value.to_optional();
470            }
471            "malloc_stats" => {
472                inner.config.malloc_stats = value.to_optional();
473            }
474            "module_search_paths" => {
475                inner.config.module_search_paths = value.try_to_optional()?;
476
477                // Automatically enable filesystem importer if module search paths
478                // are registered.
479                if let Some(paths) = &inner.config.module_search_paths {
480                    if !paths.is_empty() {
481                        inner.filesystem_importer = true;
482                    }
483                }
484            }
485            "optimization_level" => {
486                inner.config.optimization_level =
487                    bytecode_optimization_level_try_to_optional(value)?;
488            }
489            "parser_debug" => {
490                inner.config.parser_debug = value.to_optional();
491            }
492            "pathconfig_warnings" => {
493                inner.config.pathconfig_warnings = value.to_optional();
494            }
495            "prefix" => {
496                inner.config.prefix = value.to_optional();
497            }
498            "program_name" => {
499                inner.config.program_name = value.to_optional();
500            }
501            "pycache_prefix" => {
502                inner.config.pycache_prefix = value.to_optional();
503            }
504            "python_path_env" => {
505                inner.config.python_path_env = value.to_optional();
506            }
507            "quiet" => {
508                inner.config.quiet = value.to_optional();
509            }
510            "run_command" => {
511                inner.config.run_command = value.to_optional();
512            }
513            "run_filename" => {
514                inner.config.run_filename = value.to_optional();
515            }
516            "run_module" => {
517                inner.config.run_module = value.to_optional();
518            }
519            "show_ref_count" => {
520                inner.config.show_ref_count = value.to_optional();
521            }
522            "site_import" => {
523                inner.config.site_import = value.to_optional();
524            }
525            "skip_first_source_line" => {
526                inner.config.skip_first_source_line = value.to_optional();
527            }
528            "stdio_encoding" => {
529                inner.config.stdio_encoding = value.to_optional();
530            }
531            "stdio_errors" => {
532                inner.config.stdio_errors = value.to_optional();
533            }
534            "tracemalloc" => {
535                inner.config.tracemalloc = value.to_optional();
536            }
537            "user_site_directory" => {
538                inner.config.user_site_directory = value.to_optional();
539            }
540            "verbose" => {
541                inner.config.configure_locale = value.to_optional();
542            }
543            "warn_options" => {
544                inner.config.warn_options = value.try_to_optional()?;
545            }
546            "write_bytecode" => {
547                inner.config.write_bytecode = value.to_optional();
548            }
549            "x_options" => {
550                inner.config.x_options = value.try_to_optional()?;
551            }
552            "allocator_backend" => {
553                inner.allocator_backend =
554                    MemoryAllocatorBackend::try_from(value.to_string().as_str()).map_err(|e| {
555                        ValueError::from(RuntimeError {
556                            code: INCORRECT_PARAMETER_TYPE_ERROR_CODE,
557                            message: e,
558                            label: format!("{}.{}", Self::TYPE, attribute),
559                        })
560                    })?;
561            }
562            "allocator_raw" => {
563                inner.allocator_raw = value.to_bool();
564            }
565            "allocator_mem" => {
566                inner.allocator_mem = value.to_bool();
567            }
568            "allocator_obj" => {
569                inner.allocator_obj = value.to_bool();
570            }
571            "allocator_pymalloc_arena" => {
572                inner.allocator_pymalloc_arena = value.to_bool();
573            }
574            "allocator_debug" => {
575                inner.allocator_debug = value.to_bool();
576            }
577            "oxidized_importer" => {
578                inner.oxidized_importer = value.to_bool();
579            }
580            "filesystem_importer" => {
581                inner.filesystem_importer = value.to_bool();
582            }
583            "argvb" => {
584                inner.argvb = value.to_bool();
585            }
586            "multiprocessing_auto_dispatch" => {
587                inner.multiprocessing_auto_dispatch = value.to_bool();
588            }
589            "multiprocessing_start_method" => {
590                inner.multiprocessing_start_method = MultiprocessingStartMethod::from_str(
591                    value.to_string().as_str(),
592                )
593                .map_err(|e| {
594                    ValueError::from(RuntimeError {
595                        code: INCORRECT_PARAMETER_TYPE_ERROR_CODE,
596                        message: e,
597                        label: format!("{}.{}", Self::TYPE, attribute),
598                    })
599                })?;
600            }
601            "sys_frozen" => {
602                inner.sys_frozen = value.to_bool();
603            }
604            "sys_meipass" => {
605                inner.sys_meipass = value.to_bool();
606            }
607            "terminfo_resolution" => {
608                inner.terminfo_resolution =
609                    TerminfoResolution::try_from(value.to_string().as_str()).map_err(|e| {
610                        ValueError::from(RuntimeError {
611                            code: INCORRECT_PARAMETER_TYPE_ERROR_CODE,
612                            message: e,
613                            label: format!("{}.{}", Self::TYPE, attribute),
614                        })
615                    })?;
616            }
617            "write_modules_directory_env" => {
618                inner.write_modules_directory_env = value.to_optional();
619            }
620            attr => {
621                return Err(ValueError::OperationNotSupported {
622                    op: UnsupportedOperation::SetAttr(attr.to_string()),
623                    left: Self::TYPE.to_owned(),
624                    right: None,
625                })
626            }
627        }
628
629        Ok(())
630    }
631}
632
633#[cfg(test)]
634mod tests {
635    use crate::starlark::eval::EvaluationContext;
636    use {super::super::testutil::*, anyhow::Result};
637
638    // TODO instantiating a new distribution every call is expensive. Can we cache this?
639    fn get_env() -> Result<EvaluationContext> {
640        let mut eval = test_evaluation_context_builder()?.into_context()?;
641        eval.eval("dist = default_python_distribution()")?;
642        eval.eval("config = dist.make_python_interpreter_config()")?;
643
644        Ok(eval)
645    }
646
647    #[test]
648    fn test_profile() -> Result<()> {
649        let mut env = get_env()?;
650
651        eval_assert(&mut env, "config.config_profile == 'isolated'")?;
652
653        env.eval("config.config_profile = 'python'")?;
654        eval_assert(&mut env, "config.config_profile == 'python'")?;
655
656        env.eval("config.config_profile = 'isolated'")?;
657        eval_assert(&mut env, "config.config_profile == 'isolated'")?;
658
659        Ok(())
660    }
661
662    #[test]
663    fn test_allocator() -> Result<()> {
664        let mut env = get_env()?;
665
666        eval_assert(&mut env, "config.allocator == None")?;
667
668        env.eval("config.allocator = 'not-set'")?;
669        eval_assert(&mut env, "config.allocator == 'not-set'")?;
670
671        env.eval("config.allocator = 'default'")?;
672        eval_assert(&mut env, "config.allocator == 'default'")?;
673
674        env.eval("config.allocator = 'debug'")?;
675        eval_assert(&mut env, "config.allocator == 'debug'")?;
676
677        env.eval("config.allocator = 'malloc'")?;
678        eval_assert(&mut env, "config.allocator == 'malloc'")?;
679
680        env.eval("config.allocator = 'malloc-debug'")?;
681        eval_assert(&mut env, "config.allocator == 'malloc-debug'")?;
682
683        env.eval("config.allocator = 'py-malloc'")?;
684        eval_assert(&mut env, "config.allocator == 'py-malloc'")?;
685
686        env.eval("config.allocator = 'py-malloc-debug'")?;
687        eval_assert(&mut env, "config.allocator == 'py-malloc-debug'")?;
688
689        env.eval("config.allocator = None")?;
690        eval_assert(&mut env, "config.allocator == None")?;
691
692        Ok(())
693    }
694
695    #[test]
696    fn test_configure_locale() -> Result<()> {
697        let mut env = get_env()?;
698
699        eval_assert(&mut env, "config.configure_locale == True")?;
700
701        Ok(())
702    }
703
704    #[test]
705    fn test_coerce_c_locale() -> Result<()> {
706        let mut env = get_env()?;
707
708        eval_assert(&mut env, "config.coerce_c_locale == None")?;
709
710        Ok(())
711    }
712
713    #[test]
714    fn test_development_mode() -> Result<()> {
715        let mut env = get_env()?;
716
717        eval_assert(&mut env, "config.development_mode == None")?;
718
719        Ok(())
720    }
721
722    #[test]
723    fn test_isolated() -> Result<()> {
724        let mut env = get_env()?;
725
726        eval_assert(&mut env, "config.isolated == None")?;
727
728        Ok(())
729    }
730
731    #[test]
732    fn test_legacy_windows_fs_encoding() -> Result<()> {
733        let mut env = get_env()?;
734
735        eval_assert(&mut env, "config.legacy_windows_fs_encoding == None")?;
736
737        Ok(())
738    }
739
740    #[test]
741    fn test_parse_argv() -> Result<()> {
742        let mut env = get_env()?;
743
744        eval_assert(&mut env, "config.parse_argv == None")?;
745
746        Ok(())
747    }
748
749    #[test]
750    fn test_use_environment() -> Result<()> {
751        let mut env = get_env()?;
752
753        eval_assert(&mut env, "config.use_environment == None")?;
754
755        Ok(())
756    }
757
758    #[test]
759    fn test_utf8_mode() -> Result<()> {
760        let mut env = get_env()?;
761
762        eval_assert(&mut env, "config.utf8_mode == None")?;
763
764        Ok(())
765    }
766
767    #[test]
768    fn test_base_exec_prefix() -> Result<()> {
769        let mut env = get_env()?;
770
771        eval_assert(&mut env, "config.base_exec_prefix == None")?;
772
773        Ok(())
774    }
775
776    #[test]
777    fn test_base_executable() -> Result<()> {
778        let mut env = get_env()?;
779
780        eval_assert(&mut env, "config.base_executable == None")?;
781
782        Ok(())
783    }
784
785    #[test]
786    fn test_base_prefix() -> Result<()> {
787        let mut env = get_env()?;
788
789        eval_assert(&mut env, "config.base_prefix == None")?;
790
791        Ok(())
792    }
793
794    #[test]
795    fn test_buffered_stdio() -> Result<()> {
796        let mut env = get_env()?;
797
798        eval_assert(&mut env, "config.buffered_stdio == None")?;
799
800        Ok(())
801    }
802
803    #[test]
804    fn test_bytes_warning() -> Result<()> {
805        let mut env = get_env()?;
806
807        eval_assert(&mut env, "config.bytes_warning == None")?;
808
809        env.eval("config.bytes_warning = 'warn'")?;
810        eval_assert(&mut env, "config.bytes_warning == 'warn'")?;
811
812        env.eval("config.bytes_warning = 'raise'")?;
813        eval_assert(&mut env, "config.bytes_warning == 'raise'")?;
814
815        env.eval("config.bytes_warning = None")?;
816        eval_assert(&mut env, "config.bytes_warning == None")?;
817
818        Ok(())
819    }
820
821    #[test]
822    fn test_check_hash_pycs_mode() -> Result<()> {
823        let mut env = get_env()?;
824
825        eval_assert(&mut env, "config.check_hash_pycs_mode == None")?;
826
827        Ok(())
828    }
829
830    #[test]
831    fn test_configure_c_stdio() -> Result<()> {
832        let mut env = get_env()?;
833
834        eval_assert(&mut env, "config.configure_c_stdio == None")?;
835
836        Ok(())
837    }
838
839    #[test]
840    fn test_dump_refs() -> Result<()> {
841        let mut env = get_env()?;
842
843        eval_assert(&mut env, "config.dump_refs == None")?;
844
845        Ok(())
846    }
847
848    #[test]
849    fn test_exec_prefix() -> Result<()> {
850        let mut env = get_env()?;
851
852        eval_assert(&mut env, "config.exec_prefix == None")?;
853
854        Ok(())
855    }
856
857    #[test]
858    fn test_executable() -> Result<()> {
859        let mut env = get_env()?;
860
861        eval_assert(&mut env, "config.executable == None")?;
862
863        Ok(())
864    }
865
866    #[test]
867    fn test_fault_handler() -> Result<()> {
868        let mut env = get_env()?;
869
870        eval_assert(&mut env, "config.fault_handler == None")?;
871
872        Ok(())
873    }
874
875    #[test]
876    fn test_filesystem_encoding() -> Result<()> {
877        let mut env = get_env()?;
878
879        eval_assert(&mut env, "config.filesystem_encoding == None")?;
880
881        Ok(())
882    }
883
884    #[test]
885    fn test_filesystem_errors() -> Result<()> {
886        let mut env = get_env()?;
887
888        eval_assert(&mut env, "config.filesystem_errors == None")?;
889
890        Ok(())
891    }
892
893    #[test]
894    fn test_hash_seed() -> Result<()> {
895        let mut env = get_env()?;
896
897        eval_assert(&mut env, "config.hash_seed == None")?;
898
899        Ok(())
900    }
901
902    #[test]
903    fn test_home() -> Result<()> {
904        let mut env = get_env()?;
905
906        eval_assert(&mut env, "config.home == None")?;
907
908        Ok(())
909    }
910
911    #[test]
912    fn test_import_time() -> Result<()> {
913        let mut env = get_env()?;
914
915        eval_assert(&mut env, "config.import_time == None")?;
916
917        Ok(())
918    }
919
920    #[test]
921    fn test_inspect() -> Result<()> {
922        let mut env = get_env()?;
923
924        eval_assert(&mut env, "config.inspect == None")?;
925
926        Ok(())
927    }
928
929    #[test]
930    fn test_install_signal_handlers() -> Result<()> {
931        let mut env = get_env()?;
932
933        eval_assert(&mut env, "config.install_signal_handlers == None")?;
934
935        Ok(())
936    }
937
938    #[test]
939    fn test_interactive() -> Result<()> {
940        let mut env = get_env()?;
941
942        eval_assert(&mut env, "config.interactive == None")?;
943
944        Ok(())
945    }
946
947    #[test]
948    fn test_legacy_windows_stdio() -> Result<()> {
949        let mut env = get_env()?;
950
951        eval_assert(&mut env, "config.legacy_windows_stdio == None")?;
952
953        Ok(())
954    }
955
956    #[test]
957    fn test_malloc_stats() -> Result<()> {
958        let mut env = get_env()?;
959
960        eval_assert(&mut env, "config.malloc_stats == None")?;
961
962        Ok(())
963    }
964
965    #[test]
966    fn test_module_search_paths() -> Result<()> {
967        let mut env = get_env()?;
968
969        eval_assert(&mut env, "config.module_search_paths == None")?;
970        eval_assert(&mut env, "config.filesystem_importer == False")?;
971
972        env.eval("config.module_search_paths = []")?;
973        eval_assert(&mut env, "config.module_search_paths == []")?;
974        eval_assert(&mut env, "config.filesystem_importer == False")?;
975
976        env.eval("config.module_search_paths = ['foo']")?;
977        eval_assert(&mut env, "config.module_search_paths == ['foo']")?;
978        // filesystem_importer enabled when setting paths.
979        eval_assert(&mut env, "config.filesystem_importer == True")?;
980
981        Ok(())
982    }
983
984    #[test]
985    fn test_optimization_level() -> Result<()> {
986        let mut env = get_env()?;
987
988        eval_assert(&mut env, "config.optimization_level == None")?;
989
990        env.eval("config.optimization_level = 0")?;
991        eval_assert(&mut env, "config.optimization_level == 0")?;
992
993        env.eval("config.optimization_level = 1")?;
994        eval_assert(&mut env, "config.optimization_level == 1")?;
995
996        env.eval("config.optimization_level = 2")?;
997        eval_assert(&mut env, "config.optimization_level == 2")?;
998
999        Ok(())
1000    }
1001
1002    #[test]
1003    fn test_parser_debug() -> Result<()> {
1004        let mut env = get_env()?;
1005
1006        eval_assert(&mut env, "config.parser_debug == None")?;
1007
1008        Ok(())
1009    }
1010
1011    #[test]
1012    fn test_pathconfig_warnings() -> Result<()> {
1013        let mut env = get_env()?;
1014
1015        eval_assert(&mut env, "config.pathconfig_warnings == None")?;
1016
1017        Ok(())
1018    }
1019
1020    #[test]
1021    fn test_prefix() -> Result<()> {
1022        let mut env = get_env()?;
1023
1024        eval_assert(&mut env, "config.prefix == None")?;
1025
1026        Ok(())
1027    }
1028
1029    #[test]
1030    fn test_program_name() -> Result<()> {
1031        let mut env = get_env()?;
1032
1033        eval_assert(&mut env, "config.program_name == None")?;
1034
1035        Ok(())
1036    }
1037
1038    #[test]
1039    fn test_pycache_prefix() -> Result<()> {
1040        let mut env = get_env()?;
1041
1042        eval_assert(&mut env, "config.pycache_prefix == None")?;
1043
1044        Ok(())
1045    }
1046
1047    #[test]
1048    fn test_python_path_env() -> Result<()> {
1049        let mut env = get_env()?;
1050
1051        eval_assert(&mut env, "config.python_path_env == None")?;
1052
1053        Ok(())
1054    }
1055
1056    #[test]
1057    fn test_quiet() -> Result<()> {
1058        let mut env = get_env()?;
1059
1060        eval_assert(&mut env, "config.quiet == None")?;
1061
1062        Ok(())
1063    }
1064
1065    #[test]
1066    fn test_run_command() -> Result<()> {
1067        let mut env = get_env()?;
1068
1069        eval_assert(&mut env, "config.run_command == None")?;
1070
1071        Ok(())
1072    }
1073
1074    #[test]
1075    fn test_run_filename() -> Result<()> {
1076        let mut env = get_env()?;
1077
1078        eval_assert(&mut env, "config.run_filename == None")?;
1079
1080        Ok(())
1081    }
1082
1083    #[test]
1084    fn test_run_module() -> Result<()> {
1085        let mut env = get_env()?;
1086
1087        eval_assert(&mut env, "config.run_module == None")?;
1088
1089        Ok(())
1090    }
1091
1092    #[test]
1093    fn test_show_ref_count() -> Result<()> {
1094        let mut env = get_env()?;
1095
1096        eval_assert(&mut env, "config.show_ref_count == None")?;
1097
1098        Ok(())
1099    }
1100
1101    #[test]
1102    fn test_site_import() -> Result<()> {
1103        let mut env = get_env()?;
1104
1105        eval_assert(&mut env, "config.site_import == None")?;
1106
1107        Ok(())
1108    }
1109
1110    #[test]
1111    fn test_skip_first_source_line() -> Result<()> {
1112        let mut env = get_env()?;
1113
1114        eval_assert(&mut env, "config.skip_first_source_line == None")?;
1115
1116        Ok(())
1117    }
1118
1119    #[test]
1120    fn test_stdio_encoding() -> Result<()> {
1121        let mut env = get_env()?;
1122
1123        eval_assert(&mut env, "config.stdio_encoding == None")?;
1124
1125        Ok(())
1126    }
1127
1128    #[test]
1129    fn test_stdio_errors() -> Result<()> {
1130        let mut env = get_env()?;
1131
1132        eval_assert(&mut env, "config.stdio_errors == None")?;
1133
1134        Ok(())
1135    }
1136
1137    #[test]
1138    fn test_tracemalloc() -> Result<()> {
1139        let mut env = get_env()?;
1140
1141        eval_assert(&mut env, "config.tracemalloc == None")?;
1142
1143        Ok(())
1144    }
1145
1146    #[test]
1147    fn test_user_site_directory() -> Result<()> {
1148        let mut env = get_env()?;
1149
1150        eval_assert(&mut env, "config.user_site_directory == None")?;
1151        env.eval("config.user_site_directory = True")?;
1152        let v = env.eval("config.user_site_directory")?;
1153        assert!(v.to_bool());
1154        env.eval("config.user_site_directory = False")?;
1155        let v = env.eval("config.user_site_directory")?;
1156        assert!(!v.to_bool());
1157
1158        Ok(())
1159    }
1160
1161    #[test]
1162    fn test_verbose() -> Result<()> {
1163        let mut env = get_env()?;
1164
1165        eval_assert(&mut env, "config.verbose == None")?;
1166
1167        Ok(())
1168    }
1169
1170    #[test]
1171    fn test_warn_options() -> Result<()> {
1172        let mut env = get_env()?;
1173
1174        eval_assert(&mut env, "config.warn_options == None")?;
1175
1176        Ok(())
1177    }
1178
1179    #[test]
1180    fn test_write_bytecode() -> Result<()> {
1181        let mut env = get_env()?;
1182
1183        eval_assert(&mut env, "config.write_bytecode == None")?;
1184
1185        Ok(())
1186    }
1187
1188    #[test]
1189    fn test_x_options() -> Result<()> {
1190        let mut env = get_env()?;
1191
1192        eval_assert(&mut env, "config.x_options == None")?;
1193
1194        Ok(())
1195    }
1196
1197    #[test]
1198    fn test_allocator_backend() -> Result<()> {
1199        let mut env = get_env()?;
1200
1201        eval_assert(&mut env, "config.allocator_backend == 'default'")?;
1202
1203        env.eval("config.allocator_backend = 'jemalloc'")?;
1204        eval_assert(&mut env, "config.allocator_backend == 'jemalloc'")?;
1205
1206        env.eval("config.allocator_backend = 'mimalloc'")?;
1207        eval_assert(&mut env, "config.allocator_backend == 'mimalloc'")?;
1208
1209        env.eval("config.allocator_backend = 'rust'")?;
1210        eval_assert(&mut env, "config.allocator_backend == 'rust'")?;
1211
1212        env.eval("config.allocator_backend = 'snmalloc'")?;
1213        eval_assert(&mut env, "config.allocator_backend == 'snmalloc'")?;
1214
1215        env.eval("config.allocator_backend = 'default'")?;
1216        eval_assert(&mut env, "config.allocator_backend == 'default'")?;
1217
1218        Ok(())
1219    }
1220
1221    #[test]
1222    fn test_allocator_raw() -> Result<()> {
1223        let mut env = get_env()?;
1224
1225        eval_assert(&mut env, "config.allocator_raw == True")?;
1226
1227        env.eval("config.allocator_raw = False")?;
1228        eval_assert(&mut env, "config.allocator_raw == False")?;
1229
1230        Ok(())
1231    }
1232
1233    #[test]
1234    fn test_allocator_mem() -> Result<()> {
1235        let mut env = get_env()?;
1236
1237        eval_assert(&mut env, "config.allocator_mem == False")?;
1238
1239        env.eval("config.allocator_mem = True")?;
1240        eval_assert(&mut env, "config.allocator_mem == True")?;
1241
1242        Ok(())
1243    }
1244
1245    #[test]
1246    fn test_allocator_obj() -> Result<()> {
1247        let mut env = get_env()?;
1248
1249        eval_assert(&mut env, "config.allocator_obj == False")?;
1250
1251        env.eval("config.allocator_obj = True")?;
1252        eval_assert(&mut env, "config.allocator_obj == True")?;
1253
1254        Ok(())
1255    }
1256
1257    #[test]
1258    fn test_allocator_pymalloc_arena() -> Result<()> {
1259        let mut env = get_env()?;
1260
1261        eval_assert(&mut env, "config.allocator_pymalloc_arena == False")?;
1262
1263        env.eval("config.allocator_pymalloc_arena = True")?;
1264        eval_assert(&mut env, "config.allocator_pymalloc_arena == True")?;
1265
1266        Ok(())
1267    }
1268
1269    #[test]
1270    fn test_allocator_debug() -> Result<()> {
1271        let mut env = get_env()?;
1272
1273        eval_assert(&mut env, "config.allocator_debug == False")?;
1274
1275        env.eval("config.allocator_debug = True")?;
1276        eval_assert(&mut env, "config.allocator_debug == True")?;
1277
1278        Ok(())
1279    }
1280
1281    #[test]
1282    fn test_oxidized_importer() -> Result<()> {
1283        let mut env = get_env()?;
1284
1285        eval_assert(&mut env, "config.oxidized_importer == True")?;
1286
1287        Ok(())
1288    }
1289
1290    #[test]
1291    fn test_filesystem_importer() -> Result<()> {
1292        let mut env = get_env()?;
1293
1294        eval_assert(&mut env, "config.filesystem_importer == False")?;
1295
1296        Ok(())
1297    }
1298
1299    #[test]
1300    fn test_argvb() -> Result<()> {
1301        let mut env = get_env()?;
1302
1303        eval_assert(&mut env, "config.argvb == False")?;
1304
1305        Ok(())
1306    }
1307
1308    #[test]
1309    fn test_multiprocessing_auto_dispatch() -> Result<()> {
1310        let mut env = get_env()?;
1311
1312        eval_assert(&mut env, "config.multiprocessing_auto_dispatch == True")?;
1313
1314        env.eval("config.multiprocessing_auto_dispatch = False")?;
1315        eval_assert(&mut env, "config.multiprocessing_auto_dispatch == False")?;
1316
1317        Ok(())
1318    }
1319
1320    #[test]
1321    fn test_multiprocessing_start_method() -> Result<()> {
1322        let mut env = get_env()?;
1323
1324        eval_assert(&mut env, "config.multiprocessing_start_method == 'auto'")?;
1325
1326        env.eval("config.multiprocessing_start_method = 'none'")?;
1327        eval_assert(&mut env, "config.multiprocessing_start_method == 'none'")?;
1328
1329        env.eval("config.multiprocessing_start_method = 'fork'")?;
1330        eval_assert(&mut env, "config.multiprocessing_start_method == 'fork'")?;
1331
1332        env.eval("config.multiprocessing_start_method = 'forkserver'")?;
1333        eval_assert(
1334            &mut env,
1335            "config.multiprocessing_start_method == 'forkserver'",
1336        )?;
1337
1338        env.eval("config.multiprocessing_start_method = 'spawn'")?;
1339        eval_assert(&mut env, "config.multiprocessing_start_method == 'spawn'")?;
1340
1341        env.eval("config.multiprocessing_start_method = 'auto'")?;
1342        eval_assert(&mut env, "config.multiprocessing_start_method == 'auto'")?;
1343
1344        Ok(())
1345    }
1346
1347    #[test]
1348    fn test_sys_frozen() -> Result<()> {
1349        let mut env = get_env()?;
1350
1351        eval_assert(&mut env, "config.sys_frozen == True")?;
1352
1353        Ok(())
1354    }
1355
1356    #[test]
1357    fn test_sys_meipass() -> Result<()> {
1358        let mut env = get_env()?;
1359
1360        eval_assert(&mut env, "config.sys_meipass == False")?;
1361
1362        Ok(())
1363    }
1364
1365    #[test]
1366    fn test_terminfo_resolution() -> Result<()> {
1367        let mut env = get_env()?;
1368
1369        eval_assert(&mut env, "config.terminfo_resolution == 'dynamic'")?;
1370
1371        env.eval("config.terminfo_resolution = 'none'")?;
1372        eval_assert(&mut env, "config.terminfo_resolution == 'none'")?;
1373
1374        env.eval("config.terminfo_resolution = 'static:foo'")?;
1375        eval_assert(&mut env, "config.terminfo_resolution == 'static:foo'")?;
1376
1377        Ok(())
1378    }
1379
1380    #[test]
1381    fn test_write_modules_directory_env() -> Result<()> {
1382        let mut env = get_env()?;
1383
1384        eval_assert(&mut env, "config.write_modules_directory_env == None")?;
1385
1386        Ok(())
1387    }
1388}