Given the path to a .py file, return the path to its .pyc file. The .py file does not need to exist; this simply returns the path to the .pyc file calculated as if the .py file were imported. The 'optimization' parameter controls the presumed optimization level of the bytecode file
(path, debug_override=None, *, optimization=None)
| 237 | DEBUG_BYTECODE_SUFFIXES = OPTIMIZED_BYTECODE_SUFFIXES = BYTECODE_SUFFIXES |
| 238 | |
| 239 | def cache_from_source(path, debug_override=None, *, optimization=None): |
| 240 | """Given the path to a .py file, return the path to its .pyc file. |
| 241 | |
| 242 | The .py file does not need to exist; this simply returns the path to the |
| 243 | .pyc file calculated as if the .py file were imported. |
| 244 | |
| 245 | The 'optimization' parameter controls the presumed optimization level of |
| 246 | the bytecode file. If 'optimization' is not None, the string representation |
| 247 | of the argument is taken and verified to be alphanumeric (else ValueError |
| 248 | is raised). |
| 249 | |
| 250 | The debug_override parameter is deprecated. If debug_override is not None, |
| 251 | a True value is the same as setting 'optimization' to the empty string |
| 252 | while a False value is equivalent to setting 'optimization' to '1'. |
| 253 | |
| 254 | If sys.implementation.cache_tag is None then NotImplementedError is raised. |
| 255 | |
| 256 | """ |
| 257 | if debug_override is not None: |
| 258 | _warnings.warn('the debug_override parameter is deprecated; use ' |
| 259 | "'optimization' instead", DeprecationWarning) |
| 260 | if optimization is not None: |
| 261 | message = 'debug_override or optimization must be set to None' |
| 262 | raise TypeError(message) |
| 263 | optimization = '' if debug_override else 1 |
| 264 | path = _os.fspath(path) |
| 265 | head, tail = _path_split(path) |
| 266 | base, sep, rest = tail.rpartition('.') |
| 267 | tag = sys.implementation.cache_tag |
| 268 | if tag is None: |
| 269 | raise NotImplementedError('sys.implementation.cache_tag is None') |
| 270 | almost_filename = ''.join([(base if base else rest), sep, tag]) |
| 271 | if optimization is None: |
| 272 | if sys.flags.optimize == 0: |
| 273 | optimization = '' |
| 274 | else: |
| 275 | optimization = sys.flags.optimize |
| 276 | optimization = str(optimization) |
| 277 | if optimization != '': |
| 278 | if not optimization.isalnum(): |
| 279 | raise ValueError(f'{optimization!r} is not alphanumeric') |
| 280 | almost_filename = f'{almost_filename}.{_OPT}{optimization}' |
| 281 | filename = almost_filename + BYTECODE_SUFFIXES[0] |
| 282 | if sys.pycache_prefix is not None: |
| 283 | # We need an absolute path to the py file to avoid the possibility of |
| 284 | # collisions within sys.pycache_prefix, if someone has two different |
| 285 | # `foo/bar.py` on their system and they import both of them using the |
| 286 | # same sys.pycache_prefix. Let's say sys.pycache_prefix is |
| 287 | # `C:\Bytecode`; the idea here is that if we get `Foo\Bar`, we first |
| 288 | # make it absolute (`C:\Somewhere\Foo\Bar`), then make it root-relative |
| 289 | # (`Somewhere\Foo\Bar`), so we end up placing the bytecode file in an |
| 290 | # unambiguous `C:\Bytecode\Somewhere\Foo\Bar\`. |
| 291 | head = _path_abspath(head) |
| 292 | |
| 293 | # Strip initial drive from a Windows path. We know we have an absolute |
| 294 | # path here, so the second part of the check rules out a POSIX path that |
| 295 | # happens to contain a colon at the second character. |
| 296 | # Slicing avoids issues with an empty (or short) `head`. |