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, *, optimization=None)
| 237 | DEBUG_BYTECODE_SUFFIXES = OPTIMIZED_BYTECODE_SUFFIXES = BYTECODE_SUFFIXES |
| 238 | |
| 239 | def cache_from_source(path, *, 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 | If sys.implementation.cache_tag is None then NotImplementedError is raised. |
| 251 | |
| 252 | """ |
| 253 | path = _os.fspath(path) |
| 254 | head, tail = _path_split(path) |
| 255 | base, sep, rest = tail.rpartition('.') |
| 256 | tag = sys.implementation.cache_tag |
| 257 | if tag is None: |
| 258 | raise NotImplementedError('sys.implementation.cache_tag is None') |
| 259 | almost_filename = ''.join([(base if base else rest), sep, tag]) |
| 260 | if optimization is None: |
| 261 | if sys.flags.optimize == 0: |
| 262 | optimization = '' |
| 263 | else: |
| 264 | optimization = sys.flags.optimize |
| 265 | optimization = str(optimization) |
| 266 | if optimization != '': |
| 267 | if not optimization.isalnum(): |
| 268 | raise ValueError(f'{optimization!r} is not alphanumeric') |
| 269 | almost_filename = f'{almost_filename}.{_OPT}{optimization}' |
| 270 | filename = almost_filename + BYTECODE_SUFFIXES[0] |
| 271 | if sys.pycache_prefix is not None: |
| 272 | # We need an absolute path to the py file to avoid the possibility of |
| 273 | # collisions within sys.pycache_prefix, if someone has two different |
| 274 | # `foo/bar.py` on their system and they import both of them using the |
| 275 | # same sys.pycache_prefix. Let's say sys.pycache_prefix is |
| 276 | # `C:\Bytecode`; the idea here is that if we get `Foo\Bar`, we first |
| 277 | # make it absolute (`C:\Somewhere\Foo\Bar`), then make it root-relative |
| 278 | # (`Somewhere\Foo\Bar`), so we end up placing the bytecode file in an |
| 279 | # unambiguous `C:\Bytecode\Somewhere\Foo\Bar\`. |
| 280 | head = _path_abspath(head) |
| 281 | |
| 282 | # Strip initial drive from a Windows path. We know we have an absolute |
| 283 | # path here, so the second part of the check rules out a POSIX path that |
| 284 | # happens to contain a colon at the second character. |
| 285 | # Slicing avoids issues with an empty (or short) `head`. |
| 286 | if head[1:2] == ':' and head[0:1] not in path_separators: |
| 287 | head = head[2:] |
| 288 | |
| 289 | # Strip initial path separator from `head` to complete the conversion |
| 290 | # back to a root-relative path before joining. |
| 291 | return _path_join( |
| 292 | sys.pycache_prefix, |
| 293 | head.lstrip(path_separators), |
| 294 | filename, |
| 295 | ) |
| 296 | return _path_join(head, _PYCACHE, filename) |
searching dependent graphs…