I'm trying to create a shared object with Python to read a CSV file to be used by a C application.
I'm having a really hard time doing this.
My code is here:
from cffi import FFI
import csv
import io
ffi = FFI()
ffi.cdef("""
void processCsv(const char[], const char[], const char[]);
void processCsvFile(const char[], const char[], const char[]);
""")
def process_csv(csv_data, selected_columns, row_filter_definitions):
# Parse the CSV data
csv_reader = csv.DictReader(io.StringIO(csv_data.decode('utf-8')))
headers = csv_reader.fieldnames
# Parse selected columns
if selected_columns:
selected_columns = selected_columns.decode('utf-8').split(',')
else:
selected_columns = headers
# Parse filters
filters = []
if row_filter_definitions:
for line in row_filter_definitions.decode('utf-8').split('\n'):
if line:
if '=' in line:
header, value = line.split('=')
op = '='
elif '>' in line:
header, value = line.split('>')
op = '>'
elif '<' in line:
header, value = line.split('<')
op = '<'
filters.append((header, op, value))
# Apply filters and select columns
output = io.StringIO()
csv_writer = csv.DictWriter(output, fieldnames=selected_columns)
csv_writer.writeheader()
for row in csv_reader:
match = all((op == '=' and row[header] == value) or
(op == '>' and row[header] > value) or
(op == '<' and row[header] < value) for header, op, value in filters)
if match:
csv_writer.writerow({col: row[col] for col in selected_columns})
print(output.getvalue(), end='')
def process_csv_file(csv_file_path, selected_columns, row_filter_definitions):
with open(csv_file_path.decode('utf-8'), 'r') as f:
process_csv(f.read().encode('utf-8'), selected_columns, row_filter_definitions)
ffi.set_source("_csv_processor",
"""
#include <stdio.h>
void process_csv(const char csv[], const char selectedColumns[], const char rowFilterDefinitions[]);
void process_csv_file(const char csvFilePath[], const char selectedColumns[], const char rowFilterDefinitions[]);
void processCsv(const char csv[], const char selectedColumns[], const char rowFilterDefinitions[]) {
process_csv(csv, selectedColumns, rowFilterDefinitions);
}
void processCsvFile(const char csvFilePath[], const char selectedColumns[], const char rowFilterDefinitions[]) {
process_csv_file(csvFilePath, selectedColumns, rowFilterDefinitions);
}
""")
if __name__ == "__main__":
ffi.compile(verbose=True)
And I'm generating this code with:
python3 csv_processor.py
When I try:
gcc -o programa_c programa_c.c -L. -l_csv_processor -lpython3.10
I receive this error:
/27818bb096b67c55a7a954c23cec29630e6d644e$ gcc -o programa_c programa_c.c -L. -l_csv_processor -lpython3.10
/usr/bin/ld: cannot find -l_csv_processor: No such file or directory
collect2: error: ld returned 1 exit status
The code in C is here:
#include <stdio.h>
void processCsv(const char[], const char[], const char[]);
void processCsvFile(const char[], const char[], const char[]);
int main(){
const char csv[] = "header1,header2,header3\n1,2,3\n4,5,6\n7,8,9";processCsv(csv, "header1,header3", "header1>1\nheader3<9");
const char csv_file[] = "data.csv";
processCsvFile(csv_file, "header1,header3", "header1>1\nheader3<9");
return 0;
}
and I need:
- Implement a library that processes CSV files, applying filters and selecting columns as specified. The solution must be able to integrate with the interface defined in C below.
c /** * Process the CSV data by applying filters and selecting columns. * * @param csv The CSV data to be processed. * @param selectedColumns The columns to be selected from the CSV data. * @param rowFilterDefinitions The filters to be applied to the CSV data.
- @return void */ void processCsv(const char[], const char[], const char[]);
/** * Process the CSV file by applying filters and selecting columns.
- @param csvFilePath The path to the CSV file to be processed. * @param selectedColumns The columns to be selected from the CSV data.
- @param rowFilterDefinitions The filters to be applied to the CSV data. * * @return void */ void processCsvFile(const char[], const char[], const char[]);
processCsv
- csv: String with CSV data, where each line represents a record and the columns are separated by commas.
- Example: "header1,header2,header3\n1,2,3\n4,5,6"
- selectedColumns: A string where the names of the columns to be selected are separated by commas.
- Example: "header1,header3"
- rowFilterDefinitions: A string where each filter is defined on a new line, in the format header(comparador)valor.
- Example: "header1>1\nheader2=2\nheader3<6"
processCsvFile
- csvFilePath: String with the CSV file path.
- Example: "path/to/csv_file.csv"
- selectedColumns: A string where the names of the columns to be selected are separated by commas.
- Example: "header1,header3"
- rowFilterDefinitions: A string where each filter is defined on a new line, in the format header(comparador)valor.
- Example: "header1>1\nheader2=2\nheader3<6"
I don't know where I could be going wrong, as I've never worked with this type of application, it's the first time