diff --git a/fourtytwo/bqtools/__init__.py b/fourtytwo/bqtools/__init__.py
index 9542242..136e18c 100644
--- a/fourtytwo/bqtools/__init__.py
+++ b/fourtytwo/bqtools/__init__.py
@@ -104,14 +104,21 @@ class BQTable(object):
     def __init__(self, schema=None, data=None):
         if DEBUG:
             logging.debug('bqtools.BQTable.__init__')
-
+        
         self.schema = schema if schema else []
         self.data = data if data else []
     
-    #def __repr__(self):
-    #    pass
+    def __repr__(self):
+        schema_shape = len(self.schema)
+        if len(self.data) > 0:
+            data_shape = (len(self.data[0]), len(self.data))
+        else:
+            data_shape = (0,)
+        return '<bqtools.BQTable(shape_schema={}, shape_data={})>'.format(schema_shape, data_shape)
 
     def __eq__(self, other):
+        if not isinstance(other, BQTable):
+            raise TypeError('other must be of type BQTable')
         return self.schema == other.schema and self.data == other.data
     
     def __setattr__(self, name, value):
@@ -146,13 +153,18 @@ class BQTable(object):
                 new_schema.append(bigquery.SchemaField(**field))
         
         if self.schema and new_schema and new_schema != self.schema:
-            data = self._move_columns(new_schema)
+            # TODO Handle appends to schema
+            # if len(new_schema) > len(self.schema)
+            data = self._move_columns(schema=new_schema)
         else:
             data = self.data
-
-        data = self._typecheck(schema=new_schema, data=data)
-        object.__setattr__(self, '_schema', new_schema)
-        object.__setattr__(self, '_data', data)
+        
+        if data:
+            data = self._typecheck(schema=new_schema, data=data)
+            object.__setattr__(self, '_schema', new_schema)
+            object.__setattr__(self, '_data', data)
+        else:
+            object.__setattr__(self, '_schema', new_schema)
 
     def _set_data(self, data):
         if DEBUG:
@@ -160,14 +172,14 @@ class BQTable(object):
         
         if data and isinstance(data, list):
             if isinstance(data[0], dict):
-                data = _rows_to_columns(data, self.schema)
-        data = self._typecheck(data=data)
+                data = _rows_to_columns(rows=data, schema=self.schema)
+            data = self._typecheck(data=data)
         object.__setattr__(self, '_data', data)
     
     def _move_columns(self, schema):
         if DEBUG:
             logging.debug('bqtools.BQTable._move_columns()')
-
+        
         old_field_names = [field.name for field in self.schema]
         new_field_names = [field.name for field in schema]
         column_order = [old_field_names.index(name) for name in new_field_names]
@@ -219,8 +231,8 @@ class BQTable(object):
         self._rename_columns(mapping=columns)
     
     def append(self, rows):
-        append_columns = _rows_to_columns(rows, self.schema)
-        data = self.data
+        append_columns = _rows_to_columns(rows=rows, schema=self.schema)
+        data = self.data if self.data else [[] for n in range(len(self.schema))]
         for index in range(len(data)):
             data[index] += append_columns[index]
         self.data = data

append data to empty table.data fails - required for schema_only
```python
>>> from fourtytwo import bqtools
>>> table = bqtools.read_bq(table_ref='project.dataset.table', schema_only=True)
>>> table.append([])
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/bqtools/fourtytwo/bqtools/__init__.py", line 224, in append
    for index in range(len(data)):
TypeError: object of type 'NoneType' has no len()
```

File "/bqtools/fourtytwo/bqtools/\_\_init\_\_.py", line 224, in append:
```python
    def append(self, rows):
        append_columns = _rows_to_columns(rows, self.schema)
        data = self.data
        for index in range(len(data)):
            data[index] += append_columns[index]
```

Probably replace range(len(data)) with range(len(self.schema))
diff --git a/tests/test_bqtools.py b/tests/test_bqtools.py
index 0202f79..f990c0c 100644
--- a/tests/test_bqtools.py
+++ b/tests/test_bqtools.py
@@ -1,6 +1,6 @@
 from fourtytwo import bqtools
 
