Repository: python-semver/python-semver (python)

Issue:
__getitem__ returns `None` for version parts that are falsy
For example, VersionInfo(0, 1, 0, 'r.1')[2] returns None when it should return 0.  

Pull request description:
Fix #260 __getitem__ returning `None` on falsy parts
For reference [here](https://stackoverflow.com/questions/38339496/python-filternone-list-of-bools-behavior) is the behavior that caused the problem in the first.

I also found that the IndexError wasn't being raised every time it should because it was reliant on the faulty behavior descibed above for some edge cases.

Patch:
diff --git a/CHANGELOG.rst b/CHANGELOG.rst
index c28880e..2671ef2 100644
--- a/CHANGELOG.rst
+++ b/CHANGELOG.rst
@@ -7,6 +7,34 @@ All notable changes to this code base will be documented in this file,
 in every released version.
 
 
+Version 2.10.2 (WIP)
+====================
+
+:Released: 2020-xx-yy
+:Maintainer:
+
+Features
+--------
+
+n/a
+
+Bug Fixes
+---------
+
+:gh:`260` (:pr:`261`): Fixed ``__getitem__`` returning None on wrong parts
+
+
+Additions
+---------
+
+n/a
+
+Removals
+--------
+
+n/a
+
+
 Version 2.10.1
 ==============
 
diff --git a/semver.py b/semver.py
index 00338e8..0c98af9 100644
--- a/semver.py
+++ b/semver.py
@@ -548,17 +548,16 @@ build='build.10')
 
         if (
             isinstance(index, slice)
-            and (index.start is None or index.start < 0)
-            and (index.stop is None or index.stop < 0)
+            and (index.start is not None and index.start < 0)
+            or (index.stop is not None and index.stop < 0)
         ):
             raise IndexError("Version index cannot be negative")
 
-        # Could raise IndexError:
-        part = tuple(filter(None, self.to_tuple()[index]))
+        part = tuple(filter(lambda p: p is not None, self.to_tuple()[index]))
 
         if len(part) == 1:
             part = part[0]
-        if not part:
+        elif not part:
             raise IndexError("Version part undefined")
         return part
 


Test patch:
diff --git a/test_semver.py b/test_semver.py
index 8ecc81f..1fd87ee 100644
--- a/test_semver.py
+++ b/test_semver.py
@@ -774,6 +774,8 @@ def test_should_be_able_to_use_integers_as_prerelease_build():
         ("1.2.3", 0, 1),
         ("1.2.3", 1, 2),
         ("1.2.3", 2, 3),
+        # Special cases
+        ("1.0.2", 1, 0),
     ],
 )
 def test_version_info_should_be_accessed_with_index(version, index, expected):
@@ -801,6 +803,7 @@ def test_version_info_should_be_accessed_with_index(version, index, expected):
         ("1.2.3-rc.0+build.0", slice(0, 5, 2), (1, 3, "build.0")),
         ("1.2.3-rc.0+build.0", slice(None, 5, 2), (1, 3, "build.0")),
         ("1.2.3-rc.0+build.0", slice(5, 0, -2), ("build.0", 3)),
+        ("1.2.0-rc.0+build.0", slice(3), (1, 2, 0)),
     ],
 )
 def test_version_info_should_be_accessed_with_slice_object(
@@ -813,19 +816,37 @@ def test_version_info_should_be_accessed_with_slice_object(
 @pytest.mark.parametrize(
     "version, index",
     [
-        ("1.2.3-rc.0+build.0", -1),
-        ("1.2.3-rc.0", -1),
-        ("1.2.3-rc.0", 4),
-        ("1.2.3", -1),
         ("1.2.3", 3),
+        ("1.2.3", slice(3, 4)),
         ("1.2.3", 4),
-        ("1.2.3", 10),
-        ("1.2.3", slice(-3)),
+        ("1.2.3", slice(4, 5)),
+        ("1.2.3", 5),
+        ("1.2.3", slice(5, 6)),
+        ("1.2.3-rc.0", 5),
+        ("1.2.3-rc.0", slice(5, 6)),
+        ("1.2.3-rc.0", 6),
+        ("1.2.3-rc.0", slice(6, 7)),
     ],
 )
 def test_version_info_should_throw_index_error(version, index):
     version_info = VersionInfo.parse(version)
-    with pytest.raises(IndexError):
+    with pytest.raises(IndexError, match=r"Version part undefined"):
+        version_info[index]
+
+
+@pytest.mark.parametrize(
+    "version, index",
+    [
+        ("1.2.3", -1),
+        ("1.2.3", -2),
+        ("1.2.3", slice(-2, 2)),
+        ("1.2.3", slice(2, -2)),
+        ("1.2.3", slice(-2, -2)),
+    ],
+)
+def test_version_info_should_throw_index_error_when_negative_index(version, index):
+    version_info = VersionInfo.parse(version)
+    with pytest.raises(IndexError, match=r"Version index cannot be negative"):
         version_info[index]