Skip to content

Commit 6f56833

Browse files
bazarnovOleksandr Bazarnov
andauthored
🐛 Source HubSpot: Fix empty string inside number / float datatype (#5334)
#5293 - Source Hubspot fails in normalization step Co-authored-by: Oleksandr Bazarnov <oleksandr.bazarnov@globallogic.com>
1 parent acab9dd commit 6f56833

File tree

24 files changed

+298
-232
lines changed

24 files changed

+298
-232
lines changed

airbyte-config/init/src/main/resources/config/STANDARD_SOURCE_DEFINITION/36c891d9-4bd9-43ac-bad2-10e12756272c.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"sourceDefinitionId": "36c891d9-4bd9-43ac-bad2-10e12756272c",
33
"name": "Hubspot",
44
"dockerRepository": "airbyte/source-hubspot",
5-
"dockerImageTag": "0.1.8",
5+
"dockerImageTag": "0.1.9",
66
"documentationUrl": "https://docs.airbyte.io/integrations/sources/hubspot",
77
"icon": "hubspot.svg"
88
}

airbyte-config/init/src/main/resources/seed/source_definitions.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,7 @@
137137
- sourceDefinitionId: 36c891d9-4bd9-43ac-bad2-10e12756272c
138138
name: Hubspot
139139
dockerRepository: airbyte/source-hubspot
140-
dockerImageTag: 0.1.8
140+
dockerImageTag: 0.1.9
141141
documentationUrl: https://docs.airbyte.io/integrations/sources/hubspot
142142
icon: hubspot.svg
143143
- sourceDefinitionId: 95e8cffd-b8c4-4039-968e-d32fb4a69bde

airbyte-integrations/connectors/source-hubspot/Dockerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,5 +14,5 @@ RUN pip install .
1414

1515
ENV AIRBYTE_ENTRYPOINT "/airbyte/base.sh"
1616

17-
LABEL io.airbyte.version=0.1.8
17+
LABEL io.airbyte.version=0.1.9
1818
LABEL io.airbyte.name=airbyte/source-hubspot

airbyte-integrations/connectors/source-hubspot/README.md

