I am nooby to Plugin Development but I'm trying to create a plugin in QGIS, for a Uni-subject, with its own graphical interface, which will receive a zipcode from the user and return the name of the corresponding location.
I already created the plugin skeleton, through the Plugin Builder and have designed the graphical interface with QtDesigner https://i.stack.imgur.com/h6k6Q.png . I also added the .txt file that contains the zipcodes database to the plugin folder as a resource.
From what I understand, the file to edit is the one that ends in dialog.py, through the init() method, in order to establish the connections between the signals emitted by the elements of the graphical interface and the corresponding callbacks.
However, when I change the code in the dialog.py and reload the plugin, it gives me an error, and when starting the QGIS it pop-ups an error message, and the plugin no longer appears. Error message after plugin reload
Could you give me some guidance here and maybe point me to where the problem could be? Thanks
The code is this one:
import os
import sys
import qgis.core
from qgis.PyQt import uic
from qgis.PyQt import (
QtCore,
QtWidgets
)
import geocoder
sys.path.append(os.path.dirname(__file__))
FORM_CLASS, _ = uic.loadUiType(
os.path.join(
os.path.dirname(__file__),
"example_dialog_base.ui"
),
resource_suffix=""
)
class ExampleDialog(QtWidgets.QDialog, FORM_CLASS):
POSTAL_CODES_PATH = ":/plugins/example/todos_cp.txt"
def __init__(self, parent=None):
"""Constructor."""
super(ExampleDialog, self).__init__(parent)
self.setupUi(self)
# connect signals
self.postal_code_le.textChanged.connect(self.toggle_find_button)
self.find_code_btn.clicked.connect(self.execute)
# set initial state
self.find_code_btn.setEnabled(False)
def toggle_find_button(self):
if self.postal_code_le.text() == "":
self.find_code_btn.setEnabled(False)
else:
self.find_code_btn.setEnabled(True)
def execute(self):
self.address_te.clear()
try:
raw_postal_code = self.postal_code_le.text()
main_code, extension = validate_postal_code(raw_postal_code)
record = self.find_record(main_code, extension)
place_name = record[3]
self.address_te.setPlainText(place_name)
if self.create_layer_chb.isChecked():
self.handle_layer_creation(record)
except (ValueError, RuntimeError) as err:
self.show_error(str(err))
def find_record(self, main_code, extension):
file_handler = QtCore.QFile(self.POSTAL_CODES_PATH)
file_handler.open(QtCore.QIODevice.ReadOnly)
stream = QtCore.QTextStream(file_handler)
while not stream.atEnd():
line = stream.readLine()
info = line.split(";")
code1 = info[-3]
code2 = info[-2]
if code1 == main_code and code2 == extension:
result = info
break
else:
raise RuntimeError("Sem resultados")
return result
def handle_layer_creation(self, record):
place_name = record[3]
point = geocode_place_name(place_name)
print("lon: {} - lat: {}".format(point.x(), point.y()))
layer = create_point_layer(
point,
f"found_location_for_{record[-3]}_{record[-2]}",
place_name
)
current_project = qgis.core.QgsProject.instance()
current_project.addMapLayer(layer)
def show_error(self, message):
message_bar = self.iface.messageBar()
message_bar.pushMessage("Error", message, level=message_bar.Critical)
def validate_postal_code(raw_postal_code):
code1, code2 = raw_postal_code.partition("-")[::2]
if code1 == "" or code2 == "":
raise ValueError(
"Incorrect postal code: {!r}".format(raw_postal_code))
return code1, code2
def geocode_place_name(place_name):
geocoder_object = geocoder.osm(place_name)
lon = geocoder_object.json.get("lng")
lat = geocoder_object.json.get("lat")
if lat is None or lon is None:
raise RuntimeError(
"Could not retrieve lon/lat for "
"place: {!r}".format(place_name)
)
point = qgis.core.QgsPointXY(lon, lat)
return point
def create_point_layer(point, layer_name, place_name):
layer = qgis.core.QgsVectorLayer(
"Point?crs=epsg:4326&field=address:string(100)",
layer_name,
"memory"
)
provider = layer.dataProvider()
geometry = qgis.core.QgsGeometry.fromPointXY(point)
feature = qgis.core.QgsFeature()
feature.setGeometry(geometry)
feature.setAttributes([place_name])
provider.addFeatures([feature])
layer.updateExtents()
return layer
Related
I am currently working on a project that involves graphing text file data into a pyqt graph and I have been running into problems with a subclass QDialog box. My goal is to have the QDialog box use a combox to choose between different data sets to graph (The code below shows the "steering angle" setting being chosen). The problem lies with how to make it so that when the Create Graph button is pressed (Found in the QDialog Class), it runs the createGraph(self): function in the main class. I dont know how to work classes that well so I dont know how to make this work.
If anyone has any pointers on either how to get this working, how to properly structure a PYQT Program or how to make it more efficient, I'm all ears.
Thank you for your time!
Main Window Code:
class MainWidget(QMainWindow):
def __init__(self, parent=None):
super(MainWidget, self).__init__(parent)
self.activateWindow()
self.raise_()
self.setupGraph()
self.dockcheck = 0
self.graphcheck = 0
self.setWindowTitle("Drag and Drop Test")
self.resize(1200, 800)
self.setAcceptDrops(True)
self.LBLDragAndDrop = QLabel("Drag And Drop Files Here")
self.LBLDragAndDrop.setAlignment(Qt.AlignHCenter | Qt.AlignVCenter)
if self.graphcheck == 0:
self.setCentralWidget(self.LBLDragAndDrop)
self.path3 = "C:\\Users\\steph\\OneDrive\\Documents\\SAA Wing\\Coding\\Can Bus Data Reading\\Temporary Saves"
self.treeview = QTreeView()
self.treeview.setAnimated(True)
self.fileModel = QFileSystemModel()
self.fileModel.setRootPath(self.path3)
self.indexRoot = self.fileModel.index(self.fileModel.rootPath())
self.treeview.setModel(self.fileModel)
self.treeview.setRootIndex(self.fileModel.index(self.path3))
self.treeview.setColumnWidth(0, 250)
self.treeview.doubleClicked.connect(self.onSelectionChanged)
#self.treeview.doubleClicked.connect(self.openDialog)
####################################################################################################################
# Dialog Box
####################################################################################################################
def onSelectionChanged(self, index):
self.selectionPath = self.sender().model().filePath(index)
self.selectionFilename = (self.selectionPath.split("/")[-1])
IDList = ("ID 00d0","ID 00d1","ID 00d3","ID 00d4","ID 0140","ID 0141","ID 0360","ID 0361")
if self.selectionFilename in IDList:
if self.selectionFilename == "ID 00d0":
editDialog = Dialog00d0()
editDialog.exec_()
####################################################################################################################
# Graphing data
####################################################################################################################
def createGraph(self):
self.graphcheck = 1
if self.graphcheck == 1:
self.setCentralWidget(self.scroll_area)
################################################################################################################
# ID 00D0 Creating Graph
################################################################################################################
if self.selectionFilename == "ID 00d0":
self.df00d0 = pd.read_table(self.selectionPath, header=None , delim_whitespace=True, dtype=object)
self.df00d0.columns = ['Timestamp','ID',"B0","B1","B2","B3","B4","B5","B6","B7"]
self.df00d0.dropna(inplace=True)
self.SA = np.array([], dtype=float)
self.LatAcc = np.array([], dtype=float)
self.LonAcc = np.array([], dtype=float)
self.ComAcc = np.array([], dtype=float)
self.Time00d0 = np.array([], dtype=float)
self.Timestamp00d0 = np.array([], dtype=float)
############################################################################################################
# Getting Time Stamps
############################################################################################################
for item in self.df00d0['Timestamp']:
self.Time00d0 = np.append(self.Time00d0, datetime.fromtimestamp(float(item)).strftime("%H:%M:%S.%f")[:-4])
self.Timestamp00d0 = np.append(self.Timestamp00d0, float(item))
############################################################################################################
# Steering Angle Graph
############################################################################################################
if self.combobox00d0.currentText() == "Steering Angle":
SA_ = (((self.df00d0['B1']) + (self.df00d0['B0'])).apply(int, base=16) * 0.1)
for item in SA_:
if item > 6000:
self.SA = np.append(self.SA, round((item - 6553.6), 1))
else:
self.SA = np.append(self.SA, round(item))
y_value = self.SA
Here is the QDialog Box class code:
class Dialog00d0(QDialog):
def __init__(self):
super().__init__()
self.layout = QVBoxLayout()
hlay = QHBoxLayout()
self.setLayout(self.layout)
self.setWindowTitle("Create Graph")
label = QLabel("Data Type")
self.combobox00d0 = QComboBox()
self.combobox00d0.addItem("Steering Angle")
self.combobox00d0.addItem("Latitudinal Acceleration")
self.combobox00d0.addItem("Longitudinal Acceleration")
self.combobox00d0.addItem("Combined Acceleration")
self.BTNCreateGraph = QPushButton("Create Graph")
self.BTNCancel = QPushButton("Cancel")
hlay.addWidget(self.BTNCreateGraph)
hlay.addWidget(self.BTNCancel)
self.layout.addWidget(label)
self.layout.addWidget(self.combobox00d0)
self.layout.addLayout(hlay)
self.BTNCreateGraph.clicked.connect("I need the self.creatGraph here")
self.BTNCancel.clicked.connect("self.close")
I imagine this will help you.
The pyqtSignal() argument tells you what information you want to carry.
In this case, I'm passing a text.
Good luck, I hope I helped.
import sys
from PyQt5.QtWidgets import QMainWindow, QDialog, QApplication
from PyQt5.QtWidgets import QPushButton, QVBoxLayout
from PyQt5 import QtCore, QtGui
class MainWidget(QMainWindow):
def __init__(self, parent=None):
super(MainWidget, self).__init__(parent)
button = QPushButton("Button to open dialog")
button.clicked.connect(self.button_clicked)
self.setCentralWidget(button)
self.show()
def button_clicked(self):
dlg = Dialog00d0()
dlg.signEmit.connect(self.createGraph)
dlg.exec()
def createGraph(self, _str):
print('Now Im here')
print(_str)
class Dialog00d0(QDialog):
signEmit = QtCore.pyqtSignal(str)
def __init__(self):
super().__init__()
self.layout = QVBoxLayout()
self.BTNCreateGraph = QPushButton("link to createGraph()")
self.layout.addWidget(self.BTNCreateGraph)
self.setLayout(self.layout)
self.BTNCreateGraph.clicked.connect(self.BTNCreateGraph_clicked)
def BTNCreateGraph_clicked(self):
self.signEmit.emit('But I passed by')
app = QApplication(sys.argv)
win = MainWidget()
app.exec()
We have a Locust load/performance test running (in a docker-compose setup).
It now runs on our build-server.
Ideally we would like the build-job to fail if certain requirements are not met.
For example require a certain average response time, or a minimum number of requests within a given timeout.
The expections/requirements must be compared with the aggregated data. So not in the individual (python) test methods.
One option can be to parse the generated reports, but I imagine locust has built-in support for the feature I'm thinking of.
Have a look at locust-plugins, specifically the custom command line options like --check-rps, --check-fail-ratio and --check-avg-response-time
https://github.com/SvenskaSpel/locust-plugins/blob/master/examples/cmd_line_examples.sh
For the purpose of automated KPI validation, you could create a custom plugin using locust’s event hooks and its inner statistics. The overall plugin design is pretty simple:
Register quitting event
Get all statistics and serialize them
Calculate missing metrics (RPS, percentiles, …)
Check provided KPI definition
Validate provided KPI agains actual measurements
The whole KPI plugin code looks like this:
import logging
from enum import Enum
from typing import List
import locust.env
from locust.stats import calculate_response_time_percentile
class Metric(Enum):
EROR_RATE = 'error_rate'
PERCENTILE_90 = 'percentile_90'
RPS = 'rps'
#staticmethod
def has_value(item):
return item in [v.value for v in Metric.__members__.values()]
class KpiPluigin:
def __init__(
self,
env: locust.env.Environment,
kpis: List,
):
self.env = env
self.kpis = kpis
self.errors = []
self._validate_kpis()
events = self.env.events
events.quitting.add_listener(self.quitting) # pyre-ignore
def quitting(self, environment):
serialized_stats = self.serialize_stats(self.env.stats)
updated_stats = self._update_data(serialized_stats)
self._kpi_check(updated_stats)
self._interpret_errors()
def serialize_stats(self, stats):
return [stats.entries[key].serialize() for key in stats.entries.keys() if
not (stats.entries[key].num_requests == 0 and stats.entries[key].num_failures == 0)]
def _update_data(self, stats):
for stat in stats:
stat['error_rate'] = self._calculate_fail_rate(stat)
stat['percentile_90'] = self._calculate_percentile(stat, 0.90)
stat['rps'] = self._calculate_rps(stat)
return stats
def _calculate_rps(self, stat):
rps = stat['num_reqs_per_sec']
num_of_measurements = len(rps)
return sum(rps.values()) / num_of_measurements
def _calculate_fail_rate(self, stat):
num_failures = stat['num_failures']
num_requests = stat["num_requests"]
return (num_failures / num_requests) * 100
def _calculate_percentile(self, stat, percentile):
response_times = stat['response_times']
num_requests = stat['num_requests']
return calculate_response_time_percentile(response_times, num_requests, percentile)
def _kpi_check(self, stats):
if len(stats) == 0:
return
for kpi in self.kpis:
name = list(kpi.keys())[0]
stat = next(stat for stat in stats if stat["name"] == name)
if stat:
kpi_settings = kpi[list(kpi.keys())[0]]
for kpi_setting in kpi_settings:
self._metrics_check(kpi_setting, stat)
def _metrics_check(self, kpi_setting, stat):
(metric, value) = kpi_setting
name = stat["name"]
if metric == Metric.EROR_RATE.value:
error_rate = stat['error_rate']
error_rate <= value or self._log_error(error_rate, kpi_setting, name)
if metric == Metric.PERCENTILE_90.value:
percentile = stat['percentile_90']
percentile <= value or self._log_error(percentile, kpi_setting, name)
if metric == Metric.RPS.value:
rps = stat['rps']
rps >= value or self._log_error(rps, kpi_setting, name)
def _log_error(self, stat_value, kpi_settings, name):
(metric, value) = kpi_settings
self.errors.append(
f"{metric} for '{name}' is {stat_value}, but expected it to be better than {value}") # noqa: E501
def _interpret_errors(self):
if len(self.errors) == 0:
logging.info('All KPIs are good!')
else:
for error in self.errors:
logging.error(f"SLA failed: \n {error}")
self.env.process_exit_code = 1
def _validate_kpis(self):
for kpi in self.kpis:
kpi_keys = list(kpi.keys())
if len(kpi_keys) > 1:
raise Exception("Every dict must contain definition for only one endpoint")
kpi_settings = kpi[kpi_keys[0]]
if len(kpi_settings) == 0:
raise Exception(f"No KPI defined for endpoint {kpi_keys[0]}")
for kpi_setting in kpi_settings:
(metric, value) = kpi_setting
if not isinstance(value, (int, float)):
raise Exception(f"Provide valid value for '{metric}' metric for endpoint {kpi_keys[0]}")
if not Metric.has_value(metric):
raise Exception(f"Metric {metric} not implemented")
Now you have to register KpiPlugin class within your Locust script and define KPI(s) like this:
events.init.add_listener
def on_locust_init(environment, **_kwargs):
KPI_SETTINGS = [{'/store/inventory': [('percentile_90', 50), ('rps', 500), ('error_rate', 0)]}]
KpiPlugin(env=environment, kpis=KPI_SETTINGS)
The above script will make your build fail in case /store/inventory endpoint won't meet one of the defined criteria — 90 percentile is worse than 50ms, RPS is under 500, the error rate is higher than 0%.
I am creating a REST API using Flask, SQLAlchemy, and Marshmallow. I have defined my Product Model in app.py as:
from flask import Flask, request, jsonify
from flask_sqlalchemy import SQLAlchemy
from flask_marshmallow import Marshmallow
import os
# Initialize App
app = Flask(__name__)
basedir = os.path.abspath(os.path.dirname(__file__))
# Database Setup
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///' + os.path.join(basedir, 'db.sqlite')
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
# Init db
db = SQLAlchemy(app)
# Init marshmallow
ma = Marshmallow(app)
# Product Class/Model
class Product(db.Model):
id = db.Column(db.Integer, primary_key=True)
price = db.Column(db.Integer)
qty = db.Column(db.Integer)
def __init__(self, price, qty):
self.price = price
self.qty = qty
# Product Schema
class ProductSchema(ma.Schema):
class Meta:
fields = ('id', 'price', 'qty')
# Init Schema
product_schema = ProductSchema()
products_schema = ProductSchema(many=True)
# Create Product
#app.route('/product', methods=['POST'])
def add_product():
price = request.json['price']
qty = request.json['qty']
new_product = Product(price, qty)
db.session.add(new_product)
db.session.commit()
return product_schema.jsonify(new_product)
# Run the Server
if __name__ == '__main__':
app.run(debug=True)
I have to perform the following logic:
Setting price value between 0 - 100
Setting qty value between 0 - 100
If success return 200, if anything wrong return 500.
I am not able to set Integer value between the given range by db.Integer([0, 100]) as its giving me error:
TypeError: Integer() takes no arguments
How do I implement the above logic?
Edit: I've misunderstood the question and made a new function.
def ExpectedRange(var1):
return 200 if var1 in range(0,100) else 500
# Create Product
#app.route('/product', methods=['POST'])
def add_product():
price = request.json['price']
qty = request.json['qty']
if ExpectedRange(price) and ExpectedRange(qty) == 200:
new_product = Product(price, qty)
db.session.add(new_product)
db.session.commit()
return product_schema.jsonify(new_product)
#else:
# Show error. I recommend you using the method 'flash' in flask.
I think the problem with your code by using db.Integer([0, 100]) as a way to find the value between 0 and 100, instead, what you should be doing is by using range with the help of a method called randrange from the library random. With all due respect, I actually don't know what you are trying to accomplish, if I am wrong, please correct me in the comments and I'll correct my post.
What I recommend you doing is to not set the price and qty in the model class, but rather, in an entirely different function and using your model class to create the elements within your database. For example:
from random import randrange
class Product(db.Model):
id = db.Column(db.Integer, primary_key=True)
price = db.Column(db.Integer)
qty = db.Column(db.Integer)
def ProductRange(range1, range2):
return randrange(range1, range2)
print(ProductRange(1,100))
What the function ProductRange will do is to choose the range between the variable range1 and range2. As for returning 200 and 500, I am not sure what you could use with this value, but I recommend doing boolean. If it is needed, 200 and 500 is simply a constant, and you could easily implement it via putting it in a function rather than using the returned value to calculate things. So, how would you use the ProductRange function? Just follow the code below.
from random import randrange
class Product(db.Model):
id = db.Column(db.Integer, primary_key=True)
product_name = db.Column(db.String) # Ignore this line, this just for the /addpost route to get the method POST
price = db.Column(db.Integer)
qty = db.Column(db.Integer)
def ProductRange(range1, range2):
return randrange(range1, range2)
# This route is just an example of how you would use the function ProductRange
#app.route('/addpost', methods=['POST'])
def addpost():
product_name = request.form['product_name']
price = ProductRange(1,100)
qty = ProductRange(1,100)
post = Product[product_name=product_name, price=price, qty=qty]
db.session.add(post)
db.session.commit()
return redirect(url_for('index'))
If it doesn't work, please comment down below for me to help you further with this question of yours. I wish you good luck.
since you have installed marshmallow, install the marmallow-sqlalchemy and use SQLAlchemyAutoSchema feature which will allow to you to refer directly to the model and create an instance after successful load of the json object sent in request body, plus you can define your own constraints in the schema class. the marshmallow conf. will look like:
from marshmallow import ValidationError, fields
from marshmallow.validate import Range
from marshmallow_sqlalchemy import SQLAlchemyAutoSchema
ma = Marshmallow(app)
# to return marshmallow parsing error
#app.errorhandler(ValidationError)
def handle_marshmallow_validation(err):
print(err)
return jsonify(err.messages), 400
# Product Schema
class ProductSchema(ma.SQLAlchemyAutoSchema):
id = fields.Integer(required=False)
price = fields.Integer(required=True, validate=[Range(max=100, error="Value must be 100 or less")])
qty = fields.Integer(required=True, validate=[Range(max=100, error="Value must be 100 or less")])
class Meta:
model = Product
load_instance = True
now the ressource will look like:
# Create Product
#app.route('/product', methods=['POST'])
def add_product():
# here we can check the payload validity, parse it and transform it directly to instance
product_json = request.get_json()
new_product = product_schema.load(product_json)
db.session.add(new_product)
db.session.commit()
return product_schema.dump(new_product)
now if you sent value outside the range you will receive response like this
{
"price": [
"Value must be 100 or less"
],
"qty": [
"Value must be 100 or less"
]
}
I am facing a problem in developing a chatbot using rasa .
I am trying to call a custom function in rasa action file. But i am getting an error saying "name 'areThereAnyErrors' is not defined"
here is my action class. I want to call areThereAnyErrors function from run method. Could someone please help how to resolve this?
class ActionDayStatus(Action):
def areThereAnyErrors(procid):
errormessagecursor = connection.cursor()
errormessagecursor.execute(u"select count(*) from MT_PROSS_MEAGE where pro_id = :procid and msg_T = :messageT",{"procid": procid, "messageT": 'E'})
counts = errormessagecursor.fetchone()
errorCount = counts[0]
print("error count is {}".format(errorCount))
if errorCount == 0:
return False
else:
return True
def name(self):
return 'action_day_status'
def run(self, dispatcher, tracker, domain):
import cx_Oracle
import datetime
# Connect as user "hr" with password "welcome" to the "oraclepdb" service running on this computer.
conn_str = dbconnection
connection = cx_Oracle.connect(conn_str)
cursor = connection.cursor()
dateIndicator = tracker.get_slot('requiredDate')
delta = datetime.timedelta(days = 1)
now = datetime.datetime.now()
currentDate = (now - delta).strftime('%Y-%m-%d')
print(currentDate)
cursor = connection.cursor()
cursor.execute(u"select * from M_POCESS_FILE where CREATE_DATE >= TO_DATE(:createDate,'YYYY/MM/DD') fetch first 50 rows only",{"createDate":currentDate})
all_files = cursor.fetchall()
total_number_of_files = len(all_files)
print("total_number_of_files are {}".format(total_number_of_files))
Answer given by one of the intellectuals :
https://realpython.com/instance-class-and-static-methods-demystified/ Decide whether you want a static method or class method or instance method and call it appropriately . Also when you are using connection within the function it should be a member variable or passed to the method You dont have self as a parameter so you may be intending it as a static method - but you dont have it created as such
I have created a google app engine application called Ascii Art at this link http://ascii-chan-1018.appspot.com/ but for some reason sometimes when you post something it gives you this error code on the screen
"500 Internal Server Error The server has either erred or is incapable of performing the requested operation." Sometimes it works and sometimes it gives you this error code. I'm not sure if its my source code or if its an error on google's servers.
import os
import re
import sys
import urllib2
import random
import logging
from xml.dom import minidom
from string import letters
import webapp2
import jinja2
from google.appengine.api import memcache
from google.appengine.ext import db
template_dir = os.path.join(os.path.dirname(__file__), 'templates')
jinja_env = jinja2.Environment(loader = jinja2.FileSystemLoader(template_dir), autoescape=True)
art_key = db.Key.from_path('ASCIIChan', 'arts')
def console(s):
sys.stderr.write('%s\n' % s)
IP_URL = "http://api.hostip.info/?ip="
def get_coords(ip):
ip = "17.173.254.223"
url = IP_URL + ip
content = None
try:
content = urllib2.urlopen(url).read()
except URLError:
return
if content:
d = minidom.parseString(content)
coords = d.getElementsByTagName("gml:coordinates")
if coords and coords[0].childNodes[0].nodeValue:
lon, lat = coords[0].childNodes[0].nodeValue.split(',')
return db.GeoPt(lat, lon)
class Handler(webapp2.RequestHandler):
def write(self, *a, **kw):
self.response.out.write(*a, **kw)
def render_str(self, template, **params):
t = jinja_env.get_template(template)
return t.render(params)
def render(self, template, **kw):
self.write(self.render_str(template, **kw))
GMAPS_URL = "http://maps.googleapis.com/maps/api/staticmap?size=380x263&sensor=false&"
def gmap_img(points):
markers = '&'.join('markers=%s,%s' % (p.lat, p.lon) for p in points)
return GMAPS_URL + markers
class Art(db.Model):
title = db.StringProperty(required = True)
art = db.TextProperty(required = True)
created = db.DateTimeProperty(auto_now_add = True)
coords = db.GeoPtProperty( )
def top_arts(update = False):
key = 'top'
arts = memcache.get(key)
if arts is None or update:
logging.error("DB QUERY")
arts = db.GqlQuery("SELECT * "
"FROM Art "
"WHERE ANCESTOR IS :1 "
"ORDER BY created DESC "
"LIMIT 10",
art_key)
arts = list(arts)
memcache.set(key, arts)
return arts
class MainPage(Handler):
def render_front(self, title="", art="", error=""):
arts = top_arts()
img_url = None
points = filter(None, (a.coords for a in arts))
if points:
img_url = gmap_img(points)
#display the image URL
self.render("Ascii.html", title = title, art = art, error = error, arts = arts, img_url = img_url)
def get(self):
self.render_front()
def post(self):
title = self.request.get("title")
art = self.request.get("art")
if title and art:
p = Art(parent=art_key, title = title, art = art)
#lookup the user's coordinates from their IP
coords = get_coords(self.request.remote_addr)
#if we have coordinates, add them to the art
if coords:
p.coords = coords
p.put()
#rerun the query and update the cache
top_arts(True)
self.redirect("/")
else:
error = "Invalid, are you sure you entered a title and art work?"
self.render_front(error = error, title = title, art =art)
app = webapp2.WSGIApplication([('/', MainPage)])
Well I'm not sure if you can consider it solving the problem but I just removed the google maps code that was left over. It kept complaining about the line except URLError, so after I removed the maps code it worked fine, and my initial plan was to remove it anyways.