crosscontract 0.2.2__tar.gz → 0.2.3__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (116) hide show
  1. crosscontract-0.2.3/.github/workflows/publish_pypi.yml +57 -0
  2. crosscontract-0.2.2/.github/workflows/publish_pypi.yml → crosscontract-0.2.3/.github/workflows/publish_pypi_test.yml +1 -1
  3. {crosscontract-0.2.2 → crosscontract-0.2.3}/CHANGELOG.md +14 -0
  4. {crosscontract-0.2.2 → crosscontract-0.2.3}/PKG-INFO +1 -1
  5. {crosscontract-0.2.2 → crosscontract-0.2.3}/pyproject.toml +1 -1
  6. {crosscontract-0.2.2 → crosscontract-0.2.3}/src/crosscontract/__init__.py +1 -1
  7. {crosscontract-0.2.2 → crosscontract-0.2.3}/src/crosscontract/crossclient/services/contract_resource.py +30 -1
  8. {crosscontract-0.2.2 → crosscontract-0.2.3}/src/crosscontract/crossclient/services/contract_service.py +1 -0
  9. {crosscontract-0.2.2 → crosscontract-0.2.3}/src/tests/crossclient/contracts/test_contract_resource.py +46 -1
  10. {crosscontract-0.2.2 → crosscontract-0.2.3}/.github/CODEOWNERS +0 -0
  11. {crosscontract-0.2.2 → crosscontract-0.2.3}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
  12. {crosscontract-0.2.2 → crosscontract-0.2.3}/.github/ISSUE_TEMPLATE/discussion---design-proposal.md +0 -0
  13. {crosscontract-0.2.2 → crosscontract-0.2.3}/.github/ISSUE_TEMPLATE/documentation-request.md +0 -0
  14. {crosscontract-0.2.2 → crosscontract-0.2.3}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
  15. {crosscontract-0.2.2 → crosscontract-0.2.3}/.github/ISSUE_TEMPLATE/improvement.md +0 -0
  16. {crosscontract-0.2.2 → crosscontract-0.2.3}/.github/ISSUE_TEMPLATE/maintenance---chore.md +0 -0
  17. {crosscontract-0.2.2 → crosscontract-0.2.3}/.github/ISSUE_TEMPLATE/qa---test-case.md +0 -0
  18. {crosscontract-0.2.2 → crosscontract-0.2.3}/.github/copilot-instructions.md +0 -0
  19. {crosscontract-0.2.2 → crosscontract-0.2.3}/.github/workflows/check_pr_title.yml +0 -0
  20. {crosscontract-0.2.2 → crosscontract-0.2.3}/.github/workflows/check_pr_to_main.yml +0 -0
  21. {crosscontract-0.2.2 → crosscontract-0.2.3}/.github/workflows/deploy_docs.yml +0 -0
  22. {crosscontract-0.2.2 → crosscontract-0.2.3}/.github/workflows/release_main_branch.yml +0 -0
  23. {crosscontract-0.2.2 → crosscontract-0.2.3}/.github/workflows/test_and_coverage.yml +0 -0
  24. {crosscontract-0.2.2 → crosscontract-0.2.3}/.github/workflows/versioning.yml +0 -0
  25. {crosscontract-0.2.2 → crosscontract-0.2.3}/.gitignore +0 -0
  26. {crosscontract-0.2.2 → crosscontract-0.2.3}/.pre-commit-config.yaml +0 -0
  27. {crosscontract-0.2.2 → crosscontract-0.2.3}/.python-version +0 -0
  28. {crosscontract-0.2.2 → crosscontract-0.2.3}/.vscode/launch.json +0 -0
  29. {crosscontract-0.2.2 → crosscontract-0.2.3}/.vscode/settings.json +0 -0
  30. {crosscontract-0.2.2 → crosscontract-0.2.3}/LICENSE +0 -0
  31. {crosscontract-0.2.2 → crosscontract-0.2.3}/README.md +0 -0
  32. {crosscontract-0.2.2 → crosscontract-0.2.3}/docs/about.md +0 -0
  33. {crosscontract-0.2.2 → crosscontract-0.2.3}/docs/client/index.md +0 -0
  34. {crosscontract-0.2.2 → crosscontract-0.2.3}/docs/contracts/gdp_example.yaml +0 -0
  35. {crosscontract-0.2.2 → crosscontract-0.2.3}/docs/contracts/index.md +0 -0
  36. {crosscontract-0.2.2 → crosscontract-0.2.3}/docs/contracts/metadata.md +0 -0
  37. {crosscontract-0.2.2 → crosscontract-0.2.3}/docs/contracts/schema.md +0 -0
  38. {crosscontract-0.2.2 → crosscontract-0.2.3}/docs/index.md +0 -0
  39. {crosscontract-0.2.2 → crosscontract-0.2.3}/docs/notebooks/.gitignore +0 -0
  40. {crosscontract-0.2.2 → crosscontract-0.2.3}/docs/reference/client.md +0 -0
  41. {crosscontract-0.2.2 → crosscontract-0.2.3}/docs/reference/contracts.md +0 -0
  42. {crosscontract-0.2.2 → crosscontract-0.2.3}/mkdocs.yml +0 -0
  43. {crosscontract-0.2.2 → crosscontract-0.2.3}/notebooks/.gitkeep +0 -0
  44. {crosscontract-0.2.2 → crosscontract-0.2.3}/notebooks/client_tutorial.ipynb +0 -0
  45. {crosscontract-0.2.2 → crosscontract-0.2.3}/notebooks/contract_tutorial.ipynb +0 -0
  46. {crosscontract-0.2.2 → crosscontract-0.2.3}/scripts/copy_notebooks_to_docs.py +0 -0
  47. {crosscontract-0.2.2 → crosscontract-0.2.3}/src/crosscontract/contracts/__init__.py +0 -0
  48. {crosscontract-0.2.2 → crosscontract-0.2.3}/src/crosscontract/contracts/contracts/__init__.py +0 -0
  49. {crosscontract-0.2.2 → crosscontract-0.2.3}/src/crosscontract/contracts/contracts/base_contract.py +0 -0
  50. {crosscontract-0.2.2 → crosscontract-0.2.3}/src/crosscontract/contracts/contracts/cross_contract.py +0 -0
  51. {crosscontract-0.2.2 → crosscontract-0.2.3}/src/crosscontract/contracts/schema/__init__.py +0 -0
  52. {crosscontract-0.2.2 → crosscontract-0.2.3}/src/crosscontract/contracts/schema/adapters/__init__.py +0 -0
  53. {crosscontract-0.2.2 → crosscontract-0.2.3}/src/crosscontract/contracts/schema/adapters/abstract_adapter.py +0 -0
  54. {crosscontract-0.2.2 → crosscontract-0.2.3}/src/crosscontract/contracts/schema/adapters/pandera_adapter.py +0 -0
  55. {crosscontract-0.2.2 → crosscontract-0.2.3}/src/crosscontract/contracts/schema/adapters/pydantic_adapter.py +0 -0
  56. {crosscontract-0.2.2 → crosscontract-0.2.3}/src/crosscontract/contracts/schema/adapters/sqlalchemy_adapter.py +0 -0
  57. {crosscontract-0.2.2 → crosscontract-0.2.3}/src/crosscontract/contracts/schema/adapters/utils.py +0 -0
  58. {crosscontract-0.2.2 → crosscontract-0.2.3}/src/crosscontract/contracts/schema/exceptions/__init__.py +0 -0
  59. {crosscontract-0.2.2 → crosscontract-0.2.3}/src/crosscontract/contracts/schema/exceptions/validation_error.py +0 -0
  60. {crosscontract-0.2.2 → crosscontract-0.2.3}/src/crosscontract/contracts/schema/field_descriptors/__init__.py +0 -0
  61. {crosscontract-0.2.2 → crosscontract-0.2.3}/src/crosscontract/contracts/schema/field_descriptors/descriptors.py +0 -0
  62. {crosscontract-0.2.2 → crosscontract-0.2.3}/src/crosscontract/contracts/schema/field_descriptors/field_descriptors.py +0 -0
  63. {crosscontract-0.2.2 → crosscontract-0.2.3}/src/crosscontract/contracts/schema/fields/__init__.py +0 -0
  64. {crosscontract-0.2.2 → crosscontract-0.2.3}/src/crosscontract/contracts/schema/fields/base.py +0 -0
  65. {crosscontract-0.2.2 → crosscontract-0.2.3}/src/crosscontract/contracts/schema/fields/datetime_field.py +0 -0
  66. {crosscontract-0.2.2 → crosscontract-0.2.3}/src/crosscontract/contracts/schema/fields/list_field.py +0 -0
  67. {crosscontract-0.2.2 → crosscontract-0.2.3}/src/crosscontract/contracts/schema/fields/numeric_field.py +0 -0
  68. {crosscontract-0.2.2 → crosscontract-0.2.3}/src/crosscontract/contracts/schema/fields/string_field.py +0 -0
  69. {crosscontract-0.2.2 → crosscontract-0.2.3}/src/crosscontract/contracts/schema/reference/__init__.py +0 -0
  70. {crosscontract-0.2.2 → crosscontract-0.2.3}/src/crosscontract/contracts/schema/reference/foreign_key.py +0 -0
  71. {crosscontract-0.2.2 → crosscontract-0.2.3}/src/crosscontract/contracts/schema/reference/primary_key.py +0 -0
  72. {crosscontract-0.2.2 → crosscontract-0.2.3}/src/crosscontract/contracts/schema/schema.py +0 -0
  73. {crosscontract-0.2.2 → crosscontract-0.2.3}/src/crosscontract/contracts/schema/validation/__init__.py +0 -0
  74. {crosscontract-0.2.2 → crosscontract-0.2.3}/src/crosscontract/contracts/schema/validation/validate_dataframe.py +0 -0
  75. {crosscontract-0.2.2 → crosscontract-0.2.3}/src/crosscontract/contracts/utils.py +0 -0
  76. {crosscontract-0.2.2 → crosscontract-0.2.3}/src/crosscontract/contracts/valid_items.py +0 -0
  77. {crosscontract-0.2.2 → crosscontract-0.2.3}/src/crosscontract/crossclient/__init__.py +0 -0
  78. {crosscontract-0.2.2 → crosscontract-0.2.3}/src/crosscontract/crossclient/crossclient.py +0 -0
  79. {crosscontract-0.2.2 → crosscontract-0.2.3}/src/crosscontract/crossclient/exceptions/__init__.py +0 -0
  80. {crosscontract-0.2.2 → crosscontract-0.2.3}/src/crosscontract/crossclient/exceptions/exception_factory.py +0 -0
  81. {crosscontract-0.2.2 → crosscontract-0.2.3}/src/crosscontract/crossclient/exceptions/exceptions.py +0 -0
  82. {crosscontract-0.2.2 → crosscontract-0.2.3}/src/crosscontract/crossclient/logger.py +0 -0
  83. {crosscontract-0.2.2 → crosscontract-0.2.3}/src/crosscontract/crossclient/services/__init__.py +0 -0
  84. {crosscontract-0.2.2 → crosscontract-0.2.3}/src/crosscontract/py.typed +0 -0
  85. {crosscontract-0.2.2 → crosscontract-0.2.3}/src/tests/__init__.py +0 -0
  86. {crosscontract-0.2.2 → crosscontract-0.2.3}/src/tests/contracts/contracts/test_contracts.py +0 -0
  87. {crosscontract-0.2.2 → crosscontract-0.2.3}/src/tests/contracts/frictionless_package_standard_v2.json +0 -0
  88. {crosscontract-0.2.2 → crosscontract-0.2.3}/src/tests/contracts/frictionless_table_standard_v1.json +0 -0
  89. {crosscontract-0.2.2 → crosscontract-0.2.3}/src/tests/contracts/frictionless_table_standard_v2.json +0 -0
  90. {crosscontract-0.2.2 → crosscontract-0.2.3}/src/tests/contracts/schema/__init__.py +0 -0
  91. {crosscontract-0.2.2 → crosscontract-0.2.3}/src/tests/contracts/schema/adapters/test_integration_pandera.py +0 -0
  92. {crosscontract-0.2.2 → crosscontract-0.2.3}/src/tests/contracts/schema/adapters/test_integration_pandera_references.py +0 -0
  93. {crosscontract-0.2.2 → crosscontract-0.2.3}/src/tests/contracts/schema/adapters/test_integration_pydantic.py +0 -0
  94. {crosscontract-0.2.2 → crosscontract-0.2.3}/src/tests/contracts/schema/adapters/test_pandera_pandas_adapter.py +0 -0
  95. {crosscontract-0.2.2 → crosscontract-0.2.3}/src/tests/contracts/schema/adapters/test_pydantic_adapater.py +0 -0
  96. {crosscontract-0.2.2 → crosscontract-0.2.3}/src/tests/contracts/schema/adapters/test_sqlaqlchemy_adapter.py +0 -0
  97. {crosscontract-0.2.2 → crosscontract-0.2.3}/src/tests/contracts/schema/adapters/test_utils_adapter.py +0 -0
  98. {crosscontract-0.2.2 → crosscontract-0.2.3}/src/tests/contracts/schema/exceptions/__init__.py +0 -0
  99. {crosscontract-0.2.2 → crosscontract-0.2.3}/src/tests/contracts/schema/exceptions/test_validation_error.py +0 -0
  100. {crosscontract-0.2.2 → crosscontract-0.2.3}/src/tests/contracts/schema/reference/__init__.py +0 -0
  101. {crosscontract-0.2.2 → crosscontract-0.2.3}/src/tests/contracts/schema/reference/test_foreign_key.py +0 -0
  102. {crosscontract-0.2.2 → crosscontract-0.2.3}/src/tests/contracts/schema/reference/test_primary_key.py +0 -0
  103. {crosscontract-0.2.2 → crosscontract-0.2.3}/src/tests/contracts/schema/test_descriptors.py +0 -0
  104. {crosscontract-0.2.2 → crosscontract-0.2.3}/src/tests/contracts/schema/test_schema.py +0 -0
  105. {crosscontract-0.2.2 → crosscontract-0.2.3}/src/tests/contracts/schema/validation/__init__.py +0 -0
  106. {crosscontract-0.2.2 → crosscontract-0.2.3}/src/tests/contracts/schema/validation/test_pandas_validation.py +0 -0
  107. {crosscontract-0.2.2 → crosscontract-0.2.3}/src/tests/contracts/simple_contract.yaml +0 -0
  108. {crosscontract-0.2.2 → crosscontract-0.2.3}/src/tests/contracts/test_utils.py +0 -0
  109. {crosscontract-0.2.2 → crosscontract-0.2.3}/src/tests/crossclient/conftest.py +0 -0
  110. {crosscontract-0.2.2 → crosscontract-0.2.3}/src/tests/crossclient/contracts/__init__.py +0 -0
  111. {crosscontract-0.2.2 → crosscontract-0.2.3}/src/tests/crossclient/contracts/test_contracts_service.py +0 -0
  112. {crosscontract-0.2.2 → crosscontract-0.2.3}/src/tests/crossclient/exceptions/__init__.py +0 -0
  113. {crosscontract-0.2.2 → crosscontract-0.2.3}/src/tests/crossclient/exceptions/test_exception_factory.py +0 -0
  114. {crosscontract-0.2.2 → crosscontract-0.2.3}/src/tests/crossclient/exceptions/test_exceptions.py +0 -0
  115. {crosscontract-0.2.2 → crosscontract-0.2.3}/src/tests/crossclient/test_crossclient.py +0 -0
  116. {crosscontract-0.2.2 → crosscontract-0.2.3}/uv.lock +0 -0
