Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Airtable connector #631

Closed
wants to merge 6 commits into from
Closed

Airtable connector #631

wants to merge 6 commits into from

Conversation

Tanmaypatil123
Copy link
Contributor

@Tanmaypatil123 Tanmaypatil123 commented Oct 10, 2023

  • closes #xxxx (Replace xxxx with the GitHub issue number)
  • Tests added and passed if fixing a bug or adding a new feature
  • All code checks passed.

Implemented Airtable connector with the help of official docs.
Required parameters according to new policy of airtable . Authorization token is used for authentication and baseid and table_name required to connect and load data.

Summary by CodeRabbit

New Feature:

  • Added AirtableConnector module to the pandasai package. This module allows users to connect to Airtable records, authenticate, and perform operations like retrieving the head of the table.

Refactor:

  • Introduced a new class AirtableConnectorConfig that extends BaseConnectorConfig to handle the connector configuration for Airtable.

Test:

  • Added a new unit test class TestAirTableConnector to validate the functionality of the AirtableConnector class. The tests cover the constructor, properties, connect_load method, and head method.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Oct 10, 2023

Walkthrough

This change introduces the AirtableConnector module to connect to Airtable records, extending the BaseConnector class. It includes validation and session setup with the Airtable API. A new AirtableConnectorConfig class is added to represent the connector configuration. Unit tests are also provided to ensure the correct behavior of the new connector.

Changes

File Summary
pandasai/connectors/__init__.py New import statement for AirtableConnector module.
pandasai/connectors/airtable.py New AirtableConnector module for connecting to Airtable records. Includes validation and session setup.
pandasai/connectors/base.py New AirtableConnectorConfig class for connector configuration.
tests/connectors/test_airtable.py Unit tests for AirtableConnector class, including constructor, properties, and methods.

🐇

In the land of code, changes are afoot,

With connectors new, and tests to boot.

Airtable's call we now can heed,

Thanks to the coder's skillful deed. 🎉


Tips

Chat with CodeRabbit Bot (@coderabbitai)

  • Mention @coderabbitai in any review comment for bot assistance.
  • Note: Review comments are made on code diffs or files, not on the PR overview.

Pause Incremental Reviews

  • Insert @coderabbitai: ignore in the PR description to halt the bot's ongoing reviews. Remove the line to resume.
  • Additionally, enter @coderabbitai pause to halt the bot's ongoing reviews as any issue or review comment. To
    resume reviews, enter @coderabbitai resume as any issue or review comment.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review Status

Actionable comments generated: 7

Commits Files that changed from the base of the PR and between 3813663 and 8c04ad6.
Files selected for processing (4)
  • pandasai/connectors/init.py (2 hunks)
  • pandasai/connectors/airtable.py (1 hunks)
  • pandasai/connectors/base.py (1 hunks)
  • tests/connectors/test_airtable.py (1 hunks)
Files skipped from review due to trivial changes (1)
  • pandasai/connectors/init.py
Additional comments (Suppressed): 5
tests/connectors/test_airtable.py (2)
  • 9-21: The setUp method is used to set up the testing environment before each test method is run. Here, an instance of AirtableConnectorConfig and AirtableConnector is created. This is a good practice as it reduces code duplication in each test method.

  • 22-28: This test case checks the constructor and properties of the AirtableConnector class. It verifies that the _config attribute is correctly set and that the _session attribute is an instance of requests.Session. It also checks that the Authorization header is correctly set in the _session attribute. This is a good practice as it ensures that the class is correctly initialized.

pandasai/connectors/base.py (2)
  • 74-76: The token and httpPath attributes are already defined in the old hunk. If these are not specific to AirtableConnectorConfig, consider removing them to avoid duplication.
-    token: str
-    httpPath: str
  • 77-83: The AirtableConnectorConfig class is well defined with token and baseID attributes. Ensure that the token and baseID are properly validated before being used in the AirtableConnector class.
pandasai/connectors/airtable.py (1)
  • 1-74: The AirtableConnector class is well-structured and follows the SOLID principles. However, there are a few areas that could be improved for better error handling and maintainability.

Comment on lines +30 to +35
@patch("pandasai.connectors.AirtableConnector._connect_load")
@patch("pandas.DataFrame")
def test_connect_load(self,_connect_load,mock_dataframe):
response = _connect_load(self.config)
self.assertEqual(type(self.connector._response),mock_dataframe())

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This test case checks the _connect_load method of the AirtableConnector class. It verifies that the _response attribute is an instance of pandas.DataFrame. However, the _connect_load method is patched but not used in the test. Instead, the self.config is passed directly to _connect_load which is incorrect. The _connect_load method should be called on the self.connector instance. Here is the corrected code:

