Repository: xlwings/jsondiff

Issue:
No difference label if one of JSON is empty
Hi,

I did some tests with the library and I have a case scenario where one of the compared JSON is empty: { }. I am using syntax='explicit' and the diff returns me exactly the JSON that is not the one empty. My problem is that I would like it to return me something like:

```js
{
  insert: ...
}
```

The "insert" tag is quite important during my parsing.

Comments:

Patch:
diff --git a/.github/workflows/pr_check.yml b/.github/workflows/pr_check.yml
index aafc4f9..41155fb 100644
--- a/.github/workflows/pr_check.yml
+++ b/.github/workflows/pr_check.yml
@@ -19,7 +19,7 @@ jobs:
           python-version: ${{ matrix.python-version }}
       - name: Install Dependencies
         run: |
-          pip install -r dev-requirements.txt
+          pip install .[test]
       - name: Run Tests
         run: |
           python -m pytest
diff --git a/dev-requirements.txt b/dev-requirements.txt
deleted file mode 100644
index 9a54149..0000000
--- a/dev-requirements.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-hypothesis
-pytest
diff --git a/jsondiff/__init__.py b/jsondiff/__init__.py
index e2920c4..a3fdcc2 100644
--- a/jsondiff/__init__.py
+++ b/jsondiff/__init__.py
@@ -84,7 +84,7 @@ class CompactJsonDiffSyntax(object):
     def emit_list_diff(self, a, b, s, inserted, changed, deleted):
         if s == 0.0:
             return {replace: b} if isinstance(b, dict) else b
-        elif s == 1.0:
+        elif s == 1.0 and not (inserted or changed or deleted):
             return {}
         else:
             d = changed
@@ -97,7 +97,7 @@ class CompactJsonDiffSyntax(object):
     def emit_dict_diff(self, a, b, s, added, changed, removed):
         if s == 0.0:
             return {replace: b} if isinstance(b, dict) else b
-        elif s == 1.0:
+        elif s == 1.0 and not (added or changed or removed):
             return {}
         else:
             changed.update(added)
@@ -171,9 +171,9 @@ class ExplicitJsonDiffSyntax(object):
             return d
 
     def emit_list_diff(self, a, b, s, inserted, changed, deleted):
-        if s == 0.0:
+        if s == 0.0 and not (inserted or changed or deleted):
             return b
-        elif s == 1.0:
+        elif s == 1.0 and not (inserted or changed or deleted):
             return {}
         else:
             d = changed
@@ -184,9 +184,9 @@ class ExplicitJsonDiffSyntax(object):
             return d
 
     def emit_dict_diff(self, a, b, s, added, changed, removed):
-        if s == 0.0:
+        if s == 0.0 and not (added or changed or removed):
             return b
-        elif s == 1.0:
+        elif s == 1.0 and not (added or changed or removed):
             return {}
         else:
             d = {}
@@ -218,9 +218,9 @@ class SymmetricJsonDiffSyntax(object):
             return d
 
     def emit_list_diff(self, a, b, s, inserted, changed, deleted):
-        if s == 0.0:
+        if s == 0.0 and not (inserted or changed or deleted):
             return [a, b]
-        elif s == 1.0:
+        elif s == 1.0 and not (inserted or changed or deleted):
             return {}
         else:
             d = changed
@@ -231,9 +231,9 @@ class SymmetricJsonDiffSyntax(object):
             return d
 
     def emit_dict_diff(self, a, b, s, added, changed, removed):
-        if s == 0.0:
+        if s == 0.0 and not (added or changed or removed):
             return [a, b]
-        elif s == 1.0:
+        elif s == 1.0 and not (added or changed or removed):
             return {}
         else:
             d = changed
