Repository: linw1995/data_extractor

Issue:
need to check extractors of the super class available or not
https://github.com/linw1995/data_extractor/blob/0c5c8640a207e9785a856787cc5b327ff7b7724c/data_extractor/core.py#L198-L214

Below test case means to be pass.

```python
    @pytest.mark.usefixtures("json_extractor_backend")
    def test_item_remove_super_extractor():
        class User(Item):
            id = Field(JSONExtractor("id"))

        class NoIdUser(User):
            id = None  # bad example to show how to remove super class sub-extractors

        extractor = NoIdUser()
        assert extractor.extract({"id": 1}) == {}
```

But how to remove or deactivate the super class sub-extractors properly? I will open a new issue to discuss.

Discussion:

Patch:
diff --git a/README.rst b/README.rst
index 903d19c..efbd40c 100644
--- a/README.rst
+++ b/README.rst
@@ -112,6 +112,7 @@ Unreleased
 
 - remove LICENSE file from dist files
 - duplicated extracting if class attrs overlap happened #67
+- remove super class sub-extractors error #68
 
 **Refactor**
 
diff --git a/data_extractor/core.py b/data_extractor/core.py
index 5cd1363..fecbb5f 100644
--- a/data_extractor/core.py
+++ b/data_extractor/core.py
@@ -195,7 +195,7 @@ class ComplexExtractorMeta(SimpleExtractorMeta):
     ):
         super().__init__(name, bases, attr_dict)
 
-        field_names = []
+        field_names = set()
         for key, attr in attr_dict.items():
             if isinstance(type(attr), ComplexExtractorMeta):
                 # can't using data_extractor.utils.is_complex_extractor here,
@@ -204,14 +204,18 @@ class ComplexExtractorMeta(SimpleExtractorMeta):
                 _check_field_overwrites_bases_method(cls, name, bases, key, attr)
                 _check_field_overwrites_bases_property(cls, name, bases, key, attr)
 
-                field_names.append(key)
+                field_names.add(key)
 
         # check field overwrites method
         _check_field_overwrites_method(cls)
 
-        cls._field_names: Tuple[str, ...] = tuple(
-            set(field_names) | set(getattr(cls, "_field_names", []))
-        )
+        field_names |= set(getattr(cls, "_field_names", []))
+        for key in field_names.copy():
+            attr = getattr(cls, key, None)
+            if not attr or not isinstance(type(attr), ComplexExtractorMeta):
+                field_names.remove(key)
+
+        cls._field_names: Tuple[str, ...] = tuple(field_names)
 
 
 class AbstractSimpleExtractor(metaclass=SimpleExtractorMeta):
diff --git a/docs/source/changelog.rst b/docs/source/changelog.rst
index 18c393e..c34a2c9 100644
--- a/docs/source/changelog.rst
+++ b/docs/source/changelog.rst
@@ -13,6 +13,7 @@ Unreleased
 
 - remove LICENSE file from dist files
 - duplicated extracting if class attrs overlap happened #67
+- remove super class sub-extractors error #68
 
 **Refactor**
 


Test patch:
diff --git a/tests/test_item.py b/tests/test_item.py
index 5a20702..0f4d731 100644
--- a/tests/test_item.py
+++ b/tests/test_item.py
@@ -1552,3 +1552,16 @@ def test_simplified_nested_item_extract():
 
     extractor = Users().simplify()
     assert extractor.extract_first({}) == {"users": [], "count": 0}
+
+
+@pytest.mark.usefixtures("json_extractor_backend")
+def test_item_remove_super_extractor():
+    class User(Item):
+        id = Field(JSONExtractor("id"))
+
+    class NoIdUser(User):
+        # bad example to show how to remove super class sub-extractors
+        id = None  # type: ignore
+
+    extractor = NoIdUser()
+    assert extractor.extract({"id": 1}) == {}