Nuitka
The Python compiler
Loading...
Searching...
No Matches
MetaPathBasedLoaderImportlibMetadataDistribution.c
1// Copyright 2026, Kay Hayen, mailto:kay.hayen@gmail.com find license text at end of file
2
3// This implements the "importlib.metadata.distribution" values, also for
4// the backport "importlib_metadata.distribution"
5
6// This file is included from another C file, help IDEs to still parse it on
7// its own.
8#ifdef __IDE_ONLY__
9#include "nuitka/prelude.h"
10#include "nuitka/unfreezing.h"
11#endif
12
13static PyObject *metadata_values_dict = NULL;
14
15// For initialization of the metadata dictionary during startup.
16void setDistributionsMetadata(PyThreadState *tstate, PyObject *metadata_values) {
17 metadata_values_dict = MAKE_DICT_EMPTY(tstate);
18
19 // We get the items passed, and need to add it to the dictionary.
20 int res = PyDict_MergeFromSeq2(metadata_values_dict, metadata_values, 1);
21
22 if (res != 0) {
23 NUITKA_CANNOT_GET_HERE("Failed to setup distributions metadata");
24 }
25
26 // PRINT_ITEM(metadata_values_dict);
27 // PRINT_NEW_LINE();
28}
29
30bool Nuitka_DistributionNext(Py_ssize_t *pos, PyObject **distribution_name_ptr) {
31 PyObject *value;
32 return Nuitka_DictNext(metadata_values_dict, pos, distribution_name_ptr, &value);
33}
34
35PyObject *Nuitka_Distribution_New(PyThreadState *tstate, PyObject *name) {
36 // TODO: Have our own Python code to be included in compiled form,
37 // this duplicates with inspec patcher code.
38 static PyObject *nuitka_distribution_type = NULL;
39 static PyObject *importlib_metadata_distribution = NULL;
40 // TODO: Use pathlib.Path for "locate_file" result should be more compatible.
41
42 if (nuitka_distribution_type == NULL) {
43 static char const *nuitka_distribution_code = "\n\
44import os,sys\n\
45if sys.version_info >= (3, 8):\n\
46 from importlib.metadata import Distribution,distribution\n\
47else:\n\
48 from importlib_metadata import Distribution,distribution\n\
49class nuitka_distribution(Distribution):\n\
50 def __init__(self, package_name, path, metadata, entry_points):\n\
51 self.package_name = package_name; self._path = path\n\
52 self.metadata_data = metadata; self.entry_points_data = entry_points\n\
53 def read_text(self, filename):\n\
54 if filename == 'METADATA':\n\
55 return self.metadata_data\n\
56 elif filename == 'entry_points.txt':\n\
57 return self.entry_points_data\n\
58 elif filename == 'top_level.txt':\n\
59 return self.package_name + '\\n'\n\
60 def locate_file(self, path):\n\
61 return os.path.join(self._path, path)\n\
62";
63
64 PyObject *nuitka_distribution_code_object = Py_CompileString(nuitka_distribution_code, "<exec>", Py_file_input);
65 CHECK_OBJECT(nuitka_distribution_code_object);
66
67 {
68 PyObject *module =
69 PyImport_ExecCodeModule((char *)"nuitka_distribution_patch", nuitka_distribution_code_object);
70 CHECK_OBJECT(module);
71
72 nuitka_distribution_type = PyObject_GetAttrString(module, "nuitka_distribution");
73 CHECK_OBJECT(nuitka_distribution_type);
74
75 importlib_metadata_distribution = PyObject_GetAttrString(module, "distribution");
76 CHECK_OBJECT(importlib_metadata_distribution);
77
78 {
79 NUITKA_MAY_BE_UNUSED bool bool_res = Nuitka_DelModuleString(tstate, "nuitka_distribution_patch");
80 assert(bool_res != false);
81 }
82
83 Py_DECREF(module);
84 }
85 }
86
87 PyObject *metadata_value_item = DICT_GET_ITEM0(tstate, metadata_values_dict, name);
88 if (metadata_value_item == NULL) {
89 PyObject *result = CALL_FUNCTION_WITH_SINGLE_ARG(tstate, importlib_metadata_distribution, name);
90
91 return result;
92 } else {
93 PyObject *package_name = PyTuple_GET_ITEM(metadata_value_item, 0);
94 PyObject *metadata = PyTuple_GET_ITEM(metadata_value_item, 1);
95 PyObject *entry_points = PyTuple_GET_ITEM(metadata_value_item, 2);
96
97 struct Nuitka_MetaPathBasedLoaderEntry *entry = findEntry(Nuitka_String_AsString_Unchecked(package_name));
98
99 if (unlikely(entry == NULL)) {
100 SET_CURRENT_EXCEPTION_TYPE0_FORMAT1(PyExc_RuntimeError,
101 "cannot locate package '%s' associated with metadata",
102 Nuitka_String_AsString(package_name));
103
104 return NULL;
105 }
106
107 PyObject *args[4] = {package_name, getModuleDirectory(tstate, entry), metadata, entry_points};
108 PyObject *result = CALL_FUNCTION_WITH_ARGS4(tstate, nuitka_distribution_type, args);
109 CHECK_OBJECT(result);
110 return result;
111 }
112}
113
114// Part of "Nuitka", an optimizing Python compiler that is compatible and
115// integrates with CPython, but also works on its own.
116//
117// Licensed under the GNU Affero General Public License, Version 3 (the "License");
118// you may not use this file except in compliance with the License.
119// You may obtain a copy of the License at
120//
121// http://www.gnu.org/licenses/agpl.txt
122//
123// Unless required by applicable law or agreed to in writing, software
124// distributed under the License is distributed on an "AS IS" BASIS,
125// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
126// See the License for the specific language governing permissions and
127// limitations under the License.
Definition unfreezing.h:36