-
-
Save jmwenda/7655bbf81e029367dc6449f157a4be38 to your computer and use it in GitHub Desktop.
Revisions
-
andrewxhill revised this gist
Jul 3, 2014 . 1 changed file with 5 additions and 1 deletion.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -5,7 +5,11 @@ import json import sys import argparse try: import requests except ImportError: print 'The requests package is required: http://docs.python-requests.org/en/latest/user/install/#install' sys.exit() class CartoDB: def __init__(self, options): -
andrewxhill revised this gist
Jun 20, 2014 . 1 changed file with 1 addition and 1 deletion.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -176,7 +176,7 @@ def clean_table(self): 'export' :{ "description": "Export an existing table to a local file (default GeoJSON)", "requirements": ["k","u","t","l"], "example": "python cartodb-utils.py export -t some_existing_table -m CSV -l local_file.csv -k myapikey -u myusername" }, 'clean' : { "description": "Vacuum and analyze a table for speed", -
andrewxhill revised this gist
Jun 20, 2014 . 1 changed file with 0 additions and 1 deletion.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -211,7 +211,6 @@ def failure(message): sys.exit() cartodb = CartoDB(options) if args.method.lower() == 'import': new_table = cartodb.upload() success(new_table) -
andrewxhill revised this gist
Jun 20, 2014 . 1 changed file with 2 additions and 2 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -194,7 +194,7 @@ def clean_table(self): parser.add_argument('-u', '--user', dest='u', help='CartoDB username') parser.add_argument('-k', '--key', dest='k', help='CartoDB account API Key') parser.add_argument('-t', '--target', dest='t', help='Target table') parser.add_argument('-v', '--verbose', dest='verbose', default=False, action="store_true", help='Verbose output if included') args = parser.parse_args() options = vars(args) @@ -211,7 +211,7 @@ def failure(message): sys.exit() cartodb = CartoDB(options) print args if args.method.lower() == 'import': new_table = cartodb.upload() success(new_table) -
andrewxhill revised this gist
Jun 20, 2014 . 1 changed file with 1 addition and 1 deletion.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -86,7 +86,7 @@ def overwrite(self, append=False): else: insert_cols[c] = self.type_map[target_columns[c]['type']] for c in alter_cols: self.add_column(self.options['t'], c, insert_cols[c]) select_list = [] for c,t in insert_cols.items(): select_list.append( "%s::%s" % (c,t)) -
andrewxhill revised this gist
Jun 20, 2014 . 1 changed file with 20 additions and 24 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -6,7 +6,7 @@ import sys import argparse import requests class CartoDB: def __init__(self, options): # do stuff @@ -58,25 +58,22 @@ def upload(self): self._error(d['get_error_text']['what_about']) self.new_tables.append(d['table_name']) return d['table_name'] def columns(self, table): sql = "SELECT * FROM %s LIMIT 0" % table data = self.sql_api(sql) return data['fields'] def add_column(self, table, name, coltype): sql = "ALTER TABLE %s ADD COLUMN %s %s" % (table, name, coltype) data = self.sql_api(sql) return True def overwrite(self, append=False): # upload new data new_table = self.upload() source_columns = self.columns(new_table) target_columns = self.columns(self.options['t']) insert_cols = {} alter_cols = [] for c in source_columns.keys(): @@ -88,34 +85,29 @@ def overwrite(self, append=False): alter_cols.append(c) else: insert_cols[c] = self.type_map[target_columns[c]['type']] for c in alter_cols: self.add_column(self.options['t'], c, insert_cos[c]) select_list = [] for c,t in insert_cols.items(): select_list.append( "%s::%s" % (c,t)) sql = "INSERT INTO %s (the_geom, %s) " % (self.options['t'], ','.join(insert_cols.keys())) sql += "SELECT the_geom, %s FROM %s; " % (','.join(select_list), new_table) sql += "DROP TABLE %s" % new_table self._log("Writing data to %s and droppping %s" % (self.options['t'],new_table)) if append==False: sql = "DELETE FROM %s; %s " % (self.options['t'], sql) data = self.sql_api(sql) if 'error' in data.keys(): self._log('Overwrite failed, cleaning-up') sql = "DROP TABLE %s" % new_table self.sql_api(sql) return False else: return True def drop_table(self): # drop a table ' self._log("Dropping table %s" % self.options['t']) sql = "DROP TABLE %s" % self.options['t'] data = self.sql_api(sql) if 'error' in data.keys(): @@ -124,13 +116,15 @@ def drop_table(self): def clear_rows(self): # clear all rows from a table self._log("Deleting all rows") sql = "DELETE FROM %s" % self.options['t'] data = self.sql_api(sql) if 'error' in data.keys(): self._error(data['error']) return True def export_table(self): self._log("Exporting new %s" % self.options['m']) params = {"format": self.options['m'], "api_key": self.options["k"],"q": "SELECT * FROM %s" % self.options["t"]} r = requests.get(self.api_url, params=params, stream=True) with open(self.options['l'], 'wb') as fd: @@ -139,18 +133,20 @@ def export_table(self): return True def clean_table(self): # clean up table for speed self._log("Cleaning up unused space") sql = "VACUUM FULL %s" % self.options['t'] data = self.sql_api(sql) if 'error' in data.keys(): self._error(data['error']) self._log("Optimizing existing indexes") sql = "ANALYZE %s" % self.options['t'] data = self.sql_api(sql) if 'error' in data.keys(): self._error(data['error']) return True if __name__ == "__main__": SUPPORTED_METHODS = { 'import' : { "description": "Import a file to create a new table", @@ -189,20 +185,20 @@ def clean_table(self): } } parser = argparse.ArgumentParser(description="CartoDB Python Utility") parser.add_argument('method', nargs="?", help='e.g. %s' % ','.join(SUPPORTED_METHODS.keys())) parser.add_argument('-f', '--file', dest='f', help='Source file') parser.add_argument('-l', '--local', dest='l', help='Local file') parser.add_argument('-m', '--format', default="GeoJSON", dest='m', help='Export file format') parser.add_argument('-u', '--user', dest='u', help='CartoDB username') parser.add_argument('-k', '--key', dest='k', help='CartoDB account API Key') parser.add_argument('-t', '--target', dest='t', help='Target table') parser.add_argument('-v', '--verbose', dest='verbose', type=bool, default=True, help='Verbose output') args = parser.parse_args() options = vars(args) def success(message): print 'SUCCESS', message def failure(message): @@ -213,9 +209,9 @@ def failure(message): if options[d] is None: print "Arguement -%s is required\n\n%s\n\ndescription:\t%s\nrequired args:\t%s\nexample:\t%s" % (d,m,SUPPORTED_METHODS[m]['description'],SUPPORTED_METHODS[m]['requirements'],SUPPORTED_METHODS[m]['example']) sys.exit() cartodb = CartoDB(options) if args.method.lower() == 'import': new_table = cartodb.upload() success(new_table) @@ -242,4 +238,4 @@ def failure(message): if args.method.lower() == 'export': status = cartodb.export_table() if status == True: success('Exported table to %s' % options['l']) -
andrewxhill revised this gist
Jun 20, 2014 . 1 changed file with 12 additions and 8 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -137,14 +137,18 @@ def export_table(self): for chunk in r.iter_content(10): fd.write(chunk) return True def clean_table(self): # clean up table for speed sql = "VACUUM FULL %s" % self.options['t'] data = self.sql_api(sql) if 'error' in data.keys(): self._error(data['error']) sql = "ANALYZE %s" % self.options['t'] data = self.sql_api(sql) if 'error' in data.keys(): self._error(data['error']) return True if __name__ == "__main__": SUPPORTED_METHODS = { -
andrewxhill revised this gist
Jun 20, 2014 . 1 changed file with 15 additions and 15 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -121,14 +121,14 @@ def drop_table(self): if 'error' in data.keys(): self._error(data['error']) return True def clear_rows(self): # clear all rows from a table sql = "DELETE FROM %s" % self.options['t'] data = self.sql_api(sql) if 'error' in data.keys(): self._error(data['error']) return True def export_table(self): params = {"format": self.options['m'], "api_key": self.options["k"],"q": "SELECT * FROM %s" % self.options["t"]} @@ -138,13 +138,13 @@ def export_table(self): fd.write(chunk) return True if __name__ == "__main__": SUPPORTED_METHODS = { -
andrewxhill revised this gist
Jun 20, 2014 . 1 changed file with 7 additions and 7 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -122,13 +122,13 @@ def drop_table(self): self._error(data['error']) return True def export_table(self): params = {"format": self.options['m'], "api_key": self.options["k"],"q": "SELECT * FROM %s" % self.options["t"]} -
andrewxhill revised this gist
Jun 19, 2014 . 1 changed file with 0 additions and 8 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -7,14 +7,6 @@ import argparse import requests class CartoDB: def __init__(self, options): # do stuff -
andrewxhill created this gist
Jun 19, 2014 .There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,249 @@ import os import urllib import urllib2 import base64 import json import sys import argparse import requests class EnhancedFile(file): def __init__(self, *args, **keyws): file.__init__(self, *args, **keyws) def __len__(self): return int(os.fstat(self.fileno())[6]) class CartoDB: def __init__(self, options): # do stuff self.options = options self.api_url = "https://%s.cartodb.com/api/v2/sql" % (self.options['u']) self.import_url = "https://%s.cartodb.com/api/v1/imports/?api_key=%s" % (self.options['u'], self.options['k']) self.new_tables = [] self.internal_columns = ['created_at', 'updated_at', 'the_geom', 'the_geom_webmercator', 'cartodb_id'] self.type_map = {'string':'text', 'boolean': 'boolean', 'date': 'timestamp', 'number':'numeric'} def _log(self, message): if self.options['verbose'] == True: print message def _error(self, error): print error sys.exit() def sql_api(self, sql): # execute sql request over API params = { 'api_key' : self.options["k"], 'q' : sql } r = requests.get(self.api_url, params=params) return r.json() def upload(self): # import a file # see https://gist.github.com/lbosque/5876697 # returns new table name r = requests.post(self.import_url, files={'file': open(self.options['f'], 'rb')}) data = r.json() if data['success']!=True: self._error("Upload failed") complete = False last_state = '' while not complete: import_status_url = "https://%s.cartodb.com/api/v1/imports/%s?api_key=%s" % (self.options['u'], data['item_queue_id'], self.options['k']) req = urllib2.Request(import_status_url) response = urllib2.urlopen(req) d = json.loads(str(response.read())) if last_state!=d['state']: last_state=d['state'] if d['state']=='uploading': self._log('Uploading file...') elif d['state']=='importing': self._log('Importing data...') elif d['state']=='complete': complete = True self._log('Table "%s" created' % d['table_name']) if d['state']=='failure': self._error(d['get_error_text']['what_about']) self.new_tables.append(d['table_name']) return d['table_name'] def columns(self, table): sql = "SELECT * FROM %s LIMIT 0" % table data = self.sql_api(sql) return data['fields'] def add_column(self, table, name, coltype): sql = "ALTER TABLE %s ADD COLUMN %s %s" % (table, name, coltype) data = self.sql_api(sql) return True def overwrite(self, append=False): # upload new data new_table = self.upload() source_columns = self.columns(new_table) target_columns = self.columns(self.options['t']) insert_cols = {} alter_cols = [] for c in source_columns.keys(): if c in self.internal_columns: source_columns.pop(c, None) else: if c not in target_columns.keys(): insert_cols[c] = self.type_map[source_columns[c]['type']] alter_cols.append(c) else: insert_cols[c] = self.type_map[target_columns[c]['type']] for c in alter_cols: self.add_column(self.options['t'], c, insert_cos[c]) select_list = [] for c,t in insert_cols.items(): select_list.append( "%s::%s" % (c,t)) sql = "INSERT INTO %s (the_geom, %s) " % (self.options['t'], ','.join(insert_cols.keys())) sql += "SELECT the_geom, %s FROM %s; " % (','.join(select_list), new_table) sql += "DROP TABLE %s" % new_table if append==False: sql = "DELETE FROM %s; %s " % (self.options['t'], sql) data = self.sql_api(sql) if 'error' in data.keys(): self._log('Overwrite failed, cleaning-up') sql = "DROP TABLE %s" % new_table self.sql_api(sql) return False else: return True def drop_table(self): # drop a table ' sql = "DROP TABLE %s" % self.options['t'] data = self.sql_api(sql) if 'error' in data.keys(): self._error(data['error']) return True def clear_rows(self): # drop a table ' sql = "DELETE FROM %s" % self.options['t'] data = self.sql_api(sql) if 'error' in data.keys(): self._error(data['error']) return True def export_table(self): params = {"format": self.options['m'], "api_key": self.options["k"],"q": "SELECT * FROM %s" % self.options["t"]} r = requests.get(self.api_url, params=params, stream=True) with open(self.options['l'], 'wb') as fd: for chunk in r.iter_content(10): fd.write(chunk) return True def clear_rows(self): # drop a table ' sql = "DELETE FROM %s" % self.options['t'] data = self.sql_api(sql) if 'error' in data.keys(): self._error(data['error']) return True if __name__ == "__main__": SUPPORTED_METHODS = { 'import' : { "description": "Import a file to create a new table", "requirements": ["f","k","u"], "example": "python cartodb-utils.py import -f myfile.csv -k myapikey -u myusername" }, 'overwrite' : { "description": "Overwrite an existing table with data from a file", "requirements": ["f","k","u","t"], "example": "python cartodb-utils.py overwrite -f myfile.csv -t some_existing_table -k myapikey -u myusername" }, 'append' : { "description": "Append rows to an existing table from a file", "requirements": ["f","k","u","t"], "example": "python cartodb-utils.py append -f myfile.csv -t some_existing_table -k myapikey -u myusername" }, 'clear' : { "description": "Clear all rows from an existing table", "requirements": ["k","u","t"], "example": "python cartodb-utils.py clear -t some_existing_table -k myapikey -u myusername" }, 'drop' : { "description": "Completely drop an existing table", "requirements": ["k","u","t"], "example": "python cartodb-utils.py drop -t some_existing_table -k myapikey -u myusername" }, 'export' :{ "description": "Export an existing table to a local file (default GeoJSON)", "requirements": ["k","u","t","l"], "example": "python cartodb-utils.py clean -t some_existing_table -m CSV -l local_file.csv -k myapikey -u myusername" }, 'clean' : { "description": "Vacuum and analyze a table for speed", "requirements": ["k","u","t"], "example": "python cartodb-utils.py clean -t some_existing_table -k myapikey -u myusername" } } parser = argparse.ArgumentParser(description="CartoDB Python Utility") parser.add_argument('method', nargs="?", help='e.g. %s' % ','.join(SUPPORTED_METHODS.keys())) parser.add_argument('-f', '--file', dest='f', help='Source file') parser.add_argument('-l', '--local', dest='l', help='Local file') parser.add_argument('-m', '--format', default="GeoJSON", dest='m', help='Export file format') parser.add_argument('-u', '--user', dest='u', help='CartoDB username') parser.add_argument('-k', '--key', dest='k', help='CartoDB account API Key') parser.add_argument('-t', '--target', dest='t', help='Target table') parser.add_argument('-v', '--verbose', dest='verbose', type=bool, default=True, help='Verbose output') args = parser.parse_args() options = vars(args) def success(message): print 'SUCCESS', message def failure(message): print 'FAILURE', message m = args.method.lower() if m in SUPPORTED_METHODS.keys(): for d in SUPPORTED_METHODS[m]["requirements"]: if options[d] is None: print "Arguement -%s is required\n\n%s\n\ndescription:\t%s\nrequired args:\t%s\nexample:\t%s" % (d,m,SUPPORTED_METHODS[m]['description'],SUPPORTED_METHODS[m]['requirements'],SUPPORTED_METHODS[m]['example']) sys.exit() cartodb = CartoDB(options) if args.method.lower() == 'import': new_table = cartodb.upload() success(new_table) if args.method.lower() == 'overwrite': status = cartodb.overwrite() if status == True: success('Table data replaced') if args.method.lower() == 'append': status = cartodb.overwrite(True) if status == True: success('Data appended to table') if args.method.lower() == 'clean': status = cartodb.clean_table() if status == True: success('Cleaned table') if args.method.lower() == 'drop': status = cartodb.drop_table() if status == True: success('Dropped table') if args.method.lower() == 'clear': status = cartodb.clear_rows() if status == True: success('Cleared all rows from table') if args.method.lower() == 'export': status = cartodb.export_table() if status == True: success('Exported table to %s' % options['l'])