We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
import_verified field missing in table resource
## Description
<!-- A clear and concise description of what the bug is. -->
The Table API does not include the `import_verified` field.

## Expected behavior
<!-- A clear and concise description of what you expected to happen. -->
The frontend needs the `import_verified` field to figure out which tables to show in preview mode and which tables to show normally.

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `mathesar/serializers.py`
Content:
```
1 import requests
2 
3 from django.urls import reverse
4 from rest_framework import serializers
5 from rest_framework.exceptions import ValidationError
6 
7 from mathesar.models import Table, Schema, DataFile, Database, Constraint
8 
9 
10 SUPPORTED_URL_CONTENT_TYPES = {'text/csv', 'text/plain'}
11 
12 
13 class NestedTableSerializer(serializers.HyperlinkedModelSerializer):
14     url = serializers.SerializerMethodField()
15 
16     class Meta:
17         model = Table
18         fields = ['id', 'name', 'url']
19 
20     def get_url(self, obj):
21         request = self.context['request']
22         return request.build_absolute_uri(reverse('table-detail', kwargs={'pk': obj.pk}))
23 
24 
25 class ModelNameField(serializers.CharField):
26     """
27     De-serializes the request field as a string, but serializes the response field as
28     `model.name`. Required to support passing and returing a model name from the
29     endpoint, while also storing the model as a related field.
30     """
31     def to_representation(self, value):
32         return value.name
33 
34 
35 class SchemaSerializer(serializers.HyperlinkedModelSerializer):
36     tables = NestedTableSerializer(many=True, read_only=True)
37     name = serializers.CharField()
38     database = ModelNameField(max_length=128)
39 
40     class Meta:
41         model = Schema
42         fields = ['id', 'name', 'tables', 'database', 'has_dependencies']
43 
44 
45 class TypeOptionSerializer(serializers.Serializer):
46     precision = serializers.IntegerField(required=False)
47     scale = serializers.IntegerField(required=False)
48 
49 
50 class SimpleColumnSerializer(serializers.Serializer):
51     name = serializers.CharField()
52     type = serializers.CharField(source='plain_type')
53     type_options = TypeOptionSerializer(required=False)
54 
55 
56 class ColumnSerializer(SimpleColumnSerializer):
57     index = serializers.IntegerField(source='column_index', read_only=True)
58     nullable = serializers.BooleanField(default=True)
59     primary_key = serializers.BooleanField(default=False)
60     valid_target_types = serializers.ListField(read_only=True)
61 
62 
63 class TableSerializer(serializers.ModelSerializer):
64     columns = SimpleColumnSerializer(many=True, read_only=True, source='sa_columns')
65     records_url = serializers.SerializerMethodField()
66     constraints_url = serializers.SerializerMethodField()
67     columns_url = serializers.SerializerMethodField()
68     name = serializers.CharField(required=False, allow_blank=True, default='')
69     data_files = serializers.PrimaryKeyRelatedField(
70         required=False, many=True, queryset=DataFile.objects.all()
71     )
72 
73     class Meta:
74         model = Table
75         fields = ['id', 'name', 'schema', 'created_at', 'updated_at',
76                   'columns', 'records_url', 'constraints_url', 'columns_url', 'data_files', 'has_dependencies']
77 
78     def get_records_url(self, obj):
79         if isinstance(obj, Table):
80             # Only get records if we are serializing an existing table
81             request = self.context['request']
82             return request.build_absolute_uri(reverse('table-record-list', kwargs={'table_pk': obj.pk}))
83         else:
84             return None
85 
86     def get_constraints_url(self, obj):
87         if isinstance(obj, Table):
88             # Only get constraints if we are serializing an existing table
89             request = self.context['request']
90             return request.build_absolute_uri(reverse('table-constraint-list', kwargs={'table_pk': obj.pk}))
91         else:
92             return None
93 
94     def get_columns_url(self, obj):
95         if isinstance(obj, Table):
96             # Only get columns if we are serializing an existing table
97             request = self.context['request']
98             return request.build_absolute_uri(reverse('table-column-list', kwargs={'table_pk': obj.pk}))
99         else:
100             return None
101 
102     def validate_data_files(self, data_files):
103         if data_files and len(data_files) > 1:
104             raise ValidationError('Multiple data files are unsupported.')
105         return data_files
106 
107 
108 class RecordSerializer(serializers.BaseSerializer):
109     def to_representation(self, instance):
110         return instance._asdict()
111 
112 
113 class TablePreviewSerializer(serializers.Serializer):
114     name = serializers.CharField(required=False)
115     columns = SimpleColumnSerializer(many=True)
116 
117 
118 class RecordListParameterSerializer(serializers.Serializer):
119     filters = serializers.JSONField(required=False, default=[])
120     order_by = serializers.JSONField(required=False, default=[])
121     group_count_by = serializers.JSONField(required=False, default=[])
122 
123 
124 class DatabaseSerializer(serializers.ModelSerializer):
125     supported_types = serializers.ListField(child=serializers.CharField())
126 
127     class Meta:
128         model = Database
129         fields = ['id', 'name', 'deleted', 'supported_types']
130         read_only_fields = ['id', 'name', 'deleted', 'supported_types']
131 
132 
133 class DataFileSerializer(serializers.ModelSerializer):
134     user = serializers.PrimaryKeyRelatedField(
135         default=serializers.CurrentUserDefault(), read_only=True
136     )
137     header = serializers.BooleanField(default=True)
138     paste = serializers.CharField(required=False, trim_whitespace=False)
139     url = serializers.URLField(required=False)
140 
141     class Meta:
142         model = DataFile
143         fields = [
144             'id', 'file', 'table_imported_to', 'user', 'header', 'delimiter',
145             'escapechar', 'quotechar', 'paste', 'url', 'created_from'
146         ]
147         extra_kwargs = {
148             'file': {'required': False},
149             'delimiter': {'trim_whitespace': False},
150             'escapechar': {'trim_whitespace': False},
151             'quotechar': {'trim_whitespace': False}
152         }
153         # We only currently support importing to a new table, so setting a table via API is invalid.
154         # User should be set automatically, not submitted via the API.
155         read_only_fields = ['user', 'table_imported_to', 'created_from']
156         write_only_fields = ['paste', 'url']
157 
158     def save(self, **kwargs):
159         """
160         Set user to current user while saving the data file.
161         """
162         current_user = self.fields['user'].get_default()
163         if current_user.is_authenticated:
164             kwargs['user'] = current_user
165         return super().save(**kwargs)
166 
167     def validate(self, data):
168         if not self.partial:
169             # Only perform validation on source files when we're not partial
170             source_fields = ['file', 'paste', 'url']
171             present_fields = [field for field in source_fields if field in data]
172             if len(present_fields) > 1:
173                 raise ValidationError(
174                     f'Multiple source fields passed: {present_fields}.'
175                     f' Only one of {source_fields} should be specified.'
176                 )
177             elif len(present_fields) == 0:
178                 raise ValidationError(
179                     f'One of {source_fields} should be specified.'
180                 )
181         return data
182 
183     def validate_url(self, url):
184         try:
185             response = requests.head(url, allow_redirects=True)
186         except requests.exceptions.ConnectionError:
187             raise ValidationError('URL cannot be reached.')
188 
189         content_type = response.headers.get('content-type')
190         if content_type not in SUPPORTED_URL_CONTENT_TYPES:
191             raise ValidationError(f"URL resource '{content_type}' not a valid type.")
192         return url
193 
194 
195 class ConstraintSerializer(serializers.ModelSerializer):
196     name = serializers.CharField(required=False)
197     type = serializers.CharField()
198     columns = serializers.ListField()
199 
200     class Meta:
201         model = Constraint
202         fields = ['id', 'name', 'type', 'columns']
203
```

