Repository: vyperlang/vyper

Issue:
Silence deprecation warnings if Python `3.12` is used
If Python `3.12` is used, the compiler currently prints a lot of deprecations as `stderr`. It adds a lot of noise, and I would suggest to suppress these non-fatal deprecation warnings in the compiler.

### Example

```console
stderr="/opt/hostedtoolcache/Python/3.12.3/x64/lib/python3.12/site-packages/vyper/ast/parse.py:238: DeprecationWarning: ast.Str is deprecated and will be removed in Python 3.14; use ast.Constant instead\n  if isinstance(n, python_ast.Expr) and isinstance(n.value, python_ast.Str):\n/opt/hostedtoolcache/Python/3.12.3/x64/lib/python3.12/site-packages/vyper/ast/parse.py:238: DeprecationWarning: ast.Str is deprecated and will be removed in Python 3.14; use ast.Constant instead\n  if isinstance(n, python_ast.Expr) and isinstance(n.value, python_ast.Str):\n/opt/hostedtoolcache/Python/3.12.3/x64/lib/python3.12/site-packages/vyper/ast/parse.py:238: DeprecationWarning: ast.Str is deprecated and will be removed in Python 3.14; use ast.Constant instead\n  if isinstance(n, python_ast.Expr) and isinstance(n.value, python_ast.Str):\n/opt/hostedtoolcache/Python/3.12.3/x64/lib/python3.12/site-packages/vyper/ast/parse.py:238: DeprecationWarning: ast.Str is deprecated and will be removed in Python 3.14; use ast.Constant instead\n  if isinstance(n, python_ast.Expr) and isinstance(n.value, python_ast.Str):\n/opt/hostedtoolcache/Python/3.12.3/x64/lib/python3.12/site-packages/vyper/ast/parse.py:238: DeprecationWarning: ast.Str is deprecated and will be removed in Python 3.14; use ast.Constant instead\n  if isinstance(n, python_ast.Expr) and isinstance(n.value, python_ast.Str):\n/opt/hostedtoolcache/Python/3.12.3/x64/lib/python3.12/site-packages/vyper/ast/parse.py:238: DeprecationWarning: ast.Str is deprecated and will be removed in Python 3.14; use ast.Constant instead\n  if isinstance(n, python_ast.Expr) and isinstance(n.value, python_ast.Str):\n/opt/hostedtoolcache/Python/3.12.3/x64/lib/python3.12/site-packages/vyper/ast/parse.py:238: DeprecationWarning: ast.Str is deprecated and will be removed in Python 3.14; use ast.Constant instead\n  if isinstance(n, python_ast.Expr) and isinstance(n.value, python_ast.Str):\n/opt/hostedtoolcache/Python/3.12.3/x64/lib/python3.12/site-packages/vyper/ast/parse.py:238: DeprecationWarning: ast.Str is deprecated and will be removed in Python 3.14; use ast.Constant instead\n  if isinstance(n, python_ast.Expr) and isinstance(n.value, python_ast.Str):\n/opt/hostedtoolcache/Python/3.12.3/x64/lib/python3.12/site-packages/vyper/ast/parse.py:238: DeprecationWarning: ast.Str is deprecated and will be removed in Python 3.14; use ast.Constant instead\n  if isinstance(n, python_ast.Expr) and isinstance(n.value, python_ast.Str):\n/opt/hostedtoolcache/Python/3.12.3/x64/lib/python3.12/site-packages/vyper/ast/parse.py:238: DeprecationWarning: ast.Str is deprecated and will be removed in Python 3.14; use ast.Constant instead\n  if isinstance(n, python_ast.Expr) and isinstance(n.value, python_ast.Str):\n"
```

One way to fix this is to add to the code:

```python
import warnings
warnings.filterwarnings("ignore", category=DeprecationWarning)
```


Discussion:
we should remove the deprecated classes (it's kind of a chore though since it touches a lot of files)

Resolving patch:
diff --git a/vyper/ast/parse.py b/vyper/ast/parse.py
--- a/vyper/ast/parse.py
+++ b/vyper/ast/parse.py
@@ -235,7 +235,11 @@ def _visit_docstring(self, node):
 
         if node.body:
             n = node.body[0]
-            if isinstance(n, python_ast.Expr) and isinstance(n.value, python_ast.Str):
+            if (
+                isinstance(n, python_ast.Expr)
+                and isinstance(n.value, python_ast.Constant)
+                and isinstance(n.value.value, str)
+            ):
                 self.generic_visit(n.value)
                 n.value.ast_type = "DocStr"
                 del node.body[0]
@@ -470,13 +474,9 @@ def visit_UnaryOp(self, node):
         self.generic_visit(node)
 
         is_sub = isinstance(node.op, python_ast.USub)
-        is_num = (
-            hasattr(node.operand, "n")
-            and not isinstance(node.operand.n, bool)
-            and isinstance(node.operand.n, (int, Decimal))
-        )
+        is_num = hasattr(node.operand, "value") and isinstance(node.operand.value, (int, Decimal))
         if is_sub and is_num:
-            node.operand.n = 0 - node.operand.n
+            node.operand.value = 0 - node.operand.value
             node.operand.col_offset = node.col_offset
             node.operand.node_source_code = node.node_source_code
             return node.operand


Test patch:
diff --git a/tests/unit/ast/test_annotate_and_optimize_ast.py b/tests/unit/ast/test_annotate_and_optimize_ast.py
--- a/tests/unit/ast/test_annotate_and_optimize_ast.py
+++ b/tests/unit/ast/test_annotate_and_optimize_ast.py
@@ -62,5 +62,5 @@ def test_it_rewrites_unary_subtractions():
     function_def = contract_ast.body[2]
     return_stmt = function_def.body[0]
 
-    assert isinstance(return_stmt.value, python_ast.Num)
-    assert return_stmt.value.n == -1
+    assert isinstance(return_stmt.value, python_ast.Constant)
+    assert return_stmt.value.value == -1