Skip to content

Commit

Permalink
Merge pull request #1325 from CartoDB/check-if-exists
Browse files Browse the repository at this point in the history
Check if_exists options
  • Loading branch information
alrocar committed Dec 10, 2019
2 parents 2968666 + 4dd724f commit 4161344
Show file tree
Hide file tree
Showing 5 changed files with 177 additions and 20 deletions.
12 changes: 10 additions & 2 deletions cartoframes/core/managers/context_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
from ...core.logger import log
from ...io.dataset_info import DatasetInfo
from ...auth.defaults import get_default_credentials

from ...utils.geom_utils import encode_geometry_ewkb
from ...utils.utils import is_sql_query, check_credentials, encode_row, map_geom_type, PG_NULL
from ...utils.columns import Column, get_dataframe_columns_info, obtain_converters, \
date_columns_names, normalize_name
Expand Down Expand Up @@ -56,6 +58,9 @@ def copy_from(self, cdf, table_name, if_exists='fail', cartodbfy=True, log_enabl
'Please choose a different `table_name` or use '
'if_exists="replace" to overwrite it'.format(
table_name=table_name, schema=schema))
else:
# 'append'
pass

return self._copy_from(cdf, table_name, columns)

Expand All @@ -72,6 +77,9 @@ def create_table_from_query(self, table_name, query, if_exists, cartodbfy=True,
'Please choose a different `table_name` or use '
'if_exists="replace" to overwrite it'.format(
table_name=table_name, schema=schema))
else:
# 'append'
pass

def has_table(self, table_name, schema=None):
query = self.compute_query(table_name, schema)
Expand Down Expand Up @@ -306,8 +314,8 @@ def _compute_copy_data(df, columns):
for column in columns:
val = df.at[index, column.name]

if column.is_geom and hasattr(val, 'wkt'):
val = 'SRID=4326;{}'.format(val.wkt)
if column.is_geom:
val = encode_geometry_ewkb(val)

row_data.append(encode_row(val))

Expand Down
38 changes: 31 additions & 7 deletions cartoframes/io/carto.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@

GEOM_COLUMN_NAME = 'the_geom'

IF_EXISTS_OPTIONS = ['fail', 'replace', 'append']


def read_carto(source, credentials=None, limit=None, retry_times=3, schema=None, index_col=None, decode_geom=True):
"""
Expand Down Expand Up @@ -75,13 +77,21 @@ def to_carto(dataframe, table_name, credentials=None, if_exists='fail', geom_col
index_label (str, optional): name of the index column in the table. By default it
uses the name of the index from the dataframe.
Raises:
ValueError:
When the dataframe or table name provided is wrong or the if_exists param is not valid.
"""
if not isinstance(dataframe, pd.DataFrame):
raise ValueError('Wrong dataframe. You should provide a valid DataFrame instance.')

if not isinstance(table_name, str):
raise ValueError('Wrong table name. You should provide a valid table name.')

if if_exists not in IF_EXISTS_OPTIONS:
raise ValueError('Wrong option for the `if_exists` param. You should provide: {}.'.format(
', '.join(IF_EXISTS_OPTIONS)))

context_manager = ContextManager(credentials)

