Repository: sdv-dev/RDT (language: python)

Issue:
Create `validate_transformer_code_style` function
A function should be implemented to automatically validate the code style of any new Transformer.

## Function Name and Module

The function should be implemented inside `tests/contributing.py` and should be called `validate_transformer_code_style`

## Inputs

The function should accept a single input:

* `transformer (class or str)`: Transformer class or full Python name of the class (e.g. `DatetimeTransformer` or `"rdt.transformers.time.DatetimeTransformer"`)

## Outputs

The function should return a single `bool` value indicating whether the code style is correct or not.

## Behavior

The function should run all the third party code style checkers (`flake8`, `isort`, `pylint`...) as well custom code analysis checks and report whether all of them pass, as well as feedback about why they do not otherwise.

### List of Checks

The following validations must be performed and reported:



Check | Correct If | What does it check
-- | -- | --
flake8 | flake8 check passes | PEP8 standards and basic static code analysis
isort | isort check passes | Imports are properly sorted
pylint | pylint check passes | Static code analysis and programming style
pydocstyle | pydocstyle check passes | Whether the docstrings are written in the right format
Transformer Name | The Transformer name is correct | Transformer name ends with `Transformer` (e.g. `DatetimeTransformer`)
Unit Tests Exist | The unit tests module exists and is located in the right place | The unit tests module should be located called `tests/unit/transformers/<transformer_family>/<data_type>.py`
Unit Test function names | The unit test function names are correct | The unit test function names should be called `test_<method_name>_<test_case_name>`

### Prints to console

The function prints several messages on the console indicating:
* The path to the source file of the Transformer, which is being analyzed.
* A message indicating whether the code style is correct or not.
* A list of things that were validated and whether they were correct or not (list above).

## Usage Examples

### Success

![image](https://user-images.githubusercontent.com/6129283/134681632-082d2a75-ec57-4fbb-a665-87d346b2899d.png)

### External tool failure

![image1](https://user-images.githubusercontent.com/6129283/134681447-45dbad16-9edf-470a-8ca8-77dc90babc30.png)

### Custom validation failure

![image8](https://user-images.githubusercontent.com/6129283/134681759-2018862c-58d5-4e79-adee-202d72c28667.png)



Discussion / hints:
The current format of our `docstrings` follows the [Google style guide](https://google.github.io/styleguide/pyguide.html), we can add `pydocstyle` and setting the `convention` to `google`. 

However there is a bug in their library which produces `D417 Missing arguments description`, which we do have, and occurs all over our `docstrings` and we will have to ignore the `D417` until this issue is fixed. Reference to the issue: https://github.com/PyCQA/pydocstyle/issues/449

Fix patch:
diff --git a/setup.py b/setup.py
index 04fc26626..4d9e67f6c 100644
--- a/setup.py
+++ b/setup.py
@@ -73,6 +73,7 @@
     'flake8-print>=4.0.0,<4.1',
     'isort>=4.3.4,<5',
     'pylint>=2.5.3,<3',
+    'flake8-expression-complexity>=0.0.9,<0.1',
     'pep8-naming>=0.12.1,<0.13',
 
     # fix style issues


Test patch:
diff --git a/tests/integration/test_hyper_transformer.py b/tests/integration/test_hyper_transformer.py
index 4f8edb1d7..b826d6257 100644
--- a/tests/integration/test_hyper_transformer.py
+++ b/tests/integration/test_hyper_transformer.py
@@ -60,15 +60,15 @@ def _transform(self, data):
         data.columns = [c.replace('_str.value', '') for c in data.columns]
         data = pd.to_datetime(data)
 
-        out = pd.DataFrame(dict(zip(
+        output = dict(zip(
             self.output_columns,
-            [
-                data.values.astype(np.float64),
-                data.isnull().astype(np.float64)
-            ]
-        ))).fillna(-1)
+            [data.values.astype(np.float64), data.isnull().astype(np.float64)]
+        ))
 
-        return out
+        output = pd.DataFrame(output)
+        output.fillna(-1, inplace=True)
+
+        return output
 
     def _reverse_transform(self, data):
         datetimes = data.round().astype('datetime64[ns]')
diff --git a/tests/integration/transformers/test_base.py b/tests/integration/transformers/test_base.py
index 82e205a2a..01fbffd1f 100644
--- a/tests/integration/transformers/test_base.py
+++ b/tests/integration/transformers/test_base.py
@@ -111,10 +111,11 @@ def _transform(self, data):
             return out
 
         def _reverse_transform(self, data):
-            out = data[self.output_columns[0]].round().astype(bool).astype(object)
-            out.iloc[data[self.output_columns[1]] == 1] = np.nan
+            output = data[self.output_columns[0]]
+            output = output.round().astype(bool).astype(object)
+            output.iloc[data[self.output_columns[1]] == 1] = np.nan
 
-            return out
+            return output
 
     # Run
     data = pd.DataFrame({
@@ -175,15 +176,15 @@ def _transform(self, data):
             # Convert multiple columns into a single datetime
             data = pd.to_datetime(data)
 
-            out = pd.DataFrame(dict(zip(
+            output = dict(zip(
                 self.output_columns,
-                [
-                    data.values.astype(np.float64),
-                    data.isnull().astype(np.float64)
-                ]
-            ))).fillna(-1)
+                [data.values.astype(np.float64), data.isnull().astype(np.float64)]
+            ))
 
-            return out
+            output = pd.DataFrame(output)
+            output.fillna(-1, inplace=True)
+
+            return output
 
         def _reverse_transform(self, data):
             datetimes = data.round().astype('datetime64[ns]')