Repository: linw1995/data_extractor

Issue:
The field name is the same as Item's parameter in Item.

```python3
class Parameter(Item):
    name = Field(XPathExtractor("./span[@class='name']"))
    default = Field(XPathExtractor("./span[@class='default']"))

extractor = Parameter(XPathExtractor("./li[@class='parameter']", default=None)
```
the `default=None` parameter overwrites the Field `default = Field(XPathExtractor("./span[@class='default']"))` of Item.

Discussion:
codecov-io: # [Codecov](https://codecov.io/gh/linw1995/data_extractor/pull/18?src=pr&el=h1) Report
> Merging [#18](https://codecov.io/gh/linw1995/data_extractor/pull/18?src=pr&el=desc) into [master](https://codecov.io/gh/linw1995/data_extractor/commit/ee4cc11a17b617461cf93168bbcd81fbbc14db07?src=pr&el=desc) will **not change** coverage.
> The diff coverage is `100%`.

[![Impacted file tree graph](https://codecov.io/gh/linw1995/data_extractor/pull/18/graphs/tree.svg?width=650&token=wLe2IyZWQl&height=150&src=pr)](https://codecov.io/gh/linw1995/data_extractor/pull/18?src=pr&el=tree)

```diff
@@          Coverage Diff          @@
##           master    #18   +/-   ##
=====================================
  Coverage     100%   100%           
=====================================
  Files           7      7           
  Lines         148    152    +4     
  Branches       20     21    +1     
=====================================
+ Hits          148    152    +4
```


| [Impacted Files](https://codecov.io/gh/linw1995/data_extractor/pull/18?src=pr&el=tree) | Coverage Δ | |
|---|---|---|
| [data\_extractor/abc.py](https://codecov.io/gh/linw1995/data_extractor/pull/18/diff?src=pr&el=tree#diff-ZGF0YV9leHRyYWN0b3IvYWJjLnB5) | `100% <100%> (ø)` | :arrow_up: |

------

[Continue to review full report at Codecov](https://codecov.io/gh/linw1995/data_extractor/pull/18?src=pr&el=continue).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/linw1995/data_extractor/pull/18?src=pr&el=footer). Last update [ee4cc11...daec6ae](https://codecov.io/gh/linw1995/data_extractor/pull/18?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).


Patch:
diff --git a/data_extractor/abc.py b/data_extractor/abc.py
index 0c2434e..115b15e 100644
--- a/data_extractor/abc.py
+++ b/data_extractor/abc.py
@@ -3,6 +3,7 @@
 ====================================
 """
 # Standard Library
+import inspect
 import warnings
 
 from abc import abstractmethod
@@ -20,8 +21,41 @@ class ComplexExtractorMeta(type):
     def __init__(cls, name: str, bases: Tuple[type], attr_dict: Dict[str, Any]):
         super().__init__(name, bases, attr_dict)
         field_names: List[str] = []
+
+        __init_args = inspect.getfullargspec(getattr(cls, "__init__")).args
+
         for key, attr in attr_dict.items():
             if isinstance(type(attr), ComplexExtractorMeta):
+                if key in __init_args:
+                    frame = inspect.currentframe()
+                    assert (
+                        frame is not None
+                    ), "If running in an implementation without Python stack frame support this function returns None."
+                    try:
+                        outer_frame = frame.f_back
+
+                        filename = outer_frame.f_code.co_filename
+                        firstlineno = outer_frame.f_lineno
+                        lines, _ = inspect.findsource(outer_frame)
+
+                        for lineno, line in enumerate(lines[firstlineno:], start=1):
+                            if line.strip().startswith(key):
+                                break
+                        else:  # pragma: no cover
+                            assert False, "This line is never executed."
+
+                        lineno += firstlineno
+                        index = inspect.indentsize(line)
+                    finally:
+                        del outer_frame
+                        del frame
+
+                    line = line.strip()
+                    raise SyntaxError(
+                        f"{line!r} overwriten the parameter {key!r} of '{name}.__init__' method.",
+                        (filename, lineno, index, line),
+                    )
+
                 field_names.append(key)
 
         cls._field_names = field_names


Test patch:
diff --git a/tests/test_exceptions.py b/tests/test_exceptions.py
index decde7e..7f8cbe9 100644
--- a/tests/test_exceptions.py
+++ b/tests/test_exceptions.py
@@ -1,4 +1,5 @@
 # Standard Library
+import inspect
 import textwrap
 
 # Third Party Library
@@ -8,6 +9,7 @@ import pytest
 from data_extractor.exceptions import ExtractError
 from data_extractor.item import Field, Item
 from data_extractor.json import JSONExtractor
+from data_extractor.lxml import XPathExtractor
 
 
 def test_exception_trace(json0):
@@ -47,3 +49,17 @@ def test_exception_trace(json0):
             """
         ).strip()
     )
+
+
+def test_field_name_overwrite_item_parameter():
+    with pytest.raises(SyntaxError) as catch:
+
+        class Parameter(Item):
+            name = Field(XPathExtractor("./span[@class='name']"))
+            default = Field(XPathExtractor("./span[@class='default']"))
+
+    exc = catch.value
+    assert exc.filename == __file__
+    assert exc.lineno == inspect.currentframe().f_lineno - 4
+    assert exc.offset == 12
+    assert exc.text == "default = Field(XPathExtractor(\"./span[@class='default']\"))"