cdf = CartoDataFrame(dataframe, copy=True)
Expand Down Expand Up @@ -228,14 +238,21 @@ def copy_table(table_name, new_table_name, credentials=None, if_exists='fail', l
new_table_name(str, optional): name for the new table.
credentials (:py:class:`Credentials <cartoframes.auth.Credentials>`, optional):
instance of Credentials (username, api_key, etc).
if_exists (str, optional): 'fail', 'replace'. Default is 'fail'.
if_exists (str, optional): 'fail', 'replace', 'append'. Default is 'fail'.
Raises:
ValueError:
When the table name provided is wrong or the if_exists param is not valid.
"""
if not isinstance(table_name, str):
raise ValueError('Wrong table name. You should provide a valid string.')
raise ValueError('Wrong table name. You should provide a valid table name.')

if not isinstance(new_table_name, str):
raise ValueError('Wrong new table name. You should provide a valid string.')
pass
raise ValueError('Wrong new table name. You should provide a valid table name.')

if if_exists not in IF_EXISTS_OPTIONS:
raise ValueError('Wrong option for the `if_exists` param. You should provide: {}.'.format(
', '.join(IF_EXISTS_OPTIONS)))

context_manager = ContextManager(credentials)

Expand All @@ -255,14 +272,21 @@ def create_table_from_query(query, new_table_name, credentials=None, if_exists='
new_table_name(str): name for the new table.
credentials (:py:class:`Credentials <cartoframes.auth.Credentials>`, optional):
instance of Credentials (username, api_key, etc).
if_exists (str, optional): 'fail', 'replace'. Default is 'fail'.
if_exists (str, optional): 'fail', 'replace', 'append'. Default is 'fail'.
Raises:
ValueError:
When the query or table name provided is wrong or the if_exists param is not valid.
"""
if not is_sql_query(query):
raise ValueError('Wrong query. You should provide a valid SQL query.')

if not isinstance(new_table_name, str):
raise ValueError('Wrong table name. You should provide a valid table name.')
pass
raise ValueError('Wrong new table name. You should provide a valid table name.')

if if_exists not in IF_EXISTS_OPTIONS:
raise ValueError('Wrong option for the `if_exists` param. You should provide: {}.'.format(
', '.join(IF_EXISTS_OPTIONS)))

context_manager = ContextManager(credentials)

Expand Down
13 changes: 12 additions & 1 deletion cartoframes/utils/geom_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -100,8 +100,8 @@ def _load_wkb_bhex(geom):


def _load_wkt(geom):
return shapely.wkt.loads(geom)
"""Load WKT geometry."""
return shapely.wkt.loads(geom)


def _load_ewkt(egeom):
Expand All @@ -127,6 +127,17 @@ def _extract_srid(egeom):
return (0, egeom)


def encode_geometry_ewkt(geom, srid=4326):
if isinstance(geom, shapely.geometry.base.BaseGeometry):
return 'SRID={0};{1}'.format(srid, geom.wkt)


def encode_geometry_ewkb(geom, srid=4326):
if isinstance(geom, shapely.geometry.base.BaseGeometry):
shapely.geos.lgeos.GEOSSetSRID(geom._geom, srid)
return shapely.wkb.dumps(geom, hex=True, include_srid=True)


def to_geojson(geom):
if geom is not None and str(geom) != 'GEOMETRYCOLLECTION EMPTY':
return json.dumps(shapely.geometry.mapping(geom), sort_keys=True)
4 changes: 2 additions & 2 deletions tests/unit/core/managers/test_context_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,6 @@ def test_internal_copy_from(self, mocker):
COPY table_name(a,b) FROM stdin WITH (FORMAT csv, DELIMITER '|', NULL '__null');
'''.strip()
assert list(mock.call_args[0][1]) == [
b'1|SRID=4326;POINT (0 0)\n',
b'2|SRID=4326;POINT (1 1)\n'
b'1|0101000020E610000000000000000000000000000000000000\n',
b'2|0101000020E6100000000000000000F03F000000000000F03F\n'
]
130 changes: 122 additions & 8 deletions tests/unit/io/test_carto.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@

from cartoframes import CartoDataFrame
from cartoframes.auth import Credentials
from cartoframes.io.carto import read_carto
from cartoframes.core.managers.context_manager import ContextManager
from cartoframes.io.carto import read_carto, to_carto, copy_table, create_table_from_query


CREDENTIALS = Credentials('fake_user', 'fake_api_key')
Expand Down Expand Up @@ -43,21 +43,15 @@ def test_read_carto(mocker):


def test_read_carto_wrong_source(mocker):
# Given
mocker.patch.object(ContextManager, 'copy_to')

# When
with pytest.raises(ValueError) as e:
read_carto(1234, CREDENTIALS)
read_carto(1234)

# Then
assert str(e.value) == 'Wrong source. You should provide a valid table_name or SQL query.'


def test_read_carto_wrong_credentials(mocker):
# Given
mocker.patch.object(ContextManager, 'copy_to')

# When
with pytest.raises(AttributeError) as e:
read_carto('__source__', 1234)
Expand Down Expand Up @@ -181,3 +175,123 @@ def test_read_carto_decode_geom_false(mocker):

# Then
assert expected.equals(cdf)


def test_to_carto_wrong_dataframe(mocker):
# When
with pytest.raises(ValueError) as e:
to_carto(1234, '')

# Then
assert str(e.value) == 'Wrong dataframe. You should provide a valid DataFrame instance.'


def test_to_carto_wrong_table_name(mocker):
# Given
df = GeoDataFrame({'geometry': [Point([0, 0])]})

# When
with pytest.raises(ValueError) as e:
to_carto(df, 1234)

# Then
assert str(e.value) == 'Wrong table name. You should provide a valid table name.'


def test_to_carto_wrong_credentials(mocker):
# Given
df = GeoDataFrame({'geometry': [Point([0, 0])]})

# When
with pytest.raises(AttributeError) as e:
to_carto(df, '__table_name__', 1234)

# Then
assert str(e.value) == 'Credentials attribute is required. Please pass a `Credentials` ' + \
'instance or use the `set_default_credentials` function.'


def test_to_carto_wrong_if_exists(mocker):
# Given
df = GeoDataFrame({'geometry': [Point([0, 0])]})

# When
with pytest.raises(ValueError) as e:
to_carto(df, '__table_name__', if_exists='keep_calm')

# Then
assert str(e.value) == 'Wrong option for the `if_exists` param. You should provide: fail, replace, append.'


def test_copy_table_wrong_table_name(mocker):
# When
with pytest.raises(ValueError) as e:
copy_table(1234, '__new_table_name__')

# Then
assert str(e.value) == 'Wrong table name. You should provide a valid table name.'


def test_copy_table_wrong_new_table_name(mocker):
# When
with pytest.raises(ValueError) as e:
copy_table('__table_name__', 1234)

# Then
assert str(e.value) == 'Wrong new table name. You should provide a valid table name.'


def test_copy_table_wrong_credentials(mocker):
# When
with pytest.raises(AttributeError) as e:
copy_table('__table_name__', '__new_table_name__', 1234)

# Then
assert str(e.value) == 'Credentials attribute is required. Please pass a `Credentials` ' + \
'instance or use the `set_default_credentials` function.'


def test_copy_table_wrong_if_exists(mocker):
# When
with pytest.raises(ValueError) as e:
copy_table('__table_name__', '__new_table_name__', if_exists='keep_calm')

# Then
assert str(e.value) == 'Wrong option for the `if_exists` param. You should provide: fail, replace, append.'


def test_create_table_from_query_wrong_query(mocker):
# When
with pytest.raises(ValueError) as e:
create_table_from_query('WRONG SQL QUERY', '__new_table_name__')

# Then
assert str(e.value) == 'Wrong query. You should provide a valid SQL query.'


def test_create_table_from_query_wrong_new_table_name(mocker):
# When
with pytest.raises(ValueError) as e:
create_table_from_query('SELECT * FROM table', 1234)

# Then
assert str(e.value) == 'Wrong new table name. You should provide a valid table name.'


def test_create_table_from_query_wrong_credentials(mocker):
# When
with pytest.raises(AttributeError) as e:
create_table_from_query('SELECT * FROM table', '__new_table_name__', 1234)

# Then
assert str(e.value) == 'Credentials attribute is required. Please pass a `Credentials` ' + \
'instance or use the `set_default_credentials` function.'


def test_create_table_from_query_wrong_if_exists(mocker):
# When
with pytest.raises(ValueError) as e:
create_table_from_query('SELECT * FROM table', '__new_table_name__', if_exists='keep_calm')

# Then
assert str(e.value) == 'Wrong option for the `if_exists` param. You should provide: fail, replace, append.'

0 comments on commit 4161344

Please sign in to comment.