Repository: tox-dev/pipdeptree (python)

Issue:
Slightly different output for --json-tree and --json
--json-tree says `required_version": "Any"`

but 

--json says  `"required_version": null`


This command

```bash
pipdeptree  --json-tree -p wxPython
```

produces this output

```json
   {
        "key": "wxpython",
        "package_name": "wxPython",
        "installed_version": "4.2.1",
        "required_version": "4.2.1",
        "dependencies": [
            {
                "key": "numpy",
                "package_name": "numpy",
                "installed_version": "1.26.2",
                "required_version": "Any",
                "dependencies": []
            },
            {
                "key": "pillow",
                "package_name": "Pillow",
                "installed_version": "10.1.0",
                "required_version": "Any",
                "dependencies": []
            },
            {
                "key": "six",
                "package_name": "six",
                "installed_version": "1.16.0",
                "required_version": "Any",
                "dependencies": []
            }
        ]
    }
]
```

but this command

```bash
pipdeptree  --json -p wxPython
```


produces this output

```json
[
    {
        "package": {
            "key": "numpy",
            "package_name": "numpy",
            "installed_version": "1.26.2"
        },
        "dependencies": []
    },
    {
        "package": {
            "key": "pillow",
            "package_name": "Pillow",
            "installed_version": "10.1.0"
        },
        "dependencies": []
    },
    {
        "package": {
            "key": "six",
            "package_name": "six",
            "installed_version": "1.16.0"
        },
        "dependencies": []
    },
    {
        "package": {
            "key": "wxpython",
            "package_name": "wxPython",
            "installed_version": "4.2.1"
        },
        "dependencies": [
            {
                "key": "numpy",
                "package_name": "numpy",
                "installed_version": "1.26.2",
                "required_version": null
            },
            {
                "key": "pillow",
                "package_name": "Pillow",
                "installed_version": "10.1.0",
                "required_version": null
            },
            {
                "key": "six",
                "package_name": "six",
                "installed_version": "1.16.0",
                "required_version": null
            }
        ]
    }
]
```

Pull request:
Use "Any" value if necessary for required version in JSON render
Resolves #309 by having the --json render return `"required_version": "Any"` instead of `"required_version": null`.

The only problem with this change is that I'm unsure if this should be considered a breaking change or not...? Not sure if it would be better to just have both --json and --json-tree give null values for this key (I guess it would be easier for users to determine whether or not a required package has a version spec)

Patch:
diff --git a/src/pipdeptree/_models/package.py b/src/pipdeptree/_models/package.py
index 58e5664..2be5163 100644
--- a/src/pipdeptree/_models/package.py
+++ b/src/pipdeptree/_models/package.py
@@ -36,7 +36,7 @@ class Package(ABC):
         raise NotImplementedError
 
     @abstractmethod
-    def as_dict(self) -> dict[str, str | None]:
+    def as_dict(self) -> dict[str, str]:
         raise NotImplementedError
 
     def render(
@@ -138,7 +138,7 @@ class DistPackage(Package):
             return self
         return self.__class__(self._obj, req)
 
-    def as_dict(self) -> dict[str, str | None]:
+    def as_dict(self) -> dict[str, str]:
         return {"key": self.key, "package_name": self.project_name, "installed_version": self.version}
 
 
@@ -209,12 +209,12 @@ class ReqPackage(Package):
         req_obj = Requirement.parse(req_version_str)  # type: ignore[no-untyped-call]
         return self.installed_version not in req_obj
 
-    def as_dict(self) -> dict[str, str | None]:
+    def as_dict(self) -> dict[str, str]:
         return {
             "key": self.key,
             "package_name": self.project_name,
             "installed_version": self.installed_version,
-            "required_version": self.version_spec,
+            "required_version": self.version_spec if self.version_spec is not None else "Any",
         }
 
 


Test patch:
diff --git a/tests/_models/test_package.py b/tests/_models/test_package.py
index 5c4770b..a361148 100644
--- a/tests/_models/test_package.py
+++ b/tests/_models/test_package.py
@@ -84,3 +84,12 @@ def test_req_package_as_dict() -> None:
     result = rp.as_dict()
     expected = {"key": "bar", "package_name": "bar", "installed_version": "4.1.0", "required_version": ">=4.0"}
     assert expected == result
+
+
+def test_req_package_as_dict_with_no_version_spec() -> None:
+    bar = Mock(key="bar", project_name="bar", version="4.1.0")
+    bar_req = Mock(key="bar", project_name="bar", version="4.1.0", specs=[])
+    rp = ReqPackage(bar_req, dist=bar)
+    result = rp.as_dict()
+    expected = {"key": "bar", "package_name": "bar", "installed_version": "4.1.0", "required_version": "Any"}
+    assert expected == result