Skip to content

Commit

Permalink
Add CSV serialization
Browse files Browse the repository at this point in the history
  • Loading branch information
faph committed Nov 1, 2023
1 parent b6d2656 commit 2839036
Show file tree
Hide file tree
Showing 4 changed files with 86 additions and 2 deletions.
3 changes: 2 additions & 1 deletion src/py_adapter/plugin/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,10 +53,11 @@ def manager() -> pluggy.PluginManager:

def _load_default_plugins(manager_: pluggy.PluginManager) -> None:
"""Load plugins that are packaged with py-adapter"""
from py_adapter.plugin import _avro, _json
from py_adapter.plugin import _avro, _csv, _json

default_plugins = {
"Avro": _avro,
"CSV": _csv,
"JSON": _json,
}
for name, plugin in default_plugins.items():
Expand Down
41 changes: 41 additions & 0 deletions src/py_adapter/plugin/_csv.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# Copyright 2023 J.P. Morgan Chase & Co.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
# specific language governing permissions and limitations under the License.

"""
CSV serializer/deserializer **py-adapter** plugin
"""

import io
from typing import BinaryIO

import py_adapter


@py_adapter.plugin.hook
def serialize(obj: py_adapter.Basic, stream: BinaryIO) -> BinaryIO:
"""
Serialize an object of basic Python types as CSV data
:param obj: Python object to serialize
:param stream: File-like object to serialize data to
"""
import csv

text_stream = io.StringIO(newline="") # csv modules writes as text
csv_writer = csv.DictWriter(text_stream, fieldnames=obj.keys())
csv_writer.writeheader()
csv_writer.writerow(obj)
text_stream.flush()
text_stream.seek(0)

stream.write(text_stream.read().encode("utf-8"))
stream.flush()
return stream
42 changes: 42 additions & 0 deletions tests/test_csv.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# Copyright 2023 J.P. Morgan Chase & Co.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
# specific language governing permissions and limitations under the License.

"""
Test script for CSV serialization/deserialization
"""

import dataclasses
import datetime
from typing import Optional

import pytest

import py_adapter


@dataclasses.dataclass
class SimpleShip:
name: str
build_on: Optional[datetime.date] = None


@pytest.fixture
def simple_ship():
return SimpleShip(
name="Elvira",
build_on=datetime.date(1970, 12, 31),
)


def test_serialize_1_record(simple_ship):
data = py_adapter.serialize(simple_ship, format="CSV")
expected_lines = [b"name,build_on", b"Elvira,1970-12-31"]
assert data.splitlines() == expected_lines
2 changes: 1 addition & 1 deletion tests/test_serialize.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ def test_invalid_format(ship_obj):
py_adapter.plugin.InvalidFormat,
match=re.escape(
"A plugin for serialization format 'does not exist' is not available. Installed plugins/formats are: "
"['Avro', 'JSON']."
"['Avro', 'CSV', 'JSON']."
),
):
py_adapter.serialize(ship_obj, format="does not exist")
Expand Down

0 comments on commit 2839036

Please sign in to comment.