Lines changed: 45 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -53,12 +53,51 @@ python main_dev.py discover --config secrets/config.json
5353
python main_dev.py read --config secrets/config.json --catalog sample_files/configured_catalog.json
5454
```
5555

56+
## Testing
57+
Make sure to familiarize yourself with [pytest test discovery](https://docs.pytest.org/en/latest/goodpractices.html#test-discovery) to know how your test files and methods should be named.
58+
First install test dependencies into your virtual environment:
59+
```
60+
pip install .[tests]
61+
```
62+
5663
### Unit Tests
5764
To run unit tests locally, from the connector directory run:
5865
```
5966
python -m pytest unit_tests
6067
```
6168

69+
### Integration Tests
70+
There are two types of integration tests: Acceptance Tests (Airbyte's test suite for all source connectors) and custom integration tests (which are specific to this connector).
71+
72+
#### Custom Integration tests
73+
Place custom tests inside `integration_tests/` folder, then, from the connector root, run
74+
```
75+
python -m pytest integration_tests
76+
```
77+
78+
#### Acceptance Tests
79+
Customize `acceptance-test-config.yml` file to configure tests. See [Source Acceptance Tests](https://docs.airbyte.io/connector-development/testing-connectors/source-acceptance-tests-reference) for more information.
80+
If your connector requires to create or destroy resources for use during acceptance tests create fixtures for it and place them inside integration_tests/acceptance.py.
81+
82+
To run your integration tests with acceptance tests, from the connector root, run
83+
```
84+
python -m pytest integration_tests -p integration_tests.acceptance
85+
```
86+
87+
To run your integration tests with docker
88+
89+
### Using gradle to run tests
90+
All commands should be run from airbyte project root.
91+
To run unit tests:
92+
```
93+
./gradlew :airbyte-integrations:connectors:source-hubspot:unitTest
94+
```
95+
96+
To run acceptance and custom integration tests:
97+
```
98+
./gradlew :airbyte-integrations:connectors:source-hubspot:integrationTest
99+
```
100+
62101
### Locally running the connector docker image
63102

64103
#### Build
@@ -85,16 +124,16 @@ docker run --rm -v $(pwd)/secrets:/secrets -v $(pwd)/sample_files:/sample_files
85124

86125
### Integration Tests
87126
1. From the airbyte project root, run `./gradlew :airbyte-integrations:connectors:source-hubspot:integrationTest` to run the standard integration test suite.
88-
1. To run additional integration tests, place your integration tests in a new directory `integration_tests` and run them with `python -m pytest -s integration_tests`.
89-
Make sure to familiarize yourself with [pytest test discovery](https://docs.pytest.org/en/latest/goodpractices.html#test-discovery) to know how your test files and methods should be named.
127+
2. To run additional integration tests, place your integration tests in a new directory `integration_tests` and run them with `python -m pytest -s integration_tests`.
128+
Make sure to familiarize yourself with [pytest test discovery](https://docs.pytest.org/en/latest/goodpractices.html#test-discovery) to know how your test files and methods should be named.
90129

91130
## Dependency Management
92131
All of your dependencies should go in `setup.py`, NOT `requirements.txt`. The requirements file is only used to connect internal Airbyte dependencies in the monorepo for local development.
93132

94133
### Publishing a new version of the connector
95134
You've checked out the repo, implemented a million dollar feature, and you're ready to share your changes with the world. Now what?
96135
1. Make sure your changes are passing unit and integration tests
97-
1. Bump the connector version in `Dockerfile` -- just increment the value of the `LABEL io.airbyte.version` appropriately (we use SemVer).
98-
1. Create a Pull Request
99-
1. Pat yourself on the back for being an awesome contributor
100-
1. Someone from Airbyte will take a look at your PR and iterate with you to merge it into master
136+
2. Bump the connector version in `Dockerfile` -- just increment the value of the `LABEL io.airbyte.version` appropriately (we use SemVer).
137+
3. Create a Pull Request
138+
4. Pat yourself on the back for being an awesome contributor
139+
5. Someone from Airbyte will take a look at your PR and iterate with you to merge it into master

airbyte-integrations/connectors/source-hubspot/setup.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,9 @@
2828
MAIN_REQUIREMENTS = [
2929
"airbyte-protocol",
3030
"base-python",
31-
"backoff==1.10.0",
32-
"pendulum==1.2.0",
33-
"requests==2.25.1",
31+
"backoff==1.11.1",
32+
"pendulum==2.1.2",
33+
"requests==2.26.0",
3434
]
3535

3636
TEST_REQUIREMENTS = [

airbyte-integrations/connectors/source-hubspot/source_hubspot/api.py

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -273,12 +273,17 @@ def _cast_value(declared_field_types: List, field_name: str, field_value):
273273
target_type = CUSTOM_FIELD_VALUE_TYPE_CAST_REVERSED.get(target_type_name)
274274

275275
if target_type_name == "number":
276-
if field_name.endswith("_id"):
277-
# do not cast numeric IDs into float, use integer instead
278-
target_type = int
276+
# do not cast numeric IDs into float, use integer instead
277+
target_type = int if field_name.endswith("_id") else target_type
278+
279+
if target_type_name != "string" and field_value == '':
280+
# do not cast empty strings, return None instead to be properly casted.
281+
field_value = None
282+
return field_value
279283

280284
try:
281285
casted_value = target_type(field_value)
286+
print(casted_value)
282287
except ValueError:
283288
logger.exception(f"Could not cast `{field_value}` to `{target_type}`")
284289
return field_value
@@ -451,7 +456,7 @@ def read(self, getter: Callable, params: Mapping[str, Any] = None) -> Iterator:
451456
self._start_date = self._state
452457

453458
def read_chunked(
454-
self, getter: Callable, params: Mapping[str, Any] = None, chunk_size: pendulum.Interval = pendulum.interval(days=1)
459+
self, getter: Callable, params: Mapping[str, Any] = None, chunk_size: pendulum.duration = pendulum.duration(days=1)
455460
) -> Iterator:
456461
params = {**params} if params else {}
457462
now_ts = int(pendulum.now().timestamp() * 1000)

airbyte-integrations/connectors/source-hubspot/source_hubspot/schemas/campaigns.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@
8686
"type": ["null", "string"]
8787
},
8888
"lastUpdatedTime": {
89-
"type": "integer"
89+
"type": ["null", "integer"]
9090
}
9191
}
9292
}

airbyte-integrations/connectors/source-hubspot/source_hubspot/schemas/companies.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
"type": ["null", "integer"]
77
},
88
"companyId": {
9-
"type": "integer"
9+
"type": ["null", "integer"]
1010
},
1111
"isDeleted": {
1212
"type": ["null", "boolean"]
@@ -24,10 +24,10 @@
2424
"type": ["null", "array"]
2525
},
2626
"createdAt": {
27-
"type": "string"
27+
"type": ["null", "string"]
2828
},
2929
"updatedAt": {
30-
"type": "string"
30+
"type": ["null", "string"]
3131
}
3232
}
3333
}

airbyte-integrations/connectors/source-hubspot/source_hubspot/schemas/contact_lists.json

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
"type": ["null", "integer"]
77
},
88
"metaData": {
9-
"type": "object",
9+
"type": ["null", "object"],
1010
"properties": {
1111
"processing": {
1212
"type": ["null", "string"]
@@ -21,7 +21,7 @@
2121
"type": ["null", "integer"]
2222
},
2323
"lastSizeChangeAt": {
24-
"type": "integer"
24+
"type": ["null", "integer"]
2525
}
2626
}
2727
},
@@ -32,11 +32,11 @@
3232
"type": ["null", "string"]
3333
},
3434
"filters": {
35-
"type": "array",
35+
"type": ["null", "array"],
3636
"items": {
37-
"type": "array",
37+
"type": ["null", "array"],
3838
"items": {
39-
"type": "object",
39+
"type": ["null", "object"],
4040
"properties": {
4141
"filterFamily": {
4242
"type": ["null", "string"]
@@ -67,13 +67,13 @@
6767
"type": ["null", "integer"]
6868
},
6969
"createdAt": {
70-
"type": "integer"
70+
"type": ["null", "integer"]
7171
},
7272
"listId": {
7373
"type": ["null", "integer"]
7474
},
7575
"updatedAt": {
76-
"type": "integer"
76+
"type": ["null", "integer"]
7777
},
7878
"internalListId": {
7979
"type": ["null", "integer"]

0 commit comments

Comments
 (0)