diff --git a/.lintrunner.toml b/.lintrunner.toml index 52efb2f802..c34714eeba 100644 --- a/.lintrunner.toml +++ b/.lintrunner.toml @@ -98,42 +98,6 @@ init_command = [ ] is_formatter = true -[[linter]] -code = 'PYLINT' -include_patterns = [ - '**/*.py', -] -exclude_patterns = [ - 'docs/**', - 'examples/**', - 'onnxscript/_internal/converter_test.py', - 'onnxscript/optimizer/**', # FIXME - 'onnxscript/rewriter/**', # FIXME - 'tests/functions/**', - 'tests/models/**', - 'tests/onnx_backend_test_code/**', -] -command = [ - 'python', - '-m', - 'lintrunner_adapters', - 'run', - 'pylint_linter', - '--rcfile=pyproject_pylint.toml', - '--show-disable', - '--', - '@{{PATHSFILE}}' -] -init_command = [ - 'python', - '-m', - 'lintrunner_adapters', - 'run', - 'pip_init', - '--dry-run={{DRYRUN}}', - '--requirement=requirements/lintrunner/requirements.txt', -] - [[linter]] code = 'EDITORCONFIG-CHECKER' include_patterns = ['**'] diff --git a/onnxscript/_internal/builder.py b/onnxscript/_internal/builder.py index 1dc0875871..c430969dcf 100644 --- a/onnxscript/_internal/builder.py +++ b/onnxscript/_internal/builder.py @@ -31,6 +31,7 @@ Sequence[float], Sequence[bool], Sequence[str], + None, ] # Mapping from Python scalar types to their default ONNX DataType, @@ -258,7 +259,7 @@ def initializer( def _input_to_ir_value( self, value: VALUE_LIKE, like_type: ir.Value | None = None - ) -> ir.Value: + ) -> ir.Value | None: """Convert a permissible input (for a call to an op) into an ir.Value. Permissible values include ir.Value as well as python constants that can be converted @@ -267,6 +268,8 @@ def _input_to_ir_value( """ if isinstance(value, ir.Value): return value + if value is None: + return value dtype = ( like_type.type.dtype if like_type is not None and like_type.type is not None @@ -356,7 +359,7 @@ def _get_schema( def _partition_inputs_attributes( self, schema: onnx.defs.OpSchema | None, - inputs: Sequence[ir.Value | ir.TensorProtocol], + inputs: Sequence[ir.Value | ir.TensorProtocol | None], kwargs: dict[str, Any], ) -> tuple[Sequence[ir.Value | ir.TensorProtocol], dict[str, Any]]: if schema is None: @@ -504,7 +507,7 @@ def subgraph( def call_op( self, op_type: str, - inputs: Sequence[ir.Value | ir.TensorProtocol], + inputs: Sequence[ir.Value | ir.TensorProtocol | None], kwargs: dict[str, Any], ): """Create an ONNX node and add it to the graph, returning its output value(s).""" diff --git a/onnxscript/_internal/builder_test.py b/onnxscript/_internal/builder_test.py index f6f301954b..45e0fef77a 100644 --- a/onnxscript/_internal/builder_test.py +++ b/onnxscript/_internal/builder_test.py @@ -848,6 +848,39 @@ def add_mul(X, Y): self.assertIn("does not match", str(cm.exception)) + def test_none_input_is_passed_through(self): + """Test that None inputs are preserved as None in the node's inputs.""" + op, x, y = _create_builder_with_inputs() + + # Gemm's third input (C) is optional; passing None should work + result = op.Gemm(x, y, None, alpha=1.0) + + nodes = list(op.builder.graph) + self.assertEqual(len(nodes), 1) + node = nodes[0] + self.assertEqual(node.op_type, "Gemm") + # The third input should be None (optional, omitted) + self.assertEqual(len(list(node.inputs)), 3) + self.assertIs(node.inputs[0], x) + self.assertIs(node.inputs[1], y) + self.assertIsNone(node.inputs[2]) + self.assertIsNotNone(result) + + def test_none_input_with_custom_domain(self): + """Test that None inputs work with custom domain ops.""" + op, x, y = _create_builder_with_inputs() + + result = op.CustomOp(x, None, y, _domain="com.custom") + + nodes = list(op.builder.graph) + self.assertEqual(len(nodes), 1) + node = nodes[0] + self.assertEqual(node.op_type, "CustomOp") + self.assertIs(node.inputs[0], x) + self.assertIsNone(node.inputs[1]) + self.assertIs(node.inputs[2], y) + self.assertIsNotNone(result) + class BuildSubgraphTest(unittest.TestCase): """Tests for GraphBuilder.subgraph().""" diff --git a/pyproject.toml b/pyproject.toml index 125b41aeee..2e0d826460 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -86,8 +86,7 @@ module = [ ignore_errors = true [tool.pylint.messages_control] -# NOTE: This list is for vscode. Add new disables in pyproject_pylint.toml for lintrunner -# Exclude patterns should be modified in .lintrunner.toml +# NOTE: This list is for vscode. Pylint is removed from CI disable = [ "consider-using-from-import", "format", diff --git a/pyproject_pylint.toml b/pyproject_pylint.toml deleted file mode 100644 index a764937fb5..0000000000 --- a/pyproject_pylint.toml +++ /dev/null @@ -1,34 +0,0 @@ -# Relax pylint for lintrunner - -[tool.pylint.messages_control] -disable = [ - "arguments-differ", # TODO: abstract methods in Rewriter - "attribute-defined-outside-init", # TODO: mostly in onnxscript/converter.py - "cell-var-from-loop", # Bugbear B023 - "consider-using-from-import", - "cyclic-import", - "duplicate-code", - "fixme", - "format", - "import-error", - "invalid-name", # TODO: Add naming guidance and enable this check. - "line-too-long", - "missing-docstring", - "no-else-return", - "no-member", - "no-name-in-module", - "redefined-builtin", # TODO: should we avoid redefined-builtin? - "too-few-public-methods", - "too-many-ancestors", - "too-many-arguments", - "too-many-branches", - "too-many-instance-attributes", - "too-many-lines", - "too-many-locals", - "too-many-positional-arguments", - "too-many-public-methods", - "too-many-return-statements", - "too-many-statements", # TODO: we should work on these: too-many-xxx series - "unnecessary-ellipsis", - "use-dict-literal", # Sometime it is preferable when we construct kwargs -] diff --git a/requirements/lintrunner/requirements.txt b/requirements/lintrunner/requirements.txt index 0e132a6621..a8f3355ada 100644 --- a/requirements/lintrunner/requirements.txt +++ b/requirements/lintrunner/requirements.txt @@ -5,7 +5,5 @@ ruff==0.15.1 # MYPY mypy==1.10.1 types-PyYAML==6.0.12.20250915 -# PYLINT -pylint==3.3.9 # EDITORCONFIG-CHECKER editorconfig-checker==3.4.1