@@ -0,0 +1,57 @@
1
+ # Standalone workflow to publish the package to PyPI.
2
+ # Triggered manually. Defaults to the latest release tag.
3
+ name: Publish to PyPI
4
+
5
+ on:
6
+ workflow_dispatch:
7
+ inputs:
8
+ version:
9
+ description: "Version tag to publish (e.g. v0.2.1). Defaults to latest release."
10
+ required: false
11
+ type: string
12
+ default: ""
13
+
14
+ jobs:
15
+ resolve_version:
16
+ runs-on: ubuntu-latest
17
+ outputs:
18
+ tag: ${{ steps.resolve.outputs.tag }}
19
+ steps:
20
+ - name: Get latest release tag
21
+ id: resolve
22
+ env:
23
+ GH_TOKEN: ${{ github.token }}
24
+ run: |
25
+ if [ -n "${{ inputs.version }}" ]; then
26
+ echo "tag=${{ inputs.version }}" >> $GITHUB_OUTPUT
27
+ else
28
+ LATEST=$(gh release view --repo ${{ github.repository }} --json tagName -q .tagName)
29
+ echo "tag=$LATEST" >> $GITHUB_OUTPUT
30
+ fi
31
+ - name: Validate tag exists
32
+ if: inputs.version != ''
33
+ env:
34
+ GH_TOKEN: ${{ github.token }}
35
+ run: |
36
+ if ! gh release view ${{ inputs.version }} --repo ${{ github.repository }} > /dev/null 2>&1; then
37
+ echo "Error: version '${{ inputs.version }}' not found in releases"
38
+ exit 1
39
+ fi
40
+
41
+ publish:
42
+ needs: resolve_version
43
+ runs-on: ubuntu-latest
44
+ environment:
45
+ name: pypi
46
+ url: https://pypi.org/p/crosscontract
47
+ permissions:
48
+ id-token: write
49
+ steps:
50
+ - uses: actions/checkout@v4
51
+ with:
52
+ ref: ${{ needs.resolve_version.outputs.tag }}
53
+ - uses: astral-sh/setup-uv@v5
54
+ - run: uv build
55
+ - name: Inspect wheel contents
56
+ run: unzip -l dist/*.whl
57
+ - uses: pypa/gh-action-pypi-publish@release/v1
@@ -1,6 +1,6 @@
1
1
  # Standalone workflow to publish the package to PyPI.
2
2
  # Triggered manually. Defaults to the latest release tag.
3
- name: Publish to PyPI
3
+ name: Publish to PyPI-Test
4
4
 
5
5
  on:
6
6
  workflow_dispatch:
@@ -2,6 +2,20 @@
2
2
 
3
3
  <!-- version list -->
4
4
 
5
+ ## v0.2.3 (2026-03-08)
6
+
7
+ ### Bug Fixes
8
+
9
+ - Correct format in csv upload for datetime fields
10
+ ([#23](https://github.com/sweet-cross/crosscontract/pull/23),
11
+ [`9501a14`](https://github.com/sweet-cross/crosscontract/commit/9501a14685e90b176982c6cf51d6bd043898b453))
12
+
13
+ ### Chores
14
+
15
+ - Rename action
16
+ ([`ba3822a`](https://github.com/sweet-cross/crosscontract/commit/ba3822a13175809738a1e814ab8beba0d3a06d09))
17
+
18
+
5
19
  ## v0.2.2 (2026-03-05)
6
20
 
7
21
  ### Bug Fixes
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: crosscontract
3
- Version: 0.2.2
3
+ Version: 0.2.3
4
4
  Summary: Provides data contracts with frictionless schemas and client to interact with CROSS data platform.
5
5
  License-File: LICENSE
6
6
  Requires-Python: >=3.11
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "crosscontract"
3
- version = "0.2.2"
3
+ version = "0.2.3"
4
4
  description = "Provides data contracts with frictionless schemas and client to interact with CROSS data platform. "
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.11"
@@ -3,7 +3,7 @@
3
3
  from .contracts import BaseContract, CrossContract, SchemaValidationError, TableSchema
4
4
  from .crossclient import CrossClient
5
5
 
6
- __version__ = "0.2.2"
6
+ __version__ = "0.2.3"
7
7
 
8
8
  __all__ = [
9
9
  "CrossClient",
@@ -119,6 +119,34 @@ class ContractResource:
119
119
  )
120
120
  self._contract = contract
121
121
 
122
+ def _prepare_dataframe_csv_upload(self, df: pd.DataFrame) -> pd.DataFrame:
123
+ """Prepare a DataFrame for CSV upload by formatting datetime columns.
124
+
125
+ This method converts datetime-typed fields defined in the contract's
126
+ table schema from pandas datetime dtypes to string values using the
127
+ field's configured format. Columns of other data types are left
128
+ unchanged.
129
+
130
+ Args:
131
+ df (pd.DataFrame): The input DataFrame to be prepared for CSV upload.
132
+
133
+ Returns:
134
+ pd.DataFrame: The prepared DataFrame ready for CSV upload.
135
+ """
136
+ # convert datetime fields to string with correct format
137
+ dt_fields = [
138
+ f
139
+ for f in self.contract.tableschema.field_iterator()
140
+ if f.type == "datetime" and f.name in df.columns
141
+ ]
142
+ if len(dt_fields) == 0:
143
+ return df
144
+ df_out = df.copy(deep=False)
145
+ for field in dt_fields:
146
+ if pd.api.types.is_datetime64_any_dtype(df[field.name]):
147
+ df_out[field.name] = df_out[field.name].dt.strftime(field.format)
148
+ return df_out
149
+
122
150
  def add_data(self, data: pd.DataFrame, validate: bool = True) -> None:
123
151
  """Add data for the contract on in the CROSS platform.
124
152
 
@@ -134,7 +162,8 @@ class ContractResource:
134
162
  if validate:
135
163
  # validate data against contract schema at the client side
136
164
  self.validate_dataframe(data)
137
- self._service._add_data(self.name, data)
165
+ data_out = self._prepare_dataframe_csv_upload(data)
166
+ self._service._add_data(self.name, data_out)
138
167
 
139
168
  def get_data(
140
169
  self,
@@ -219,6 +219,7 @@ class ContractService:
219
219
  httpx.HTTPStatusError: If the request fails.
220
220
  """
221
221
  endpoint = f"{self._route}{name}/data"
222
+
222
223
  # construct the payload
223
224
  with io.BytesIO(data.to_csv(index=False).encode("utf-8")) as csv_buffer:
224
225
  files = {"file": (f"{name}.csv", csv_buffer, "text/csv")}
@@ -5,7 +5,7 @@ import pytest
5
5
  from polyfactory.factories.pydantic_factory import ModelFactory
6
6
 
7
7
  from crosscontract import CrossContract
8
- from crosscontract.contracts.schema import SchemaValidationError
8
+ from crosscontract.contracts.schema import SchemaValidationError, TableSchema
9
9
  from crosscontract.crossclient.exceptions.exceptions import ValidationError
10
10
  from crosscontract.crossclient.services.contract_resource import ContractResource
11
11
  from crosscontract.crossclient.services.contract_service import ContractService
@@ -175,6 +175,51 @@ class TestAddData:
175
175
  ):
176
176
  contract_resource.add_data(self.data, validate=True)
177
177
 
178
+ def test_prepare_csv_data_success(
179
+ self, contract_factory: type[ModelFactory], service: ContractService
180
+ ):
181
+ """Test preparing CSV data successfully."""
182
+ contract: CrossContract = contract_factory.build(
183
+ name="contract",
184
+ tableschema=TableSchema(
185
+ fields=[
186
+ {"name": "timestamp", "type": "datetime"},
187
+ ],
188
+ foreignKeys=[],
189
+ ),
190
+ )
191
+ resource = ContractResource(
192
+ service=service, name=contract.name, contract=contract, status="Draft"
193
+ )
194
+ data = pd.DataFrame({"timestamp": pd.to_datetime(["2021-01-01", "2021-01-02"])})
195
+
196
+ result = resource._prepare_dataframe_csv_upload(data)
197
+ for org, val in zip(data["timestamp"], result["timestamp"], strict=True):
198
+ assert val == org.strftime(
199
+ resource.contract.tableschema.get("timestamp").format
200
+ )
201
+
202
+ def test_prepare_csv_data_no_datetime_fields(
203
+ self, contract_factory: type[ModelFactory], service: ContractService
204
+ ):
205
+ """Test preparing CSV data when there are no datetime fields."""
206
+ contract: CrossContract = contract_factory.build(
207
+ name="contract",
208
+ tableschema=TableSchema(
209
+ fields=[
210
+ {"name": "timestamp", "type": "string"},
211
+ ],
212
+ foreignKeys=[],
213
+ ),
214
+ )
215
+ resource = ContractResource(
216
+ service=service, name=contract.name, contract=contract, status="Draft"
217
+ )
218
+ data = pd.DataFrame({"timestamp": ["a", "b"]})
219
+
220
+ result = resource._prepare_dataframe_csv_upload(data)
221
+ pd.testing.assert_frame_equal(data, result)
222
+
178
223
 
179
224
  class TestImmutability:
180
225
  def test_immutable_name(self, contract_resource: ContractResource):
File without changes
File without changes
File without changes
File without changes
File without changes