-def test_bqorm_construct_columns():
+def test_bqtools_construct_columns():
     schema = [
         {'name': 'number', 'field_type': 'INTEGER'},
         {'name': 'text', 'field_type': 'STRING'},
@@ -12,7 +12,7 @@ def test_bqorm_construct_columns():
     assert len(table.data) == 2
     assert len(table.rows()) == 4
 
-def test_bqorm_construct_rows_dicts():
+def test_bqtools_construct_rows_dicts():
     schema = [
         {'name': 'number', 'field_type': 'INTEGER'},
         {'name': 'text', 'field_type': 'STRING'},
@@ -28,3 +28,46 @@ def test_bqorm_construct_rows_dicts():
     assert len(table.schema) == 2
     assert len(table.data) == 2
     assert len(table.rows()) == 4
+
+def test_bqtools_append_list():
+    schema = [
+        {'name': 'number', 'field_type': 'INTEGER'},
+        {'name': 'text', 'field_type': 'STRING'},
+    ]
+    table = bqtools.BQTable(schema=schema)
+    table.append([[1, 'a'], [2, 'b']])
+    assert len(table.data) == 2
+    assert len(table.rows()) == 2
+
+def test_bqtools_append_dict():
+    schema = [
+        {'name': 'number', 'field_type': 'INTEGER'},
+        {'name': 'text', 'field_type': 'STRING'},
+    ]
+    table = bqtools.BQTable(schema=schema)
+    table.append([
+        {'number': 1, 'text': 'a'},
+        {'number': 2, 'text': 'b'}
+    ])
+    assert len(table.data) == 2
+    assert len(table.rows()) == 2
+
+def test_bqtools_append_schema():
+    schema = [
+        {'name': 'number', 'field_type': 'INTEGER'},
+        {'name': 'text', 'field_type': 'STRING'},
+    ]
+    rows = [
+        {'number': 1, 'text': 'a'},
+        {'number': 2, 'text': 'b'},
+        {'number': 3, 'text': 'c'},
+        {'number': 4, 'text': 'd'},
+    ]
+    table = bqtools.BQTable(schema=schema, data=rows)
+    
+    table.schema += [{'name': 'test', 'field_type': 'STRING'}]
+    table.schema = table.schema + [{'name': 'test', 'field_type': 'STRING'}]
+    assert len(table.schema) == 3
+    assert len(table.data) == 3
+    assert len(table.rows()) == 4
+    

pip install -e .[test]
parse_log_pytest
requirements.txt
pytest
3.9
requirements.txt
pytest --no-header -rA --tb=line --color=no -p no:cacheprovider -W ignore::DeprecationWarning
-e git+https://github.com/42DIGITAL/bqtools.git@98ce0de1d976f33cf04217ef50f864f74bd5ed52#egg=bqtools
cachetools==5.5.2
certifi==2025.1.31
charset-normalizer==3.4.1
exceptiongroup==1.2.2
google-api-core==2.24.2
google-auth==2.38.0
google-cloud-bigquery==3.31.0
google-cloud-core==2.4.3
google-crc32c==1.7.1
google-resumable-media==2.7.2
googleapis-common-protos==1.69.2
grpcio==1.71.0
grpcio-status==1.71.0
idna==3.10
iniconfig==2.1.0
numpy==2.0.2
packaging==24.2
pandas==2.2.3
pluggy==1.5.0
proto-plus==1.26.1
protobuf==5.29.4
pyasn1==0.6.1
pyasn1_modules==0.4.2
pytest==8.3.5
python-dateutil==2.9.0.post0
pytz==2025.2
requests==2.32.3
rsa==4.9
six==1.17.0
tomli==2.2.1
tzdata==2025.2
urllib3==2.3.0

name: bqtools
channels:
  - defaults
  - https://repo.anaconda.com/pkgs/main
  - https://repo.anaconda.com/pkgs/r
  - conda-forge
dependencies:
  - _libgcc_mutex=0.1=main
  - _openmp_mutex=5.1=1_gnu
  - ca-certificates=2025.2.25=h06a4308_0
  - ld_impl_linux-64=2.40=h12ee557_0
  - libffi=3.4.4=h6a678d5_1
  - libgcc-ng=11.2.0=h1234567_1
  - libgomp=11.2.0=h1234567_1
  - libstdcxx-ng=11.2.0=h1234567_1
  - ncurses=6.4=h6a678d5_0
  - openssl=3.0.16=h5eee18b_0
  - pip=25.0=py39h06a4308_0
  - python=3.9.21=he870216_1
  - readline=8.2=h5eee18b_0
  - setuptools=75.8.0=py39h06a4308_0
  - sqlite=3.45.3=h5eee18b_0
  - tk=8.6.14=h39e8969_0
  - wheel=0.45.1=py39h06a4308_0
  - xz=5.6.4=h5eee18b_1
  - zlib=1.2.13=h5eee18b_1
  - pip:
      - cachetools==5.5.2
      - certifi==2025.1.31
      - charset-normalizer==3.4.1
      - exceptiongroup==1.2.2
      - google-api-core==2.24.2
      - google-auth==2.38.0
      - google-cloud-bigquery==3.31.0
      - google-cloud-core==2.4.3
      - google-crc32c==1.7.1
      - google-resumable-media==2.7.2
      - googleapis-common-protos==1.69.2
      - grpcio==1.71.0
      - grpcio-status==1.71.0
      - idna==3.10
      - iniconfig==2.1.0
      - numpy==2.0.2
      - packaging==24.2
      - pandas==2.2.3
      - pluggy==1.5.0
      - proto-plus==1.26.1
      - protobuf==5.29.4
      - pyasn1==0.6.1
      - pyasn1-modules==0.4.2
      - pytest==8.3.5
      - python-dateutil==2.9.0.post0
      - pytz==2025.2
      - requests==2.32.3
      - rsa==4.9
      - six==1.17.0
      - tomli==2.2.1
      - tzdata==2025.2
      - urllib3==2.3.0
prefix: /opt/conda/envs/bqtools

tests/test_bqtools.py::test_bqtools_append_list tests/test_bqtools.py::test_bqtools_append_dict
tests/test_bqtools.py::test_bqtools_append_schema
tests/test_bqtools.py::test_bqtools_construct_columns tests/test_bqtools.py::test_bqtools_construct_rows_dicts
fourtytwo/bqtools/__init__.py
fourtytwo/bqtools/__init__.py