diff --git a/pyproject.toml b/pyproject.toml
new file mode 100644
index 0000000..3f46156
--- /dev/null
+++ b/pyproject.toml
@@ -0,0 +1,39 @@
+[build-system]
+requires = ["setuptools>=43.0.0", "wheel"]
+build-backend = "setuptools.build_meta"
+
+[project]
+name = "jsondiff"
+description = "Diff JSON and JSON-like structures in Python"
+dynamic = ["version"]
+readme = "README.rst"
+license= {file = "LICENSE" }
+requires-python = ">=3.8"
+authors = [
+    { name = "Zoomer Analytics LLC", email = "eric.reynolds@zoomeranalytics.com"}
+]
+keywords = ['json', 'diff', 'diffing', 'difference', 'patch', 'delta', 'dict', 'LCS']
+classifiers = [
+    'License :: OSI Approved :: MIT License',
+    'Programming Language :: Python :: 3',
+]
+
+[project.optional-dependencies]
+test = [
+    "hypothesis",
+    "pytest"
+]
+
+[project.urls]
+"Homepage" = "https://github.com/xlwings/jsondiff"
+"Bug Tracker" = "https://github.com/xlwings/jsondiff/issues"
+
+[project.scripts]
+jdiff = "jsondiff.cli:main"
+
+[tool.setuptools.packages.find]
+include = ["jsondiff*"]
+exclude = ["tests*"]
+
+[tool.setuptools.dynamic]
+version = {attr = "jsondiff.__version__"}
diff --git a/setup.py b/setup.py
index 08a30dc..bf508c8 100644
--- a/setup.py
+++ b/setup.py
@@ -1,26 +1,4 @@
-import os
-import re
-from setuptools import setup, find_packages
+# Maintained for legacy compatibility
+from setuptools import setup
 
-with open(os.path.join(os.path.dirname(__file__), 'jsondiff', '__init__.py')) as f:
-    version = re.compile(r".*__version__ = '(.*?)'", re.S).match(f.read()).group(1)
-
-setup(
-    name='jsondiff',
-    packages=find_packages(exclude=['tests']),
-    version=version,
-    description='Diff JSON and JSON-like structures in Python',
-    author='Zoomer Analytics LLC',
-    author_email='eric.reynolds@zoomeranalytics.com',
-    url='https://github.com/ZoomerAnalytics/jsondiff',
-    keywords=['json', 'diff', 'diffing', 'difference', 'patch', 'delta', 'dict', 'LCS'],
-    classifiers=[
-        'License :: OSI Approved :: MIT License',
-        'Programming Language :: Python :: 3',
-    ],
-    entry_points={
-        'console_scripts': [
-            'jdiff=jsondiff.cli:main'
-        ]
-    }
-)
+setup()


Test patch:
diff --git a/tests/test_jsondiff.py b/tests/test_jsondiff.py
index 8328ee9..2cbbc66 100644
--- a/tests/test_jsondiff.py
+++ b/tests/test_jsondiff.py
@@ -1,5 +1,6 @@
 import sys
 import unittest
+import pytest
 
 from jsondiff import diff, replace, add, discard, insert, delete, update, JsonDiffer
 
@@ -134,3 +135,30 @@ class JsonDiffTests(unittest.TestCase):
             self.fail('cannot diff long arrays')
         finally:
             sys.setrecursionlimit(r)
+
+
+@pytest.mark.parametrize(
+    ("a", "b", "syntax", "expected"),
+    [
+        pytest.param([], [{"a": True}], "explicit", {insert: [(0, {"a": True})]},
+                     id="issue59_"),
+        pytest.param([{"a": True}], [], "explicit", {delete: [0]},
+                     id="issue59_"),
+        pytest.param([], [{"a": True}], "compact", [{"a": True}],
+                     id="issue59_"),
+        pytest.param([{"a": True}], [], "compact", [],
+                     id="issue59_"),
+        pytest.param([], [{"a": True}], "symmetric", {insert: [(0, {"a": True})]},
+                     id="issue59_"),
+        pytest.param([{"a": True}], [], "symmetric", {delete: [(0, {"a": True})]},
+                     id="issue59_"),
+        pytest.param({1: 2}, {5: 3}, "symmetric", {delete: {1: 2}, insert: {5: 3}},
+                     id="issue36_"),
+        pytest.param({1: 2}, {5: 3}, "compact", {replace: {5: 3}},
+                     id="issue36_"),
+    ],
+)
+class TestSpecificIssue:
+    def test_issue(self,  a, b, syntax, expected):
+        actual = diff(a, b, syntax=syntax)
+        assert actual == expected