|
1 | | -from . import util |
| 1 | +from . import util |
2 | 2 | abc = util.import_importlib('importlib.abc') |
3 | 3 | init = util.import_importlib('importlib') |
4 | 4 | machinery = util.import_importlib('importlib.machinery') |
5 | 5 | importlib_util = util.import_importlib('importlib.util') |
6 | 6 |
|
| 7 | +import contextlib |
7 | 8 | import importlib.util |
8 | 9 | import os |
9 | 10 | import pathlib |
|
12 | 13 | from test import support |
13 | 14 | import types |
14 | 15 | import unittest |
| 16 | +import unittest.mock |
15 | 17 | import warnings |
16 | 18 |
|
17 | 19 |
|
@@ -557,8 +559,8 @@ class PEP3147Tests: |
557 | 559 |
|
558 | 560 | tag = sys.implementation.cache_tag |
559 | 561 |
|
560 | | - @unittest.skipUnless(sys.implementation.cache_tag is not None, |
561 | | - 'requires sys.implementation.cache_tag not be None') |
| 562 | + @unittest.skipIf(sys.implementation.cache_tag is None, |
| 563 | + 'requires sys.implementation.cache_tag not be None') |
562 | 564 | def test_cache_from_source(self): |
563 | 565 | # Given the path to a .py file, return the path to its PEP 3147 |
564 | 566 | # defined .pyc file (i.e. under __pycache__). |
@@ -678,18 +680,17 @@ def test_sep_altsep_and_sep_cache_from_source(self): |
678 | 680 | self.util.cache_from_source('\\foo\\bar\\baz/qux.py', optimization=''), |
679 | 681 | '\\foo\\bar\\baz\\__pycache__\\qux.{}.pyc'.format(self.tag)) |
680 | 682 |
|
681 | | - @unittest.skipUnless(sys.implementation.cache_tag is not None, |
682 | | - 'requires sys.implementation.cache_tag not be None') |
| 683 | + @unittest.skipIf(sys.implementation.cache_tag is None, |
| 684 | + 'requires sys.implementation.cache_tag not be None') |
683 | 685 | def test_source_from_cache_path_like_arg(self): |
684 | 686 | path = pathlib.PurePath('foo', 'bar', 'baz', 'qux.py') |
685 | 687 | expect = os.path.join('foo', 'bar', 'baz', '__pycache__', |
686 | 688 | 'qux.{}.pyc'.format(self.tag)) |
687 | 689 | self.assertEqual(self.util.cache_from_source(path, optimization=''), |
688 | 690 | expect) |
689 | 691 |
|
690 | | - @unittest.skipUnless(sys.implementation.cache_tag is not None, |
691 | | - 'requires sys.implementation.cache_tag to not be ' |
692 | | - 'None') |
| 692 | + @unittest.skipIf(sys.implementation.cache_tag is None, |
| 693 | + 'requires sys.implementation.cache_tag to not be None') |
693 | 694 | def test_source_from_cache(self): |
694 | 695 | # Given the path to a PEP 3147 defined .pyc file, return the path to |
695 | 696 | # its source. This tests the good path. |
@@ -749,15 +750,87 @@ def test_source_from_cache_missing_optimization(self): |
749 | 750 | with self.assertRaises(ValueError): |
750 | 751 | self.util.source_from_cache(path) |
751 | 752 |
|
752 | | - @unittest.skipUnless(sys.implementation.cache_tag is not None, |
753 | | - 'requires sys.implementation.cache_tag to not be ' |
754 | | - 'None') |
| 753 | + @unittest.skipIf(sys.implementation.cache_tag is None, |
| 754 | + 'requires sys.implementation.cache_tag to not be None') |
755 | 755 | def test_source_from_cache_path_like_arg(self): |
756 | 756 | path = pathlib.PurePath('foo', 'bar', 'baz', '__pycache__', |
757 | 757 | 'qux.{}.pyc'.format(self.tag)) |
758 | 758 | expect = os.path.join('foo', 'bar', 'baz', 'qux.py') |
759 | 759 | self.assertEqual(self.util.source_from_cache(path), expect) |
760 | 760 |
|
| 761 | + @unittest.skipIf(sys.implementation.cache_tag is None, |
| 762 | + 'requires sys.implementation.cache_tag to not be None') |
| 763 | + def test_cache_from_source_respects_pycache_prefix(self): |
| 764 | + # If pycache_prefix is set, cache_from_source will return a bytecode |
| 765 | + # path inside that directory (in a subdirectory mirroring the .py file's |
| 766 | + # path) rather than in a __pycache__ dir next to the py file. |
| 767 | + pycache_prefixes = [ |
| 768 | + os.path.join(os.path.sep, 'tmp', 'bytecode'), |
| 769 | + os.path.join(os.path.sep, 'tmp', '\u2603'), # non-ASCII in path! |
| 770 | + os.path.join(os.path.sep, 'tmp', 'trailing-slash') + os.path.sep, |
| 771 | + ] |
| 772 | + drive = '' |
| 773 | + if os.name == 'nt': |
| 774 | + drive = 'C:' |
| 775 | + pycache_prefixes = [ |
| 776 | + f'{drive}{prefix}' for prefix in pycache_prefixes] |
| 777 | + pycache_prefixes += [r'\\?\C:\foo', r'\\localhost\c$\bar'] |
| 778 | + for pycache_prefix in pycache_prefixes: |
| 779 | + with self.subTest(path=pycache_prefix): |
| 780 | + path = drive + os.path.join( |
| 781 | + os.path.sep, 'foo', 'bar', 'baz', 'qux.py') |
| 782 | + expect = os.path.join( |
| 783 | + pycache_prefix, 'foo', 'bar', 'baz', |
| 784 | + 'qux.{}.pyc'.format(self.tag)) |
| 785 | + with util.temporary_pycache_prefix(pycache_prefix): |
| 786 | + self.assertEqual( |
| 787 | + self.util.cache_from_source(path, optimization=''), |
| 788 | + expect) |
| 789 | + |
| 790 | + @unittest.skipIf(sys.implementation.cache_tag is None, |
| 791 | + 'requires sys.implementation.cache_tag to not be None') |
| 792 | + def test_cache_from_source_respects_pycache_prefix_relative(self): |
| 793 | + # If the .py path we are given is relative, we will resolve to an |
| 794 | + # absolute path before prefixing with pycache_prefix, to avoid any |
| 795 | + # possible ambiguity. |
| 796 | + pycache_prefix = os.path.join(os.path.sep, 'tmp', 'bytecode') |
| 797 | + path = os.path.join('foo', 'bar', 'baz', 'qux.py') |
| 798 | + root = os.path.splitdrive(os.getcwd())[0] + os.path.sep |
| 799 | + expect = os.path.join( |
| 800 | + pycache_prefix, |
| 801 | + os.path.relpath(os.getcwd(), root), |
| 802 | + 'foo', 'bar', 'baz', f'qux.{self.tag}.pyc') |
| 803 | + with util.temporary_pycache_prefix(pycache_prefix): |
| 804 | + self.assertEqual( |
| 805 | + self.util.cache_from_source(path, optimization=''), |
| 806 | + expect) |
| 807 | + |
| 808 | + @unittest.skipIf(sys.implementation.cache_tag is None, |
| 809 | + 'requires sys.implementation.cache_tag to not be None') |
| 810 | + def test_source_from_cache_inside_pycache_prefix(self): |
| 811 | + # If pycache_prefix is set and the cache path we get is inside it, |
| 812 | + # we return an absolute path to the py file based on the remainder of |
| 813 | + # the path within pycache_prefix. |
| 814 | + pycache_prefix = os.path.join(os.path.sep, 'tmp', 'bytecode') |
| 815 | + path = os.path.join(pycache_prefix, 'foo', 'bar', 'baz', |
| 816 | + f'qux.{self.tag}.pyc') |
| 817 | + expect = os.path.join(os.path.sep, 'foo', 'bar', 'baz', 'qux.py') |
| 818 | + with util.temporary_pycache_prefix(pycache_prefix): |
| 819 | + self.assertEqual(self.util.source_from_cache(path), expect) |
| 820 | + |
| 821 | + @unittest.skipIf(sys.implementation.cache_tag is None, |
| 822 | + 'requires sys.implementation.cache_tag to not be None') |
| 823 | + def test_source_from_cache_outside_pycache_prefix(self): |
| 824 | + # If pycache_prefix is set but the cache path we get is not inside |
| 825 | + # it, just ignore it and handle the cache path according to the default |
| 826 | + # behavior. |
| 827 | + pycache_prefix = os.path.join(os.path.sep, 'tmp', 'bytecode') |
| 828 | + path = os.path.join('foo', 'bar', 'baz', '__pycache__', |
| 829 | + f'qux.{self.tag}.pyc') |
| 830 | + expect = os.path.join('foo', 'bar', 'baz', 'qux.py') |
| 831 | + with util.temporary_pycache_prefix(pycache_prefix): |
| 832 | + self.assertEqual(self.util.source_from_cache(path), expect) |
| 833 | + |
761 | 834 |
|
762 | 835 | (Frozen_PEP3147Tests, |
763 | 836 | Source_PEP3147Tests |
|
0 commit comments