@azure-tools/typespec-python 0.24.3 → 0.25.0
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.
- package/dist/src/code-model.d.ts.map +1 -1
- package/dist/src/code-model.js +1 -4
- package/dist/src/code-model.js.map +1 -1
- package/dist/src/emitter.d.ts.map +1 -1
- package/dist/src/emitter.js +5 -4
- package/dist/src/emitter.js.map +1 -1
- package/dist/src/external-process.d.ts +0 -9
- package/dist/src/external-process.d.ts.map +1 -1
- package/dist/src/external-process.js +1 -25
- package/dist/src/external-process.js.map +1 -1
- package/dist/src/types.d.ts.map +1 -1
- package/dist/src/types.js +2 -0
- package/dist/src/types.js.map +1 -1
- package/generator/LICENSE +21 -0
- package/generator/README.md +1 -0
- package/generator/dev_requirements.txt +5 -0
- package/generator/pygen/__init__.py +107 -0
- package/generator/pygen/_version.py +7 -0
- package/generator/pygen/black.py +71 -0
- package/generator/pygen/codegen/__init__.py +334 -0
- package/generator/pygen/codegen/_utils.py +16 -0
- package/generator/pygen/codegen/models/__init__.py +202 -0
- package/generator/pygen/codegen/models/base.py +186 -0
- package/generator/pygen/codegen/models/base_builder.py +119 -0
- package/generator/pygen/codegen/models/client.py +429 -0
- package/generator/pygen/codegen/models/code_model.py +239 -0
- package/generator/pygen/codegen/models/combined_type.py +149 -0
- package/generator/pygen/codegen/models/constant_type.py +129 -0
- package/generator/pygen/codegen/models/credential_types.py +221 -0
- package/generator/pygen/codegen/models/dictionary_type.py +127 -0
- package/generator/pygen/codegen/models/enum_type.py +238 -0
- package/generator/pygen/codegen/models/imports.py +291 -0
- package/generator/pygen/codegen/models/list_type.py +143 -0
- package/generator/pygen/codegen/models/lro_operation.py +143 -0
- package/generator/pygen/codegen/models/lro_paging_operation.py +32 -0
- package/generator/pygen/codegen/models/model_type.py +361 -0
- package/generator/pygen/codegen/models/operation.py +518 -0
- package/generator/pygen/codegen/models/operation_group.py +184 -0
- package/generator/pygen/codegen/models/paging_operation.py +156 -0
- package/generator/pygen/codegen/models/parameter.py +402 -0
- package/generator/pygen/codegen/models/parameter_list.py +390 -0
- package/generator/pygen/codegen/models/primitive_types.py +626 -0
- package/generator/pygen/codegen/models/property.py +175 -0
- package/generator/pygen/codegen/models/request_builder.py +189 -0
- package/generator/pygen/codegen/models/request_builder_parameter.py +115 -0
- package/generator/pygen/codegen/models/response.py +348 -0
- package/generator/pygen/codegen/models/utils.py +23 -0
- package/generator/pygen/codegen/serializers/__init__.py +570 -0
- package/generator/pygen/codegen/serializers/base_serializer.py +21 -0
- package/generator/pygen/codegen/serializers/builder_serializer.py +1454 -0
- package/generator/pygen/codegen/serializers/client_serializer.py +295 -0
- package/generator/pygen/codegen/serializers/enum_serializer.py +15 -0
- package/generator/pygen/codegen/serializers/general_serializer.py +212 -0
- package/generator/pygen/codegen/serializers/import_serializer.py +127 -0
- package/generator/pygen/codegen/serializers/metadata_serializer.py +198 -0
- package/generator/pygen/codegen/serializers/model_init_serializer.py +33 -0
- package/generator/pygen/codegen/serializers/model_serializer.py +287 -0
- package/generator/pygen/codegen/serializers/operation_groups_serializer.py +89 -0
- package/generator/pygen/codegen/serializers/operations_init_serializer.py +44 -0
- package/generator/pygen/codegen/serializers/parameter_serializer.py +221 -0
- package/generator/pygen/codegen/serializers/patch_serializer.py +19 -0
- package/generator/pygen/codegen/serializers/request_builders_serializer.py +52 -0
- package/generator/pygen/codegen/serializers/sample_serializer.py +163 -0
- package/generator/pygen/codegen/serializers/test_serializer.py +287 -0
- package/generator/pygen/codegen/serializers/types_serializer.py +31 -0
- package/generator/pygen/codegen/serializers/utils.py +68 -0
- package/generator/pygen/codegen/templates/client.py.jinja2 +37 -0
- package/generator/pygen/codegen/templates/client_container.py.jinja2 +12 -0
- package/generator/pygen/codegen/templates/config.py.jinja2 +73 -0
- package/generator/pygen/codegen/templates/config_container.py.jinja2 +16 -0
- package/generator/pygen/codegen/templates/conftest.py.jinja2 +28 -0
- package/generator/pygen/codegen/templates/enum.py.jinja2 +13 -0
- package/generator/pygen/codegen/templates/enum_container.py.jinja2 +10 -0
- package/generator/pygen/codegen/templates/init.py.jinja2 +24 -0
- package/generator/pygen/codegen/templates/keywords.jinja2 +19 -0
- package/generator/pygen/codegen/templates/lro_operation.py.jinja2 +16 -0
- package/generator/pygen/codegen/templates/lro_paging_operation.py.jinja2 +18 -0
- package/generator/pygen/codegen/templates/macros.jinja2 +12 -0
- package/generator/pygen/codegen/templates/metadata.json.jinja2 +167 -0
- package/generator/pygen/codegen/templates/model_base.py.jinja2 +899 -0
- package/generator/pygen/codegen/templates/model_container.py.jinja2 +13 -0
- package/generator/pygen/codegen/templates/model_dpg.py.jinja2 +92 -0
- package/generator/pygen/codegen/templates/model_init.py.jinja2 +28 -0
- package/generator/pygen/codegen/templates/model_msrest.py.jinja2 +92 -0
- package/generator/pygen/codegen/templates/operation.py.jinja2 +21 -0
- package/generator/pygen/codegen/templates/operation_group.py.jinja2 +75 -0
- package/generator/pygen/codegen/templates/operation_groups_container.py.jinja2 +20 -0
- package/generator/pygen/codegen/templates/operation_tools.jinja2 +74 -0
- package/generator/pygen/codegen/templates/operations_folder_init.py.jinja2 +17 -0
- package/generator/pygen/codegen/templates/packaging_templates/CHANGELOG.md.jinja2 +6 -0
- package/generator/pygen/codegen/templates/packaging_templates/LICENSE.jinja2 +21 -0
- package/generator/pygen/codegen/templates/packaging_templates/MANIFEST.in.jinja2 +8 -0
- package/generator/pygen/codegen/templates/packaging_templates/README.md.jinja2 +107 -0
- package/generator/pygen/codegen/templates/packaging_templates/dev_requirements.txt.jinja2 +9 -0
- package/generator/pygen/codegen/templates/packaging_templates/setup.py.jinja2 +108 -0
- package/generator/pygen/codegen/templates/paging_operation.py.jinja2 +21 -0
- package/generator/pygen/codegen/templates/patch.py.jinja2 +19 -0
- package/generator/pygen/codegen/templates/pkgutil_init.py.jinja2 +1 -0
- package/generator/pygen/codegen/templates/request_builder.py.jinja2 +28 -0
- package/generator/pygen/codegen/templates/request_builders.py.jinja2 +10 -0
- package/generator/pygen/codegen/templates/rest_init.py.jinja2 +12 -0
- package/generator/pygen/codegen/templates/sample.py.jinja2 +44 -0
- package/generator/pygen/codegen/templates/serialization.py.jinja2 +2006 -0
- package/generator/pygen/codegen/templates/test.py.jinja2 +50 -0
- package/generator/pygen/codegen/templates/testpreparer.py.jinja2 +26 -0
- package/generator/pygen/codegen/templates/types.py.jinja2 +8 -0
- package/generator/pygen/codegen/templates/validation.py.jinja2 +38 -0
- package/generator/pygen/codegen/templates/vendor.py.jinja2 +98 -0
- package/generator/pygen/codegen/templates/version.py.jinja2 +4 -0
- package/generator/pygen/m2r.py +65 -0
- package/generator/pygen/postprocess/__init__.py +183 -0
- package/generator/pygen/postprocess/get_all.py +19 -0
- package/generator/pygen/postprocess/venvtools.py +77 -0
- package/generator/pygen/preprocess/__init__.py +503 -0
- package/generator/pygen/preprocess/helpers.py +27 -0
- package/generator/pygen/preprocess/python_mappings.py +222 -0
- package/generator/pygen/utils.py +149 -0
- package/generator/pygen.egg-info/PKG-INFO +25 -0
- package/generator/pygen.egg-info/SOURCES.txt +66 -0
- package/generator/pygen.egg-info/dependency_links.txt +1 -0
- package/generator/pygen.egg-info/requires.txt +4 -0
- package/generator/pygen.egg-info/top_level.txt +1 -0
- package/generator/requirements.txt +12 -0
- package/generator/setup.py +55 -0
- package/package.json +10 -7
- package/scripts/__pycache__/venvtools.cpython-38.pyc +0 -0
- package/scripts/install.py +49 -0
- package/scripts/prepare.py +38 -0
- package/scripts/run-python3.cjs +22 -0
- package/scripts/run_tsp.py +40 -0
- package/scripts/system-requirements.cjs +180 -0
- package/scripts/venvtools.py +81 -0
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
// This script wraps logic in @azure-tools/extension to resolve
|
|
2
|
+
// the path to Python 3 so that a Python script file can be run
|
|
3
|
+
// from an npm script in package.json. It uses the same Python 3
|
|
4
|
+
// path resolution algorithm as AutoRest so that the behavior
|
|
5
|
+
// is fully consistent (and also supports AUTOREST_PYTHON_EXE).
|
|
6
|
+
//
|
|
7
|
+
// Invoke it like so: "node run-python3.cjs script.py"
|
|
8
|
+
|
|
9
|
+
const cp = require("child_process");
|
|
10
|
+
const extension = require("./system-requirements.cjs");
|
|
11
|
+
|
|
12
|
+
async function runPython3(scriptName, ...args) {
|
|
13
|
+
const command = await extension.patchPythonPath(["python", scriptName, ...args], { version: ">=3.8", environmentVariable: "AUTOREST_PYTHON_EXE" });
|
|
14
|
+
cp.execSync(command.join(" "), {
|
|
15
|
+
stdio: [0, 1, 2]
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
runPython3(...process.argv.slice(2)).catch(err => {
|
|
20
|
+
console.error(err.toString());
|
|
21
|
+
process.exit(1);
|
|
22
|
+
});
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# -------------------------------------------------------------------------
|
|
2
|
+
# Copyright (c) Microsoft Corporation. All rights reserved.
|
|
3
|
+
# Licensed under the MIT License. See License.txt in the project root for
|
|
4
|
+
# license information.
|
|
5
|
+
# --------------------------------------------------------------------------
|
|
6
|
+
import sys
|
|
7
|
+
import venv
|
|
8
|
+
import logging
|
|
9
|
+
from pathlib import Path
|
|
10
|
+
from venvtools import python_run
|
|
11
|
+
|
|
12
|
+
_ROOT_DIR = Path(__file__).parent.parent
|
|
13
|
+
|
|
14
|
+
_LOGGER = logging.getLogger(__name__)
|
|
15
|
+
|
|
16
|
+
if __name__ == "__main__":
|
|
17
|
+
venv_path = _ROOT_DIR / "venv"
|
|
18
|
+
venv_prexists = venv_path.exists()
|
|
19
|
+
|
|
20
|
+
assert venv_prexists # Otherwise install was not done
|
|
21
|
+
|
|
22
|
+
env_builder = venv.EnvBuilder(with_pip=True)
|
|
23
|
+
venv_context = env_builder.ensure_directories(venv_path)
|
|
24
|
+
|
|
25
|
+
if "--debug" in sys.argv or "--debug=true" in sys.argv:
|
|
26
|
+
try:
|
|
27
|
+
import debugpy # pylint: disable=import-outside-toplevel
|
|
28
|
+
except ImportError:
|
|
29
|
+
raise SystemExit("Please pip install ptvsd in order to use VSCode debugging")
|
|
30
|
+
|
|
31
|
+
# 5678 is the default attach port in the VS Code debug configurations
|
|
32
|
+
debugpy.listen(("localhost", 5678))
|
|
33
|
+
debugpy.wait_for_client()
|
|
34
|
+
breakpoint() # pylint: disable=undefined-variable
|
|
35
|
+
|
|
36
|
+
# run m2r
|
|
37
|
+
python_run(venv_context, "generator.pygen.m2r", command=sys.argv[1:])
|
|
38
|
+
python_run(venv_context, "generator.pygen.preprocess.__init__", command=sys.argv[1:])
|
|
39
|
+
python_run(venv_context, "generator.pygen.codegen.__init__", command=sys.argv[1:])
|
|
40
|
+
python_run(venv_context, "generator.pygen.black", command=sys.argv[1:])
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
const semver = require("semver");
|
|
2
|
+
const child_process = require("child_process");
|
|
3
|
+
|
|
4
|
+
/*
|
|
5
|
+
* Copied from @autorest/system-requirements
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
const PythonRequirement = "python";
|
|
9
|
+
const PRINT_PYTHON_VERSION_SCRIPT = "import sys; print('.'.join(map(str, sys.version_info[:3])))";
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
function execute(command, cmdlineargs, options = {}) {
|
|
13
|
+
return new Promise((resolve, reject) => {
|
|
14
|
+
const cp = child_process.spawn(command, cmdlineargs, { ...options, stdio: "pipe", shell: true });
|
|
15
|
+
if (options.onCreate) {
|
|
16
|
+
options.onCreate(cp);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
options.onStdOutData ? cp.stdout.on("data", options.onStdOutData) : cp;
|
|
20
|
+
options.onStdErrData ? cp.stderr.on("data", options.onStdErrData) : cp;
|
|
21
|
+
|
|
22
|
+
let err = "";
|
|
23
|
+
let out = "";
|
|
24
|
+
let all = "";
|
|
25
|
+
cp.stderr.on("data", (chunk) => {
|
|
26
|
+
err += chunk;
|
|
27
|
+
all += chunk;
|
|
28
|
+
});
|
|
29
|
+
cp.stdout.on("data", (chunk) => {
|
|
30
|
+
out += chunk;
|
|
31
|
+
all += chunk;
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
cp.on("error", (err) => {
|
|
35
|
+
reject(err);
|
|
36
|
+
});
|
|
37
|
+
cp.on("close", (code, signal) =>
|
|
38
|
+
resolve({
|
|
39
|
+
stdout: out,
|
|
40
|
+
stderr: err,
|
|
41
|
+
log: all,
|
|
42
|
+
error: code ? new Error("Process Failed.") : null,
|
|
43
|
+
code,
|
|
44
|
+
}),
|
|
45
|
+
);
|
|
46
|
+
});
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
function versionIsSatisfied(version, requirement) {
|
|
50
|
+
const cleanedVersion = semver.coerce(version);
|
|
51
|
+
if (!cleanedVersion) {
|
|
52
|
+
throw new Error(`Invalid version ${version}.`);
|
|
53
|
+
}
|
|
54
|
+
return semver.satisfies(cleanedVersion, requirement, true);
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Validate the provided system requirement resolution is satisfying the version requirement if applicable.
|
|
59
|
+
* @param resolution Command resolution.
|
|
60
|
+
* @param actualVersion Version for that resolution.
|
|
61
|
+
* @param requirement Requirement.
|
|
62
|
+
* @returns the resolution if it is valid or an @see SystemRequirementError if not.
|
|
63
|
+
*/
|
|
64
|
+
function validateVersionRequirement(resolution, actualVersion, requirement) {
|
|
65
|
+
if (!requirement.version) {
|
|
66
|
+
return resolution; // No version requirement.
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
try {
|
|
70
|
+
if (versionIsSatisfied(actualVersion, requirement.version)) {
|
|
71
|
+
return resolution;
|
|
72
|
+
}
|
|
73
|
+
return {
|
|
74
|
+
...resolution,
|
|
75
|
+
error: true,
|
|
76
|
+
message: `'${resolution.command}' version is '${actualVersion}' but doesn't satisfy requirement '${requirement.version}'. Please update.`,
|
|
77
|
+
actualVersion: actualVersion,
|
|
78
|
+
neededVersion: requirement.version,
|
|
79
|
+
};
|
|
80
|
+
} catch {
|
|
81
|
+
return {
|
|
82
|
+
...resolution,
|
|
83
|
+
error: true,
|
|
84
|
+
message: `Couldn't parse the version ${actualVersion}. This is not a valid semver version.`,
|
|
85
|
+
actualVersion: actualVersion,
|
|
86
|
+
neededVersion: requirement.version,
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
async function tryPython(requirement, command, additionalArgs = []) {
|
|
92
|
+
const resolution = {
|
|
93
|
+
name: PythonRequirement,
|
|
94
|
+
command,
|
|
95
|
+
additionalArgs: additionalArgs.length > 0 ? additionalArgs : undefined,
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
try {
|
|
99
|
+
const result = await execute(command, [...additionalArgs, "-c", `"${PRINT_PYTHON_VERSION_SCRIPT}"`]);
|
|
100
|
+
return validateVersionRequirement(resolution, result.stdout.trim(), requirement);
|
|
101
|
+
} catch (e) {
|
|
102
|
+
return {
|
|
103
|
+
error: true,
|
|
104
|
+
...resolution,
|
|
105
|
+
message: `'${command}' command line is not found in the path. Make sure to have it installed.`,
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Returns the path to the executable as asked in the requirement.
|
|
112
|
+
* @param requirement System requirement definition.
|
|
113
|
+
* @returns If the requirement provide an environment variable for the path returns the value of that environment variable. undefined otherwise.
|
|
114
|
+
*/
|
|
115
|
+
function getExecutablePath(requirement) {
|
|
116
|
+
return requirement.environmentVariable && process.env[requirement.environmentVariable];
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
function createPythonErrorMessage(requirement, errors) {
|
|
120
|
+
const versionReq = requirement.version ?? "*";
|
|
121
|
+
const lines = [
|
|
122
|
+
`Couldn't find a valid python interpreter satisfying the requirement (version: ${versionReq}). Tried:`,
|
|
123
|
+
...errors.map((x) => ` - ${x.command} (${x.message})`),
|
|
124
|
+
];
|
|
125
|
+
|
|
126
|
+
return {
|
|
127
|
+
error: true,
|
|
128
|
+
name: "python",
|
|
129
|
+
command: "python",
|
|
130
|
+
message: lines.join("\n"),
|
|
131
|
+
};
|
|
132
|
+
};
|
|
133
|
+
|
|
134
|
+
async function resolvePythonRequirement(requirement) {
|
|
135
|
+
const path = getExecutablePath(requirement) ?? process.env["AUTOREST_PYTHON_EXE"];
|
|
136
|
+
if (path) {
|
|
137
|
+
return await tryPython(requirement, path);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
const errors = [];
|
|
141
|
+
// On windows try `py` executable with `-3` flag.
|
|
142
|
+
if (process.platform === "win32") {
|
|
143
|
+
const pyResult = await tryPython(requirement, "py", ["-3"]);
|
|
144
|
+
if ("error" in pyResult) {
|
|
145
|
+
errors.push(pyResult);
|
|
146
|
+
} else {
|
|
147
|
+
return pyResult;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
const python3Result = await tryPython(requirement, "python3");
|
|
152
|
+
if ("error" in python3Result) {
|
|
153
|
+
errors.push(python3Result);
|
|
154
|
+
} else {
|
|
155
|
+
return python3Result;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
const pythonResult = await tryPython(requirement, "python");
|
|
159
|
+
if ("error" in pythonResult) {
|
|
160
|
+
errors.push(pythonResult);
|
|
161
|
+
} else {
|
|
162
|
+
return pythonResult;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
return createPythonErrorMessage(requirement, errors);
|
|
166
|
+
};
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* @param command list of the command and arguments. First item in array must be a python exe @see KnownPythonExe. (e.g. ["python", "mypythonfile.py"]
|
|
170
|
+
* @param requirement
|
|
171
|
+
*/
|
|
172
|
+
async function patchPythonPath(command, requirement) {
|
|
173
|
+
const [_, ...args] = command;
|
|
174
|
+
const resolution = await resolvePythonRequirement(requirement);
|
|
175
|
+
if ("error" in resolution) {
|
|
176
|
+
throw new Error(`Failed to find compatible python version. ${resolution.message}`);
|
|
177
|
+
}
|
|
178
|
+
return [resolution.command, ...(resolution.additionalArgs ?? []), ...args];
|
|
179
|
+
};
|
|
180
|
+
module.exports.patchPythonPath = patchPythonPath;
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
# -------------------------------------------------------------------------
|
|
2
|
+
# Copyright (c) Microsoft Corporation. All rights reserved.
|
|
3
|
+
# Licensed under the MIT License. See License.txt in the project root for
|
|
4
|
+
# license information.
|
|
5
|
+
# --------------------------------------------------------------------------
|
|
6
|
+
from contextlib import contextmanager
|
|
7
|
+
import tempfile
|
|
8
|
+
import subprocess
|
|
9
|
+
import venv
|
|
10
|
+
import sys
|
|
11
|
+
from pathlib import Path
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
_ROOT_DIR = Path(__file__).parent.parent
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class ExtendedEnvBuilder(venv.EnvBuilder):
|
|
18
|
+
"""An extended env builder which saves the context, to have access
|
|
19
|
+
easily to bin path and such.
|
|
20
|
+
"""
|
|
21
|
+
|
|
22
|
+
def __init__(self, *args, **kwargs):
|
|
23
|
+
self.context = None
|
|
24
|
+
if sys.version_info < (3, 9, 0):
|
|
25
|
+
# Not supported on Python 3.8, and we don't need it
|
|
26
|
+
kwargs.pop("upgrade_deps", None)
|
|
27
|
+
super().__init__(*args, **kwargs)
|
|
28
|
+
|
|
29
|
+
def ensure_directories(self, env_dir):
|
|
30
|
+
self.context = super(ExtendedEnvBuilder, self).ensure_directories(env_dir)
|
|
31
|
+
return self.context
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def create(
|
|
35
|
+
env_dir, system_site_packages=False, clear=False, symlinks=False, with_pip=False, prompt=None, upgrade_deps=False
|
|
36
|
+
):
|
|
37
|
+
"""Create a virtual environment in a directory."""
|
|
38
|
+
builder = ExtendedEnvBuilder(
|
|
39
|
+
system_site_packages=system_site_packages,
|
|
40
|
+
clear=clear,
|
|
41
|
+
symlinks=symlinks,
|
|
42
|
+
with_pip=with_pip,
|
|
43
|
+
prompt=prompt,
|
|
44
|
+
upgrade_deps=upgrade_deps,
|
|
45
|
+
)
|
|
46
|
+
builder.create(env_dir)
|
|
47
|
+
return builder.context
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
@contextmanager
|
|
51
|
+
def create_venv_with_package(packages):
|
|
52
|
+
"""Create a venv with these packages in a temp dir and yielf the env.
|
|
53
|
+
|
|
54
|
+
packages should be an iterable of pip version instructio (e.g. package~=1.2.3)
|
|
55
|
+
"""
|
|
56
|
+
with tempfile.TemporaryDirectory() as tempdir:
|
|
57
|
+
myenv = create(tempdir, with_pip=True, upgrade_deps=True)
|
|
58
|
+
pip_call = [
|
|
59
|
+
myenv.env_exe,
|
|
60
|
+
"-m",
|
|
61
|
+
"pip",
|
|
62
|
+
"install",
|
|
63
|
+
]
|
|
64
|
+
subprocess.check_call(pip_call + ["-U", "pip"])
|
|
65
|
+
if packages:
|
|
66
|
+
subprocess.check_call(pip_call + packages)
|
|
67
|
+
yield myenv
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
def python_run(venv_context, module, command=None, *, additional_dir="."):
|
|
71
|
+
try:
|
|
72
|
+
cmd_line = [venv_context.env_exe, "-m", module] + (command if command else [])
|
|
73
|
+
print("Executing: {}".format(" ".join(cmd_line)))
|
|
74
|
+
subprocess.run(
|
|
75
|
+
cmd_line,
|
|
76
|
+
cwd=_ROOT_DIR / additional_dir,
|
|
77
|
+
check=True,
|
|
78
|
+
)
|
|
79
|
+
except subprocess.CalledProcessError as err:
|
|
80
|
+
print(err)
|
|
81
|
+
sys.exit(1)
|