|
1 | 1 | import ast
|
2 | 2 | import operator
|
3 | 3 | import re
|
| 4 | +import sys |
4 | 5 | import threading
|
5 | 6 | import unittest
|
6 | 7 | import uuid
|
@@ -1731,8 +1732,9 @@ def test_SelfPrint_failure(self, value):
|
1731 | 1732 | "[('company_id', 'in', (companies.active_ids or [False]))]",
|
1732 | 1733 | ),
|
1733 | 1734 | (
|
1734 |
| - "[('company_id','in', user.other.allowed_company_ids)]", |
1735 |
| - "[('company_id', 'in', user.other.allowed_company_ids)]", |
| 1735 | + "[('company_id','in', user.other.allowed_company_ids)]", |
| 1736 | + # note it keeps the original spacing since no match should happen! |
| 1737 | + "[('company_id','in', user.other.allowed_company_ids)]", |
1736 | 1738 | ),
|
1737 | 1739 | (
|
1738 | 1740 | "[('group_id','in', user.groups_id.ids)]",
|
@@ -1764,6 +1766,135 @@ def test_literal_replace(self, orig, expected, old_unparse_fallback=None):
|
1764 | 1766 | else:
|
1765 | 1767 | self.assertEqual(repl, expected)
|
1766 | 1768 |
|
| 1769 | + @unittest.skipUnless(util.ast_unparse is not None, "`ast.unparse` available from Python3.9") |
| 1770 | + @mute_logger("odoo.upgrade.util.misc") |
| 1771 | + def test_literal_replace_error(self): |
| 1772 | + # this shouldn't raise a syntax error |
| 1773 | + res = util.literal_replace("[1,2", {"1": "3"}) |
| 1774 | + self.assertEqual(res, "[1,2") |
| 1775 | + |
| 1776 | + @parametrize( |
| 1777 | + [ |
| 1778 | + ("x[1 ]", "x[1]"), |
| 1779 | + ("{x for x in y }, [ {1 }, {1 : 2},x[1],y[ 1:2:3 ] ]", "{x for x in y},[{1},{1:2},x[1],y[1:2:3]]"), |
| 1780 | + ( |
| 1781 | + "[1 if True else 2, * z] + [x for x in y if w], {x:x for x in y} ", |
| 1782 | + "[1 if True else 2,*z]+[x for x in y if w],{x:x for x in y}", |
| 1783 | + ), |
| 1784 | + ("1 < 2 <3, x or z and y or x", "1<2<3,x or z and y or x"), |
| 1785 | + ] |
| 1786 | + ) |
| 1787 | + @unittest.skipUnless(util.ast_unparse is not None, "`ast.unparse` available from Python3.9") |
| 1788 | + def test_literal_replace_full(self, text, orig): |
| 1789 | + # check each grammar piece |
| 1790 | + repl = util.literal_replace(text, {orig: "gone"}) |
| 1791 | + self.assertEqual(repl, "gone") |
| 1792 | + |
| 1793 | + # minimal change should invalidate the replace |
| 1794 | + text = text.replace("x", "xx") |
| 1795 | + repl = util.literal_replace(text, {orig: "gone"}) |
| 1796 | + self.assertEqual(text, repl) |
| 1797 | + |
| 1798 | + @unittest.skipUnless(util.ast_unparse is not None, "`ast.unparse` available from Python3.9") |
| 1799 | + def test_literal_replace_callable(self): |
| 1800 | + def adapter(node): |
| 1801 | + return ast.parse("this.get('{}')".format(node.attr), mode="eval").body |
| 1802 | + |
| 1803 | + repl = util.literal_replace( |
| 1804 | + "result = this. x if that . y == 2 else this .z", |
| 1805 | + {ast.Attribute(ast.Name("this", None), util.literal_replace.WILDCARD, None): adapter}, |
| 1806 | + ) |
| 1807 | + self.assertIn( |
| 1808 | + repl, |
| 1809 | + [ |
| 1810 | + "result = this.get('x') if that.y == 2 else this.get('z')", |
| 1811 | + # fallback for older unparse |
| 1812 | + "result = (this.get('x') if (that.y == 2) else this.get('z'))", |
| 1813 | + ], |
| 1814 | + ) |
| 1815 | + |
| 1816 | + @unittest.skipUnless(util.ast_unparse is not None, "`ast.unparse` available from Python3.9") |
| 1817 | + @unittest.skipUnless(hasattr(ast, "Constant"), "`ast.Constant` available from Python3.6") |
| 1818 | + def test_literal_replace_callable2(self): |
| 1819 | + def adapter2(node): |
| 1820 | + return ast.parse( |
| 1821 | + "{} / 42".format(node.left.value if hasattr(node.left, "value") else node.left.n), mode="eval" |
| 1822 | + ).body |
| 1823 | + |
| 1824 | + def adapter3(node): |
| 1825 | + return ast.parse("y == 42", mode="eval").body |
| 1826 | + |
| 1827 | + repl = util.literal_replace( |
| 1828 | + "16 * w or y == 2", |
| 1829 | + { |
| 1830 | + ast.BinOp(ast.Constant(16), ast.Mult(), ast.Name(util.literal_replace.WILDCARD, None)): adapter2, |
| 1831 | + ast.Compare(ast.Name("y", None), [ast.Eq()], [ast.Constant(util.literal_replace.WILDCARD)]): adapter3, |
| 1832 | + }, |
| 1833 | + ) |
| 1834 | + # Check with fallback for older unparse |
| 1835 | + self.assertIn(repl, ["16 / 42 or y == 42", "((16 / 42) or (y == 42))"]) |
| 1836 | + |
| 1837 | + def adapter4(node): |
| 1838 | + return ast.parse( |
| 1839 | + "{}.get({})".format(util.ast_unparse(node.value), util.ast_unparse(node.slice)), mode="eval" |
| 1840 | + ).body |
| 1841 | + |
| 1842 | + repl = util.literal_replace( |
| 1843 | + " x[ 'a' ]+y[b ] - z[None]", |
| 1844 | + { |
| 1845 | + ast.Subscript( |
| 1846 | + ast.Name(util.literal_replace.WILDCARD, None), util.literal_replace.WILDCARD, None |
| 1847 | + ): adapter4 |
| 1848 | + }, |
| 1849 | + ) |
| 1850 | + # Check with fallback for older unparse |
| 1851 | + self.assertIn(repl, ["x.get('a') + y.get(b) - z.get(None)", "((x.get('a') + y.get(b)) - z.get(None))"]) |
| 1852 | + |
| 1853 | + @unittest.skipUnless(util.ast_unparse is not None, "`ast.unparse` available from Python3.9") |
| 1854 | + @unittest.skipUnless(hasattr(ast, "Constant"), "`ast.Constant` available from Python3.6") |
| 1855 | + def test_literal_replace_wildcards(self): |
| 1856 | + repl = util.literal_replace( |
| 1857 | + "x+1 - z* 18 + [1,2,3]", |
| 1858 | + { |
| 1859 | + ast.Name(util.literal_replace.WILDCARD, None): "y", |
| 1860 | + (ast.Constant if sys.version_info > (3, 9) else ast.Num)(util.literal_replace.WILDCARD): "2", |
| 1861 | + ast.List([util.literal_replace.WILDCARD], None): "[4,5]", |
| 1862 | + }, |
| 1863 | + ) |
| 1864 | + self.assertIn(repl, ["y + 2 - y * 2 + [4, 5]", "(((y + 2) - (y * 2)) + [4, 5])"]) |
| 1865 | + |
| 1866 | + @parametrize( |
| 1867 | + [ |
| 1868 | + (ast.Constant(util.literal_replace.WILDCARD, kind=None), "*"), |
| 1869 | + (ast.Name(util.literal_replace.WILDCARD, None), "*"), |
| 1870 | + (ast.Attribute(ast.Name(util.literal_replace.WILDCARD, None), util.literal_replace.WILDCARD, None), "*.*"), |
| 1871 | + ( |
| 1872 | + ast.Subscript( |
| 1873 | + ast.Name(util.literal_replace.WILDCARD, None), ast.Name(util.literal_replace.WILDCARD, None), None |
| 1874 | + ), |
| 1875 | + "*[*]", |
| 1876 | + ), |
| 1877 | + ( |
| 1878 | + ast.BinOp( |
| 1879 | + ast.Name(util.literal_replace.WILDCARD, None), |
| 1880 | + ast.Add(), |
| 1881 | + ast.Name(util.literal_replace.WILDCARD, None), |
| 1882 | + ), |
| 1883 | + "* + *", |
| 1884 | + "(* + *)", |
| 1885 | + ), |
| 1886 | + (ast.List([util.literal_replace.WILDCARD], None), "[*]"), |
| 1887 | + (ast.Tuple([util.literal_replace.WILDCARD], None), "(*,)"), |
| 1888 | + ] |
| 1889 | + ) |
| 1890 | + @unittest.skipUnless(util.ast_unparse is not None, "`ast.unparse` available from Python3.9") |
| 1891 | + def test_literal_replace_wildcard_unparse(self, orig, expected, old_unparse_fallback=None): |
| 1892 | + res = util.ast_unparse(orig) |
| 1893 | + if old_unparse_fallback: |
| 1894 | + self.assertIn(res, [expected, old_unparse_fallback]) |
| 1895 | + else: |
| 1896 | + self.assertEqual(res, expected) |
| 1897 | + |
1767 | 1898 |
|
1768 | 1899 | def not_doing_anything_converter(el):
|
1769 | 1900 | return True
|
|
0 commit comments