-        response = _connect_load(self.config)
+        response = self.connector._connect_load()

Comment on lines +36 to +40
@patch("pandasai.connectors.AirtableConnector.head")
@patch("pandas.DataFrame")
def test_head(self,mock_head,mock_dataframe):
response = mock_head()
self.assertEqual(type(response),mock_dataframe())
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This test case checks the head method of the AirtableConnector class. It verifies that the returned response is an instance of pandas.DataFrame. However, similar to the previous test case, the mock_head method is patched but not used in the test. Instead, the head method should be called on the self.connector instance. Here is the corrected code:

-        response = mock_head()
+        response = self.connector.head()

Comment on lines +15 to +21
def __init__(
self,
baseid : Optional[str] = None,
bearer_token : Optional[str] = None,
table_name : Optional[str] = None,
config : Union[AirtableConnectorConfig,dict] = None
):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The constructor of AirtableConnector accepts both individual parameters and a config object. This could lead to confusion and potential bugs if both are provided but with conflicting values. Consider simplifying the constructor to accept only a config object. This would make the function signature simpler and more maintainable.

Comment on lines +22 to +29
if not bearer_token and not config:
raise ValueError(
"You must specify bearer token for authentication or a config object."
)
if not baseid and not config.baseID:
raise ValueError(
"You must specify baseId or a proper config object."
)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The error messages here are not very informative. It would be better to specify which parameter is missing in the error message. This would make debugging easier.

Comment on lines +30 to +38
if not isinstance(config,AirtableConnectorConfig):
if not config :
config = {}
if table_name :
config['table'] = table_name

airtable_config = AirtableConnectorConfig(**config)
else :
airtable_config = config
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The handling of the config parameter is a bit convoluted. It would be clearer to handle the config parameter separately depending on its type. This would make the code easier to read and maintain.

Comment on lines +57 to +63
_response = self._session.get(f"https://api.airtable.com/v0/{config['baseID']}/{config['table']}")
if _response.status_code == 200 :
self._response = pd.read_json(_response.json())
else :
raise ValueError(
"Please verify authentication details , baseid or table_name are correct ."
)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The error handling here could be improved. If the status code is not 200, it would be helpful to include the status code and the response message in the error. This would make debugging easier.

Comment on lines +66 to +74
def head(self):
"""
Return the head of the table that the connector is connected to.

Returns :
DatFrameType: The head of the data source that the conector is connected to .
"""
return self._response.head()

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The head method assumes that _response is not None and that it is a DataFrame. It would be safer to check that _response is not None and that it is a DataFrame before calling head on it. This would prevent runtime errors.

Here are the suggested changes:

    def __init__(
            self,
-            baseid : Optional[str] = None,
-            bearer_token : Optional[str] = None,
-            table_name : Optional[str] = None,
            config : Union[AirtableConnectorConfig,dict] = None
    ):
-        if not bearer_token and not config:
-            raise ValueError(
-                "You must specify bearer token for authentication or a config object."
-            )
-        if not baseid and not config.baseID:
-            raise ValueError(
-                "You must specify baseId or a proper config object."
-            )
-        if not isinstance(config,AirtableConnectorConfig):
-            if not config :
-                config = {}
-            if table_name :
-                config['table'] = table_name
-            
-            airtable_config = AirtableConnectorConfig(**config)
-        else :
-            airtable_config = config
+        if isinstance(config, dict):
+            airtable_config = AirtableConnectorConfig(**config)
+        elif isinstance(config, AirtableConnectorConfig):
+            airtable_config = config
+        else:
+            raise ValueError("Invalid config parameter. Expected a dict or an AirtableConnectorConfig instance.")

        _response = self._session.get(f"https://api.airtable.com/v0/{config['baseID']}/{config['table']}")
        if _response.status_code == 200 :
            self._response = pd.read_json(_response.json())
        else :
-            raise ValueError(
-                "Please verify authentication details , baseid or table_name are correct ."
-            )
+            raise ValueError(f"Failed to connect to Airtable. Status code: {_response.status_code}, message: {_response.text}")

    def head(self):
        """
        Return the head of the table that the connector is connected to.

        Returns :
            DatFrameType: The head of the data source that the conector is connected to . 
        """
-        return self._response.head()
+        if self._response is not None and isinstance(self._response, pd.DataFrame):
+            return self._response.head()
+        else:
+            raise ValueError("No data loaded. Please call _connect_load first.")

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant