Currently I'm exploring the google API and I have script that currently works as importer of my CSV file to google sheet, but I have issue since my script is creating new sheet once I import csv, my plan is to modify it and make it not create new sheet but to import and update the spreadsheet.
import gspread
from datetime import date
from oauth2client.service_account import ServiceAccountCredentials
scope = [
"https://spreadsheets.google.com/feeds",
"https://www.googleapis.com/auth/spreadsheets",
"https://www.googleapis.com/auth/drive.file",
"https://www.googleapis.com/auth/drive",
]
credentials = ServiceAccountCredentials.from_json_keyfile_name("pdkey123.json", scope)
client = gspread.authorize(credentials)
today = date.today()
now_date = today.strftime("%m/%d/%y")
spreadsheet = client.open("CSVImport")
worksheet = spreadsheet.add_worksheet(title=now_date, rows="1000", cols="5")
now_sheet = now_date + '!' + 'A1'
def ImportCsv(csvFile, sheet, cell):
if "!" in cell:
(tabName, cell) = cell.split("!")
wks = sheet.worksheet(tabName)
else:
wks = sheet.sheet1
(firstRow, firstColumn) = gspread.utils.a1_to_rowcol(cell)
with open(csvFile, "r") as f:
csvContents = f.read()
body = {
"requests": [
{
"pasteData": {
"coordinate": {
"sheetId": wks.id,
"rowIndex": firstRow - 1,
"columnIndex": firstColumn - 1,
},
"data": csvContents,
"type": "PASTE_NORMAL",
"delimiter": ",",
}
}
]
}
return sheet.batch_update(body)
ImportCsv("test_file.csv", spreadsheet, now_sheet)
Can someone help me to modify my script? TYIA
Related
I have the following script in Google Apps:
function createSpreadsheet(environment, timestamp) {
Logger.log(environment);
var folders = DriveApp.getFoldersByName(environment);
while (folders.hasNext()) {
var folder = folders.next();
}
var testName = timestamp + ".test_" + environment;
Logger.log(testName);
var file = {
"title": testName,
"mimeType": "application/vnd.google-apps.spreadsheet",
"parents": [
{
"id": folder.getId()
}
]
};
Drive.Files.insert(file);
var allFiles = folder.getFilesByName(testName);
var files = {};
while (allFiles.hasNext()) {
var file = allFiles.next();
return file.getId();
}
}
and from Ruby code I am performing the following call
request = Google::Apis::ScriptV1::ExecutionRequest.new
request.function = 'createSpreadsheet'
request.parameters = [environment.to_s ,timestamp.to_s ]
But it is not working and I get error during the execution of the script:
Script error message: Cannot call method "getId" of undefined.
What I am doing wrong ? that parameters are a simple strings
Thanks a lot
It was my fault I forgot publishing my last change in the script
I am trying to generate Slick 3.0 code for Oracle. The DB user points to two schemas that have tables with the same name so the generated code has duplicate classes. I would like to filter out the tables from the schema that end in "STAGE"
Here is the code:
object CodeGen2 extends App {
//https://stackoverflow.com/questions/28285129/slick-code-generation-for-only-a-single-schema
val slickDriver = "com.typesafe.slick.driver.oracle.OracleDriver"
val jdbcDriver = "oracle.jdbc.OracleDriver"
val url = "jdbc:oracle:thin:#dbhost:1521:dbsid"
val user = "dbuser"
val password = "dbpassword"
val destDir = "src/main/scala"
val destPackage = "com.mycompany.mypackage"
import scala.concurrent.{ExecutionContext, Await, Future}
import scala.concurrent.duration.Duration
import slick.codegen.SourceCodeGenerator
import scala.concurrent.ExecutionContext.Implicits.global
import slick.jdbc.JdbcModelBuilder
import slick.jdbc.meta.MTable
import com.typesafe.slick.driver.oracle.OracleDriver
import slick.jdbc.JdbcBackend.DatabaseFactoryDef
println("Starting codegen...")
val db = OracleDriver.simple.Database.forURL(url, user=user, password=password, driver=jdbcDriver)
val filteredTables = OracleDriver.defaultTables.filter(
(t: MTable) => !t.name.schema.get.endsWith("STAGE")
)
val modelAction = OracleDriver.createModel(filteredTables, true)
println("Generating model...")
val model = Await.result(db.run(modelAction), Duration.Inf)
val codegen = new SourceCodeGenerator(model) {
// for illustration
val noStage = model.tables.filter { table => !table.name.schema.get.endsWith("STAGE") }
noStage.foreach { table => println(table.name.schema.get) }
}
println("Generating files...")
codegen.writeToFile(
slickDriver, destDir, destPackage, "Tables", "Tables.scala"
)
// slick.codegen.SourceCodeGenerator.main(
// Array(slickDriver, jdbcDriver, url, destDir, destPackage, user, password)
// )
println("Finished codegen.")
}
I try and filter the defaultTables but the signature is Seq[MTable] => Boolean so I have no idea how to deal with that. Is filtering the tables passed to driver.createModel the correct approach? I looked and tried other code with override(n) methods but nothing seemed workable.
name := "slick-test"
version := "1.0"
scalaVersion := "2.11.6"
libraryDependencies ++= Seq(
"com.typesafe.slick" %% "slick" % "3.0.0",
"org.slf4j" % "slf4j-nop" % "1.6.4",
"com.typesafe.slick" %% "slick-extensions" % "3.0.0",
"com.typesafe.slick" %% "slick-codegen" % "3.0.0"
)
resolvers += "Typesafe Releases" at "http://repo.typesafe.com/typesafe/maven-releases/"
Thanks.
Try it this way :
val filteredTables = OracleDriver.defaultTables.map(seq => seq.filter(t => !t.name.schema.get.endsWith("STAGE")))
val modelAction = OracleDriver.createModel(Option(filteredTables), true)
Update: After I posted above, a workaround was found to the code generation problem for Oracle. It should be fixed in Slick 3.2. Replace the code above with this SourceCodeGenerator. See https://github.com/slick/slick/issues/1000
val codegen = new SourceCodeGenerator(model) {
// slated for fix in 3.2
override def Table = new Table(_) { table =>
// override generator responsible for columns
override def Column = new Column(_) {
override def defaultCode = v => {
def raw(v: Any) = rawType match {
case "String" => "\"" + v + "\""
case "Long" => v + "L"
case "Float" => v + "F"
case "Char" => "'" + v + "'"
case "scala.math.BigDecimal" => v.toString.trim + "d"
case "Byte" | "Short" | "Int" | "Double" | "Boolean" => v.toString
}
v match {
case Some(x) => s"Some(${raw(x)})"
case None => "None"
case x => raw(x)
}
}
}
}
}
I am using http://handsontable.com/ as one of the widgets for showing prices for my project, I could not find export and import from CSV feature in their API or FAQ.
Has anyone implemented or know about it ?
Yup, that comment links you to the explanation on how to do it, and here is my implementation of it for anyone that wants to just reuse code. There are a few enhancements beyond the basic CSV exporting like the escaping of spaces and special characters, as well as apostrophes. It also sets the column headers if they exist so remove that line if you don't have column headers.
The relevant code assuming you have a button with id=export-csv:
function parseRow(infoArray, index, csvContent) {
var sizeData = _.size(hot1.getData());
if (index < sizeData - 1) {
dataString = "";
_.each(infoArray, function(col, i) {
dataString += _.contains(col, ",") ? "\"" + col + "\"" : col;
dataString += i < _.size(infoArray) - 1 ? "," : "";
})
csvContent += index < sizeData - 2 ? dataString + "\n" : dataString;
}
return csvContent;
}
/**
* Export to CSV button
*/
var exportCsv = $("#export-csv")[0];
if (exportCsv) {
Handsontable.Dom.addEvent(exportCsv, "mouseup", function(e) {
exportCsv.blur(); // jquery ui hackfix
var csvContent = "data:text/csv;charset=utf-8,";
csvContent = parseRow(colHeaders, 0, csvContent); // comment this out to remove column headers
_.each(hot1.getData(), function(infoArray, index) {
csvContent = parseRow(infoArray, index, csvContent);
});
var encodedUri = encodeURI(csvContent);
var link = document.createElement("a");
link.setAttribute("href", encodedUri);
link.setAttribute("download", $("h1").text() + ".csv");
link.click();
})
}
Hope it helps!
I have the following snippet
class PresentationUpload {
def uploadForm(form:NodeSeq) : NodeSeq = {
var fileHolder: Box[FileParamHolder] = Empty
def handleFile() = {
fileHolder.map { holder =>
val filePath = "src/main/webapp/files"
val oFile = new File(filePath, holder.fileName)
val output = new FileOutputStream(oFile)
output.write(holder.file)
output.close()
} openOr {
// Do something
}
}
val bindForm = "type=file" #> fileUpload((fph) => fileHolder = Full(fph)) &
"type=submit" #> ajaxSubmit("Submit", handleFile _)
ajaxForm(bindForm(form))
}
}
The file uploads correctly but then reloads the application, is this the correct way to handle ajax uploads or is there another method I should be using?
Thanks for any help, much appreciated
I've configured the lift project (normally "project/build/LiftProject.scala") to not reload after changes to the files directory, problem solved :)
override def scanDirectories = (
temporaryWarPath / "WEB-INF" * ("classes" | "lib")
).get.toSeq
I'm following a phonegap tutorial and I do not know how to write this "def iphone_upload " action in ruby 1.9.2/rails 3.
http://wiki.phonegap.com/w/page/18270855/Image-Upload-using-JQuery-and-Python
function getPicture_Success(imageData)
{
var feedURL = APIPATH + "photos/iphone-upload/";
$.post(feedURL, {imageData:imageData}, function(data){
});
}
In Python (Django):
def iphone_upload(request):
import base64
data = base64.b64decode(request.POST.get("imageData"))
fileout = "/var/www/test.jpg"
f1 = open(fileout,'wb+')
f1.write(data)
f1.close()
def iphone_upload
#data = request.POST[:imageData].unpack("m")[0]
fileout = "/var/www/test.jpg"
File.open(fileout, 'w') {|f| f.write(#data) }
end