Path: `mathesar/imports/csv.py`
Content:
```
1 from io import TextIOWrapper
2 
3 import clevercsv as csv
4 
5 from mathesar.database.base import create_mathesar_engine
6 from mathesar.models import Table
7 from db import tables, records
8 from mathesar.errors import InvalidTableError
9 
10 ALLOWED_DELIMITERS = ",\t:| "
11 SAMPLE_SIZE = 20000
12 CHECK_ROWS = 10
13 
14 
15 def check_dialect(file, dialect):
16     """
17     Checks to see if we can parse the given file with the given dialect
18 
19     Parses the first CHECK_ROWS rows. Checks to see if any have formatting issues (as
20     indicated by parse_row), or if any have a differing number of columns.
21 
22     Args:
23         file: _io.TextIOWrapper object, an already opened file
24         dialect: csv.Dialect object, the dialect we are validating
25 
26     Returns:
27         bool: False if any error that would cause SQL errors were found, otherwise True
28     """
29     prev_num_columns = None
30     row_gen = csv.read.reader(file, dialect)
31     for _ in range(CHECK_ROWS):
32         try:
33             row = next(row_gen)
34         except StopIteration:
35             # If less than CHECK_ROWS rows in file, stop early
36             break
37 
38         num_columns = len(row)
39         if prev_num_columns is None:
40             prev_num_columns = num_columns
41         elif prev_num_columns != num_columns:
42             return False
43     return True
44 
45 
46 def get_sv_dialect(file):
47     """
48     Given a *sv file, generate a dialect to parse it.
49 
50     Args:
51         file: _io.TextIOWrapper object, an already opened file
52 
53     Returns:
54         dialect: csv.Dialect object, the dialect to parse the file
55 
56     Raises:
57         InvalidTableError: If the generated dialect was unable to parse the file
58     """
59     dialect = csv.detect.Detector().detect(file.read(SAMPLE_SIZE),
60                                            delimiters=ALLOWED_DELIMITERS)
61     if dialect is None:
62         raise InvalidTableError
63 
64     file.seek(0)
65     if check_dialect(file, dialect):
66         file.seek(0)
67         return dialect
68     else:
69         raise InvalidTableError
70 
71 
72 def get_sv_reader(file, header, dialect=None):
73     file = TextIOWrapper(file, encoding="utf-8-sig")
74     if dialect:
75         reader = csv.DictReader(file, dialect=dialect)
76     else:
77         reader = csv.DictReader(file)
78     if not header:
79         reader.fieldnames = [
80             f"column_{i}" for i in range(len(reader.fieldnames))
81         ]
82         file.seek(0)
83     return reader
84 
85 
86 def create_db_table_from_data_file(data_file, name, schema):
87     engine = create_mathesar_engine(schema.database.name)
88     sv_filename = data_file.file.path
89     header = data_file.header
90     dialect = csv.dialect.SimpleDialect(data_file.delimiter, data_file.quotechar,
91                                         data_file.escapechar)
92     with open(sv_filename, 'rb') as sv_file:
93         sv_reader = get_sv_reader(sv_file, header, dialect=dialect)
94         column_names = sv_reader.fieldnames
95         table = tables.create_string_column_table(
96             name=name,
97             schema=schema.name,
98             column_names=column_names,
99             engine=engine
100         )
101     records.create_records_from_csv(
102         table,
103         engine,
104         sv_filename,
105         column_names,
106         header,
107         delimiter=dialect.delimiter,
108         escape=dialect.escapechar,
109         quote=dialect.quotechar,
110     )
111     return table
112 
113 
114 def create_table_from_csv(data_file, name, schema):
115     engine = create_mathesar_engine(schema.database.name)
116     db_table = create_db_table_from_data_file(
117         data_file, name, schema
118     )
119     db_table_oid = tables.get_oid_from_table(db_table.name, db_table.schema, engine)
120     table, _ = Table.objects.get_or_create(oid=db_table_oid, schema=schema)
121     data_file.table_imported_to = table
122     data_file.save()
123     return table
124
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/mathesar/imports/csv.py b/mathesar/imports/csv.py
--- a/mathesar/imports/csv.py
+++ b/mathesar/imports/csv.py
@@ -117,7 +117,7 @@
         data_file, name, schema
     )
     db_table_oid = tables.get_oid_from_table(db_table.name, db_table.schema, engine)
-    table, _ = Table.objects.get_or_create(oid=db_table_oid, schema=schema)
+    table, _ = Table.objects.get_or_create(oid=db_table_oid, schema=schema, import_verified=False)
     data_file.table_imported_to = table
     data_file.save()
     return table
diff --git a/mathesar/serializers.py b/mathesar/serializers.py
--- a/mathesar/serializers.py
+++ b/mathesar/serializers.py
@@ -72,7 +72,7 @@
 
     class Meta:
         model = Table
-        fields = ['id', 'name', 'schema', 'created_at', 'updated_at',
+        fields = ['id', 'name', 'schema', 'created_at', 'updated_at', 'import_verified',
                   'columns', 'records_url', 'constraints_url', 'columns_url', 'data_files', 'has_dependencies']
 
     def get_records_url(self, obj):

{"golden_diff": "diff --git a/mathesar/imports/csv.py b/mathesar/imports/csv.py\n--- a/mathesar/imports/csv.py\n+++ b/mathesar/imports/csv.py\n@@ -117,7 +117,7 @@\n         data_file, name, schema\n     )\n     db_table_oid = tables.get_oid_from_table(db_table.name, db_table.schema, engine)\n-    table, _ = Table.objects.get_or_create(oid=db_table_oid, schema=schema)\n+    table, _ = Table.objects.get_or_create(oid=db_table_oid, schema=schema, import_verified=False)\n     data_file.table_imported_to = table\n     data_file.save()\n     return table\ndiff --git a/mathesar/serializers.py b/mathesar/serializers.py\n--- a/mathesar/serializers.py\n+++ b/mathesar/serializers.py\n@@ -72,7 +72,7 @@\n \n     class Meta:\n         model = Table\n-        fields = ['id', 'name', 'schema', 'created_at', 'updated_at',\n+        fields = ['id', 'name', 'schema', 'created_at', 'updated_at', 'import_verified',\n                   'columns', 'records_url', 'constraints_url', 'columns_url', 'data_files', 'has_dependencies']\n \n     def get_records_url(self, obj):\n", "issue": "import_verified field missing in table resource\n## Description\r\n<!-- A clear and concise description of what the bug is. -->\r\nThe Table API does not include the `import_verified` field.\r\n\r\n## Expected behavior\r\n<!-- A clear and concise description of what you expected to happen. -->\r\nThe frontend needs the `import_verified` field to figure out which tables to show in preview mode and which tables to show normally.\n", "before_files": [{"content": "import requests\n\nfrom django.urls import reverse\nfrom rest_framework import serializers\nfrom rest_framework.exceptions import ValidationError\n\nfrom mathesar.models import Table, Schema, DataFile, Database, Constraint\n\n\nSUPPORTED_URL_CONTENT_TYPES = {'text/csv', 'text/plain'}\n\n\nclass NestedTableSerializer(serializers.HyperlinkedModelSerializer):\n    url = serializers.SerializerMethodField()\n\n    class Meta:\n        model = Table\n        fields = ['id', 'name', 'url']\n\n    def get_url(self, obj):\n        request = self.context['request']\n        return request.build_absolute_uri(reverse('table-detail', kwargs={'pk': obj.pk}))\n\n\nclass ModelNameField(serializers.CharField):\n    \"\"\"\n    De-serializes the request field as a string, but serializes the response field as\n    `model.name`. Required to support passing and returing a model name from the\n    endpoint, while also storing the model as a related field.\n    \"\"\"\n    def to_representation(self, value):\n        return value.name\n\n\nclass SchemaSerializer(serializers.HyperlinkedModelSerializer):\n    tables = NestedTableSerializer(many=True, read_only=True)\n    name = serializers.CharField()\n    database = ModelNameField(max_length=128)\n\n    class Meta:\n        model = Schema\n        fields = ['id', 'name', 'tables', 'database', 'has_dependencies']\n\n\nclass TypeOptionSerializer(serializers.Serializer):\n    precision = serializers.IntegerField(required=False)\n    scale = serializers.IntegerField(required=False)\n\n\nclass SimpleColumnSerializer(serializers.Serializer):\n    name = serializers.CharField()\n    type = serializers.CharField(source='plain_type')\n    type_options = TypeOptionSerializer(required=False)\n\n\nclass ColumnSerializer(SimpleColumnSerializer):\n    index = serializers.IntegerField(source='column_index', read_only=True)\n    nullable = serializers.BooleanField(default=True)\n    primary_key = serializers.BooleanField(default=False)\n    valid_target_types = serializers.ListField(read_only=True)\n\n\nclass TableSerializer(serializers.ModelSerializer):\n    columns = SimpleColumnSerializer(many=True, read_only=True, source='sa_columns')\n    records_url = serializers.SerializerMethodField()\n    constraints_url = serializers.SerializerMethodField()\n    columns_url = serializers.SerializerMethodField()\n    name = serializers.CharField(required=False, allow_blank=True, default='')\n    data_files = serializers.PrimaryKeyRelatedField(\n        required=False, many=True, queryset=DataFile.objects.all()\n    )\n\n    class Meta:\n        model = Table\n        fields = ['id', 'name', 'schema', 'created_at', 'updated_at',\n                  'columns', 'records_url', 'constraints_url', 'columns_url', 'data_files', 'has_dependencies']\n\n    def get_records_url(self, obj):\n        if isinstance(obj, Table):\n            # Only get records if we are serializing an existing table\n            request = self.context['request']\n            return request.build_absolute_uri(reverse('table-record-list', kwargs={'table_pk': obj.pk}))\n        else:\n            return None\n\n    def get_constraints_url(self, obj):\n        if isinstance(obj, Table):\n            # Only get constraints if we are serializing an existing table\n            request = self.context['request']\n            return request.build_absolute_uri(reverse('table-constraint-list', kwargs={'table_pk': obj.pk}))\n        else:\n            return None\n\n    def get_columns_url(self, obj):\n        if isinstance(obj, Table):\n            # Only get columns if we are serializing an existing table\n            request = self.context['request']\n            return request.build_absolute_uri(reverse('table-column-list', kwargs={'table_pk': obj.pk}))\n        else:\n            return None\n\n    def validate_data_files(self, data_files):\n        if data_files and len(data_files) > 1:\n            raise ValidationError('Multiple data files are unsupported.')\n        return data_files\n\n\nclass RecordSerializer(serializers.BaseSerializer):\n    def to_representation(self, instance):\n        return instance._asdict()\n\n\nclass TablePreviewSerializer(serializers.Serializer):\n    name = serializers.CharField(required=False)\n    columns = SimpleColumnSerializer(many=True)\n\n\nclass RecordListParameterSerializer(serializers.Serializer):\n    filters = serializers.JSONField(required=False, default=[])\n    order_by = serializers.JSONField(required=False, default=[])\n    group_count_by = serializers.JSONField(required=False, default=[])\n\n\nclass DatabaseSerializer(serializers.ModelSerializer):\n    supported_types = serializers.ListField(child=serializers.CharField())\n\n    class Meta:\n        model = Database\n        fields = ['id', 'name', 'deleted', 'supported_types']\n        read_only_fields = ['id', 'name', 'deleted', 'supported_types']\n\n\nclass DataFileSerializer(serializers.ModelSerializer):\n    user = serializers.PrimaryKeyRelatedField(\n        default=serializers.CurrentUserDefault(), read_only=True\n    )\n    header = serializers.BooleanField(default=True)\n    paste = serializers.CharField(required=False, trim_whitespace=False)\n    url = serializers.URLField(required=False)\n\n    class Meta:\n        model = DataFile\n        fields = [\n            'id', 'file', 'table_imported_to', 'user', 'header', 'delimiter',\n            'escapechar', 'quotechar', 'paste', 'url', 'created_from'\n        ]\n        extra_kwargs = {\n            'file': {'required': False},\n            'delimiter': {'trim_whitespace': False},\n            'escapechar': {'trim_whitespace': False},\n            'quotechar': {'trim_whitespace': False}\n        }\n        # We only currently support importing to a new table, so setting a table via API is invalid.\n        # User should be set automatically, not submitted via the API.\n        read_only_fields = ['user', 'table_imported_to', 'created_from']\n        write_only_fields = ['paste', 'url']\n\n    def save(self, **kwargs):\n        \"\"\"\n        Set user to current user while saving the data file.\n        \"\"\"\n        current_user = self.fields['user'].get_default()\n        if current_user.is_authenticated:\n            kwargs['user'] = current_user\n        return super().save(**kwargs)\n\n    def validate(self, data):\n        if not self.partial:\n            # Only perform validation on source files when we're not partial\n            source_fields = ['file', 'paste', 'url']\n            present_fields = [field for field in source_fields if field in data]\n            if len(present_fields) > 1:\n                raise ValidationError(\n                    f'Multiple source fields passed: {present_fields}.'\n                    f' Only one of {source_fields} should be specified.'\n                )\n            elif len(present_fields) == 0:\n                raise ValidationError(\n                    f'One of {source_fields} should be specified.'\n                )\n        return data\n\n    def validate_url(self, url):\n        try:\n            response = requests.head(url, allow_redirects=True)\n        except requests.exceptions.ConnectionError:\n            raise ValidationError('URL cannot be reached.')\n\n        content_type = response.headers.get('content-type')\n        if content_type not in SUPPORTED_URL_CONTENT_TYPES:\n            raise ValidationError(f\"URL resource '{content_type}' not a valid type.\")\n        return url\n\n\nclass ConstraintSerializer(serializers.ModelSerializer):\n    name = serializers.CharField(required=False)\n    type = serializers.CharField()\n    columns = serializers.ListField()\n\n    class Meta:\n        model = Constraint\n        fields = ['id', 'name', 'type', 'columns']\n", "path": "mathesar/serializers.py"}, {"content": "from io import TextIOWrapper\n\nimport clevercsv as csv\n\nfrom mathesar.database.base import create_mathesar_engine\nfrom mathesar.models import Table\nfrom db import tables, records\nfrom mathesar.errors import InvalidTableError\n\nALLOWED_DELIMITERS = \",\\t:| \"\nSAMPLE_SIZE = 20000\nCHECK_ROWS = 10\n\n\ndef check_dialect(file, dialect):\n    \"\"\"\n    Checks to see if we can parse the given file with the given dialect\n\n    Parses the first CHECK_ROWS rows. Checks to see if any have formatting issues (as\n    indicated by parse_row), or if any have a differing number of columns.\n\n    Args:\n        file: _io.TextIOWrapper object, an already opened file\n        dialect: csv.Dialect object, the dialect we are validating\n\n    Returns:\n        bool: False if any error that would cause SQL errors were found, otherwise True\n    \"\"\"\n    prev_num_columns = None\n    row_gen = csv.read.reader(file, dialect)\n    for _ in range(CHECK_ROWS):\n        try:\n            row = next(row_gen)\n        except StopIteration:\n            # If less than CHECK_ROWS rows in file, stop early\n            break\n\n        num_columns = len(row)\n        if prev_num_columns is None:\n            prev_num_columns = num_columns\n        elif prev_num_columns != num_columns:\n            return False\n    return True\n\n\ndef get_sv_dialect(file):\n    \"\"\"\n    Given a *sv file, generate a dialect to parse it.\n\n    Args:\n        file: _io.TextIOWrapper object, an already opened file\n\n    Returns:\n        dialect: csv.Dialect object, the dialect to parse the file\n\n    Raises:\n        InvalidTableError: If the generated dialect was unable to parse the file\n    \"\"\"\n    dialect = csv.detect.Detector().detect(file.read(SAMPLE_SIZE),\n                                           delimiters=ALLOWED_DELIMITERS)\n    if dialect is None:\n        raise InvalidTableError\n\n    file.seek(0)\n    if check_dialect(file, dialect):\n        file.seek(0)\n        return dialect\n    else:\n        raise InvalidTableError\n\n\ndef get_sv_reader(file, header, dialect=None):\n    file = TextIOWrapper(file, encoding=\"utf-8-sig\")\n    if dialect:\n        reader = csv.DictReader(file, dialect=dialect)\n    else:\n        reader = csv.DictReader(file)\n    if not header:\n        reader.fieldnames = [\n            f\"column_{i}\" for i in range(len(reader.fieldnames))\n        ]\n        file.seek(0)\n    return reader\n\n\ndef create_db_table_from_data_file(data_file, name, schema):\n    engine = create_mathesar_engine(schema.database.name)\n    sv_filename = data_file.file.path\n    header = data_file.header\n    dialect = csv.dialect.SimpleDialect(data_file.delimiter, data_file.quotechar,\n                                        data_file.escapechar)\n    with open(sv_filename, 'rb') as sv_file:\n        sv_reader = get_sv_reader(sv_file, header, dialect=dialect)\n        column_names = sv_reader.fieldnames\n        table = tables.create_string_column_table(\n            name=name,\n            schema=schema.name,\n            column_names=column_names,\n            engine=engine\n        )\n    records.create_records_from_csv(\n        table,\n        engine,\n        sv_filename,\n        column_names,\n        header,\n        delimiter=dialect.delimiter,\n        escape=dialect.escapechar,\n        quote=dialect.quotechar,\n    )\n    return table\n\n\ndef create_table_from_csv(data_file, name, schema):\n    engine = create_mathesar_engine(schema.database.name)\n    db_table = create_db_table_from_data_file(\n        data_file, name, schema\n    )\n    db_table_oid = tables.get_oid_from_table(db_table.name, db_table.schema, engine)\n    table, _ = Table.objects.get_or_create(oid=db_table_oid, schema=schema)\n    data_file.table_imported_to = table\n    data_file.save()\n    return table\n", "path": "mathesar/imports/csv.py"}], "after_files": [{"content": "import requests\n\nfrom django.urls import reverse\nfrom rest_framework import serializers\nfrom rest_framework.exceptions import ValidationError\n\nfrom mathesar.models import Table, Schema, DataFile, Database, Constraint\n\n\nSUPPORTED_URL_CONTENT_TYPES = {'text/csv', 'text/plain'}\n\n\nclass NestedTableSerializer(serializers.HyperlinkedModelSerializer):\n    url = serializers.SerializerMethodField()\n\n    class Meta:\n        model = Table\n        fields = ['id', 'name', 'url']\n\n    def get_url(self, obj):\n        request = self.context['request']\n        return request.build_absolute_uri(reverse('table-detail', kwargs={'pk': obj.pk}))\n\n\nclass ModelNameField(serializers.CharField):\n    \"\"\"\n    De-serializes the request field as a string, but serializes the response field as\n    `model.name`. Required to support passing and returing a model name from the\n    endpoint, while also storing the model as a related field.\n    \"\"\"\n    def to_representation(self, value):\n        return value.name\n\n\nclass SchemaSerializer(serializers.HyperlinkedModelSerializer):\n    tables = NestedTableSerializer(many=True, read_only=True)\n    name = serializers.CharField()\n    database = ModelNameField(max_length=128)\n\n    class Meta:\n        model = Schema\n        fields = ['id', 'name', 'tables', 'database', 'has_dependencies']\n\n\nclass TypeOptionSerializer(serializers.Serializer):\n    precision = serializers.IntegerField(required=False)\n    scale = serializers.IntegerField(required=False)\n\n\nclass SimpleColumnSerializer(serializers.Serializer):\n    name = serializers.CharField()\n    type = serializers.CharField(source='plain_type')\n    type_options = TypeOptionSerializer(required=False)\n\n\nclass ColumnSerializer(SimpleColumnSerializer):\n    index = serializers.IntegerField(source='column_index', read_only=True)\n    nullable = serializers.BooleanField(default=True)\n    primary_key = serializers.BooleanField(default=False)\n    valid_target_types = serializers.ListField(read_only=True)\n\n\nclass TableSerializer(serializers.ModelSerializer):\n    columns = SimpleColumnSerializer(many=True, read_only=True, source='sa_columns')\n    records_url = serializers.SerializerMethodField()\n    constraints_url = serializers.SerializerMethodField()\n    columns_url = serializers.SerializerMethodField()\n    name = serializers.CharField(required=False, allow_blank=True, default='')\n    data_files = serializers.PrimaryKeyRelatedField(\n        required=False, many=True, queryset=DataFile.objects.all()\n    )\n\n    class Meta:\n        model = Table\n        fields = ['id', 'name', 'schema', 'created_at', 'updated_at', 'import_verified',\n                  'columns', 'records_url', 'constraints_url', 'columns_url', 'data_files', 'has_dependencies']\n\n    def get_records_url(self, obj):\n        if isinstance(obj, Table):\n            # Only get records if we are serializing an existing table\n            request = self.context['request']\n            return request.build_absolute_uri(reverse('table-record-list', kwargs={'table_pk': obj.pk}))\n        else:\n            return None\n\n    def get_constraints_url(self, obj):\n        if isinstance(obj, Table):\n            # Only get constraints if we are serializing an existing table\n            request = self.context['request']\n            return request.build_absolute_uri(reverse('table-constraint-list', kwargs={'table_pk': obj.pk}))\n        else:\n            return None\n\n    def get_columns_url(self, obj):\n        if isinstance(obj, Table):\n            # Only get columns if we are serializing an existing table\n            request = self.context['request']\n            return request.build_absolute_uri(reverse('table-column-list', kwargs={'table_pk': obj.pk}))\n        else:\n            return None\n\n    def validate_data_files(self, data_files):\n        if data_files and len(data_files) > 1:\n            raise ValidationError('Multiple data files are unsupported.')\n        return data_files\n\n\nclass RecordSerializer(serializers.BaseSerializer):\n    def to_representation(self, instance):\n        return instance._asdict()\n\n\nclass TablePreviewSerializer(serializers.Serializer):\n    name = serializers.CharField(required=False)\n    columns = SimpleColumnSerializer(many=True)\n\n\nclass RecordListParameterSerializer(serializers.Serializer):\n    filters = serializers.JSONField(required=False, default=[])\n    order_by = serializers.JSONField(required=False, default=[])\n    group_count_by = serializers.JSONField(required=False, default=[])\n\n\nclass DatabaseSerializer(serializers.ModelSerializer):\n    supported_types = serializers.ListField(child=serializers.CharField())\n\n    class Meta:\n        model = Database\n        fields = ['id', 'name', 'deleted', 'supported_types']\n        read_only_fields = ['id', 'name', 'deleted', 'supported_types']\n\n\nclass DataFileSerializer(serializers.ModelSerializer):\n    user = serializers.PrimaryKeyRelatedField(\n        default=serializers.CurrentUserDefault(), read_only=True\n    )\n    header = serializers.BooleanField(default=True)\n    paste = serializers.CharField(required=False, trim_whitespace=False)\n    url = serializers.URLField(required=False)\n\n    class Meta:\n        model = DataFile\n        fields = [\n            'id', 'file', 'table_imported_to', 'user', 'header', 'delimiter',\n            'escapechar', 'quotechar', 'paste', 'url', 'created_from'\n        ]\n        extra_kwargs = {\n            'file': {'required': False},\n            'delimiter': {'trim_whitespace': False},\n            'escapechar': {'trim_whitespace': False},\n            'quotechar': {'trim_whitespace': False}\n        }\n        # We only currently support importing to a new table, so setting a table via API is invalid.\n        # User should be set automatically, not submitted via the API.\n        read_only_fields = ['user', 'table_imported_to', 'created_from']\n        write_only_fields = ['paste', 'url']\n\n    def save(self, **kwargs):\n        \"\"\"\n        Set user to current user while saving the data file.\n        \"\"\"\n        current_user = self.fields['user'].get_default()\n        if current_user.is_authenticated:\n            kwargs['user'] = current_user\n        return super().save(**kwargs)\n\n    def validate(self, data):\n        if not self.partial:\n            # Only perform validation on source files when we're not partial\n            source_fields = ['file', 'paste', 'url']\n            present_fields = [field for field in source_fields if field in data]\n            if len(present_fields) > 1:\n                raise ValidationError(\n                    f'Multiple source fields passed: {present_fields}.'\n                    f' Only one of {source_fields} should be specified.'\n                )\n            elif len(present_fields) == 0:\n                raise ValidationError(\n                    f'One of {source_fields} should be specified.'\n                )\n        return data\n\n    def validate_url(self, url):\n        try:\n            response = requests.head(url, allow_redirects=True)\n        except requests.exceptions.ConnectionError:\n            raise ValidationError('URL cannot be reached.')\n\n        content_type = response.headers.get('content-type')\n        if content_type not in SUPPORTED_URL_CONTENT_TYPES:\n            raise ValidationError(f\"URL resource '{content_type}' not a valid type.\")\n        return url\n\n\nclass ConstraintSerializer(serializers.ModelSerializer):\n    name = serializers.CharField(required=False)\n    type = serializers.CharField()\n    columns = serializers.ListField()\n\n    class Meta:\n        model = Constraint\n        fields = ['id', 'name', 'type', 'columns']\n", "path": "mathesar/serializers.py"}, {"content": "from io import TextIOWrapper\n\nimport clevercsv as csv\n\nfrom mathesar.database.base import create_mathesar_engine\nfrom mathesar.models import Table\nfrom db import tables, records\nfrom mathesar.errors import InvalidTableError\n\nALLOWED_DELIMITERS = \",\\t:| \"\nSAMPLE_SIZE = 20000\nCHECK_ROWS = 10\n\n\ndef check_dialect(file, dialect):\n    \"\"\"\n    Checks to see if we can parse the given file with the given dialect\n\n    Parses the first CHECK_ROWS rows. Checks to see if any have formatting issues (as\n    indicated by parse_row), or if any have a differing number of columns.\n\n    Args:\n        file: _io.TextIOWrapper object, an already opened file\n        dialect: csv.Dialect object, the dialect we are validating\n\n    Returns:\n        bool: False if any error that would cause SQL errors were found, otherwise True\n    \"\"\"\n    prev_num_columns = None\n    row_gen = csv.read.reader(file, dialect)\n    for _ in range(CHECK_ROWS):\n        try:\n            row = next(row_gen)\n        except StopIteration:\n            # If less than CHECK_ROWS rows in file, stop early\n            break\n\n        num_columns = len(row)\n        if prev_num_columns is None:\n            prev_num_columns = num_columns\n        elif prev_num_columns != num_columns:\n            return False\n    return True\n\n\ndef get_sv_dialect(file):\n    \"\"\"\n    Given a *sv file, generate a dialect to parse it.\n\n    Args:\n        file: _io.TextIOWrapper object, an already opened file\n\n    Returns:\n        dialect: csv.Dialect object, the dialect to parse the file\n\n    Raises:\n        InvalidTableError: If the generated dialect was unable to parse the file\n    \"\"\"\n    dialect = csv.detect.Detector().detect(file.read(SAMPLE_SIZE),\n                                           delimiters=ALLOWED_DELIMITERS)\n    if dialect is None:\n        raise InvalidTableError\n\n    file.seek(0)\n    if check_dialect(file, dialect):\n        file.seek(0)\n        return dialect\n    else:\n        raise InvalidTableError\n\n\ndef get_sv_reader(file, header, dialect=None):\n    file = TextIOWrapper(file, encoding=\"utf-8-sig\")\n    if dialect:\n        reader = csv.DictReader(file, dialect=dialect)\n    else:\n        reader = csv.DictReader(file)\n    if not header:\n        reader.fieldnames = [\n            f\"column_{i}\" for i in range(len(reader.fieldnames))\n        ]\n        file.seek(0)\n    return reader\n\n\ndef create_db_table_from_data_file(data_file, name, schema):\n    engine = create_mathesar_engine(schema.database.name)\n    sv_filename = data_file.file.path\n    header = data_file.header\n    dialect = csv.dialect.SimpleDialect(data_file.delimiter, data_file.quotechar,\n                                        data_file.escapechar)\n    with open(sv_filename, 'rb') as sv_file:\n        sv_reader = get_sv_reader(sv_file, header, dialect=dialect)\n        column_names = sv_reader.fieldnames\n        table = tables.create_string_column_table(\n            name=name,\n            schema=schema.name,\n            column_names=column_names,\n            engine=engine\n        )\n    records.create_records_from_csv(\n        table,\n        engine,\n        sv_filename,\n        column_names,\n        header,\n        delimiter=dialect.delimiter,\n        escape=dialect.escapechar,\n        quote=dialect.quotechar,\n    )\n    return table\n\n\ndef create_table_from_csv(data_file, name, schema):\n    engine = create_mathesar_engine(schema.database.name)\n    db_table = create_db_table_from_data_file(\n        data_file, name, schema\n    )\n    db_table_oid = tables.get_oid_from_table(db_table.name, db_table.schema, engine)\n    table, _ = Table.objects.get_or_create(oid=db_table_oid, schema=schema, import_verified=False)\n    data_file.table_imported_to = table\n    data_file.save()\n    return table\n", "path": "mathesar/imports/csv.py"}]}