I want simple and easy integration of python and vba.
People, reading this may kill me if they meet me in person after reading this but I am using django development server for this purpose.
Is there any simple and better way.
Just for example:
I want to export comma separated string as excel file using python moduel openpyxl.
This is django app url.py
from django.conf.urls import url
from . import views
urlpatterns = [
url(r'identifier(.*)$', views.demo, name='index')
]
This is django app views.py
from django.http import HttpResponse
from openpyxl import Workbook
def demo(request, data):
(identifier, numbers, filepath) = data.split(';;;')
wb = Workbook()
ws_sent = wb.active
for number in numbers.split(','):
ws_sent.append((number.strip(),))
wb.save(filepath + identifier + '.xlsx')
return HttpResponse(identifier + " : Completed")
vba:
Sub demohttp()
Set httpobject = CreateObject("MSXML2.XMLHTTP")
url = "http://localhost:8000/appname/identifier;;;1,2,3,4,5,6,7,8,9;;;C:/ActiveDocument.Path"
httpobject.Open "GET", url, False
httpobject.send
msgbox httpobject.responseText
End Sub
This is blazing fast compared to:
calling python from vba shell functions
This is amazingly simple compared to:
automating excel from word vba.
Excel is just an example. I have so many python scripts I wanted to convert to django apps.
Questions
1) is there any downfall?
I have checked it for my maximum number count up to 1200 unique numbers.
2) is there any better way?
I tried to learn server side com but looks like mess.
Related
I stuck on the problem of how to organize code / proper way to get xlsx file as output in flask app.
I have a function.py file where for now the xlsx file generates.
The sense is that flask app gets some settings in json format, these settings are processed by function that must return xlsx(?) to app.
The function do some calculations depending on the settings.
The file has the next structure:
def function (settings):
settings=settings
df = pd.read_csv(settings['df'])
from pandas import ExcelWriter
writer = ExcelWriter('file.xlsx')
if settings[somefeature1]==1:
f1=dosmth.to_excel(writer, "feature 1")
if settings[somefeature2]==1:
f2=dosmth.to_excel(writer, "feature 2")
...
writer.save()
But if the file is already generated in function, what should I pass to flask? How the flask app function must look like then (especially in case if I want to return xlsx as json)?
#app.route('/Function', methods = ['POST'])
def Function():
settings = request.get_json(force = True)
return(function(settings)) #???
You should never forget that flask is a framework for creating web applications, a web application is a piece of software that receives a web request and generates a web response.
To make it super simple: your flask function should return something that a common web browser will be able to handle.
In this case your response should return the file but also some metadata to tell to the potential receiver what is inside the response and how to handle it.
I think that something like this could work:
return send_file(filename, mimetype='application/vnd.ms-excel')
Is there a way to detect unused templates in a Django project?
Before Django 1.3, that would have been possible with a simple string-matching function like this one. But since 1.3, there are generic class based views that automatically generate a template_name, if you don't override it (e.g. DetailView).
Also, if you override 3rd party module templates, those templates aren't used anywhere directly in your views.
Maybe it could be done by crawling all URL definitions, loading the corresponding views and getting the template_name from them?
I was curious if you could do this by monkey patching/decorating get_template instead. I think you can, though you have to find all the template loading
functions (I have two in my example below).
I used wrapt when I noticed it went beyond just loader.get_template, but it seems to the trick just fine. Of course, keep this 50000 km away from prod, but...
Now, the thing to follow as well is that I am driving this with unittests and nosetests so, if you have full branch coverage of your template-using Python code, you should be able to get most templates (assuming I didn't miss any get_template-type functions).
in settings.py
This is the "brains" to patch get_template & co.
import wrapt
import django.template.loader
import django.template.engine
def wrapper(wrapped, instance, args, kwargs):
#concatenate the args vector into a string.
# print "\n\n\n\n%s\nI am a wrapper \nusage:%s\n%s\n\n\n\n\n" % ("*"*80, usage, "*"*80)
try:
return wrapped(*args, **kwargs)
finally:
usage = ",".join([unicode(arg) for arg in args if arg])
track_usage(usage)
#you have to wrap whatever is loading templates...
#imported django module + class/method/function path of what needs to be
#wrapped within that module. comment those 2 lines out and you are back to
#normal
wrapt.wrap_function_wrapper(django.template.loader, 'get_template', wrapper)
wrapt.wrap_function_wrapper(django.template.engine, 'Engine.find_template', wrapper)
See safely-applying-monkey-patches-in-python for more details on wrapt. Actually easier to use than to understand the docs, decorators make my brain hurt.
Also, to track which django functions were doing the actual loads I mispelled some template names on purpose in the code and in templates, ran unit tests on it and looked at the stacktraces for missing template exceptions.
This is my rather badly-written function which adds to a set and puts it into
a json output....
def track_usage(usage):
fnp_usage = "./usage.json"
try:
with open(fnp_usage, "r") as fi:
data = fi.read()
#read the set of used templates from the json file
j_data = json.loads(data)
s_used_file = set(j_data.get("li_used"))
except (IOError,),e:
s_used_file = set()
j_data = dict()
s_used_file.add(usage)
#convert the set back to a list for json compatibility
j_data["li_used"] = list(s_used_file)
with open(fnp_usage, "w") as fo:
json.dump(j_data, fo)
and the ouput (with a script to format it):
import sys
import json
fnp_usage = sys.argv[1]
with open(fnp_usage, "r") as fi:
data = fi.read()
#read the set of used templates from the json file
j_data = json.loads(data)
li_used_file = j_data.get("li_used")
li_used_file.sort()
print "\n\nused templates:"
for t in li_used_file:
print(t)
From wrapping the 2 functions above, it seems to have caught extends, %includes and straight get_templates, as well as list-type templates that were being used by class-based views. It even caught my dynamically generated templates which aren't even on the file system but get loaded with a custom loader.
used templates:
bootstrap/display_form.html
bootstrap/errors.html
bootstrap/field.html
bootstrap/layout/baseinput.html
bootstrap/layout/checkboxselectmultiple.html
bootstrap/layout/field_errors.html
bootstrap/layout/field_errors_block.html
bootstrap/layout/help_text.html
bootstrap/layout/help_text_and_errors.html
bootstrap/layout/radioselect.html
bootstrap/whole_uni_form.html
django_tables2/table.html
dynamic_template:db:testdb:name:pssecurity/directive.PrimaryDetails.json
uni_form/layout/div.html
uni_form/layout/fieldset.html
websec/__base.html
websec/__full12.html
websec/__l_right_sidebar.html
websec/bootstrapped_home.html
websec/changedb.html
websec/login.html
websec/requirejs_config.html
websec/topnav.html
websec/user_msg.html
It's not possible to detect unused templates for certain, even in the absence of generic views, because you can always write code like this:
get_template(any_code_you_like()).render(context)
So even prior to Django 1.3 the django-unused-templates application you linked to could only have worked for projects that respected some kind of discipline about the use of templates. (For example, always having a string literal as the template argument to functions like get_template and render_to_response.)
Loading all the views wouldn't be sufficient either: a view may use different templates under different circumstances:
def my_view(request):
if request.user.is_authenticated():
return render(request, 'template1.html')
else:
return render(request, 'template2.html')
And of course templates may not be used by views at all, but by other parts of the system (for example, e-mail messages).
I want to generate for my users temporary download link.
Is that ok if i use django to generate link using url patterns?
Could it be correct way to do that. Because can happen that I don't understand some processes how it works. And it will overflow my memory or something else. Some kind of example or tools will be appreciated. Some nginx, apache modules probably?
So, what i wanna to achieve is to make url pattern which depend on user and time. Decript it end return in view a file.
A simple scheme might be to use a hash digest of username and timestamp:
from datetime import datetime
from hashlib import sha1
user = 'bob'
time = datetime.now().isoformat()
plain = user + '\0' + time
token = sha1(plain)
print token.hexdigest()
"1e2c5078bd0de12a79d1a49255a9bff9737aa4a4"
Next you store that token in a memcache with an expiration time. This way any of your webservers can reach it and the token will auto-expire. Finally add a Django url handler for '^download/.+' where the controller just looks up that token in the memcache to determine if the token is valid. You can even store the filename to be downloaded as the token's value in memcache.
Yes it would be ok to allow django to generate the urls. This being exclusive from handling the urls, with urls.py. Typically you don't want django to handle the serving of files see the static file docs[1] about this, so get the notion of using url patterns out of your head.
What you might want to do is generate a random key using a hash, like md5/sha1. Store the file and the key, datetime it's added in the database, create the download directory in a root directory that's available from your webserver like apache or nginx... suggest nginx), Since it's temporary, you'll want to add a cron job that checks if the time since the url was generated has expired, cleans up the file and removes the db entry. This should be a django command for manage.py
Please note this is example code written just for this and not tested! It may not work the way you were planning on achieving this goal, but it works. If you want the dl to be pw protected also, then look into httpbasic auth. you can generate and remove entries on the fly in a httpd.auth file using htpasswd and the subprocess module when you create the link or at registration time.
import hashlib, random, datetime, os, shutil
# model to hold link info. has these fields: key (charfield), filepath (filepathfield)
# datetime (datetimefield), url (charfield), orgpath (filepathfield of the orignal path
# or a foreignkey to the files model.
from models import MyDlLink
# settings.py for the app
from myapp import settings as myapp_settings
# full path and name of file to dl.
def genUrl(filepath):
# create a onetime salt for randomness
salt = ''.join(['{0}'.format(random.randrange(10) for i in range(10)])
key = hashlib('{0}{1}'.format(salt, filepath).hexdigest()
newpath = os.path.join(myapp_settings.DL_ROOT, key)
shutil.copy2(fname, newpath)
newlink = MyDlink()
newlink.key = key
newlink.date = datetime.datetime.now()
newlink.orgpath = filepath
newlink.newpath = newpath
newlink.url = "{0}/{1}/{2}".format(myapp_settings.DL_URL, key, os.path.basename(fname))
newlink.save()
return newlink
# in commands
def check_url_expired():
maxage = datetime.timedelta(days=7)
now = datetime.datetime.now()
for link in MyDlink.objects.all():
if(now - link.date) > maxage:
os.path.remove(link.newpath)
link.delete()
[1] http://docs.djangoproject.com/en/1.2/howto/static-files/
It sounds like you are suggesting using some kind of dynamic url conf.
Why not forget your concerns by simplifying and setting up a single url that captures a large encoded string that depends on user/time?
(r'^download/(?P<encrypted_id>(.*)/$', 'download_file'), # use your own regexp
def download_file(request, encrypted_id):
decrypted = decrypt(encrypted_id)
_file = get_file(decrypted)
return _file
A lot of sites just use a get param too.
www.example.com/download_file/?09248903483o8a908423028a0df8032
If you are concerned about performance, look at the answers in this post: Having Django serve downloadable files
Where the use of the apache x-sendfile module is highlighted.
Another alternative is to simply redirect to the static file served by whatever means from django.
I have a python script running fine on my localhost. Its not an enterprise app or anything, just something I'm playing around with. It uses the "bottle" library. The app basically consumes an XML file (stored either locally or online) which contains elements with their own unique IDs, as well as some coordinates, eg mysite.com/23 will bring back the lat/long of element 23. I'm sure you're all familiar with REST at this stage anyway.
Now, I want to put this online, but have had trouble finding a host that supports "bottle". I have, however, found a host that has django installed.
So, my question is, how hard would it be to convert the following code from bottle to django? And can someone give me some pointers? I've tried to use common python libraries.
thanks.
from xml.dom.minidom import parseString
from bottle import route, run
import xml
import urllib
file = open('myfile.xml','r')
data = file.read()
dom = parseString(data)
#route('/:number')
def index(number="1"):
rows = dom.getElementsByTagName("card")[0].getElementsByTagName("markers")[0].getElementsByTagName("marker")
for row in rows:
if row.getAttribute("number") == str(number):
return str(xml.dumps({'long': row.getAttribute("lng"), 'lat': row.getAttribute("lat")}, sort_keys=True, indent=4))
return "Not Found"
run(host='localhost', port=8080)
I took your question as an opportunity to learn a bit more about Django. I used The Django Book as a reference.
Starting with an empty Django site (django-admin.py startproject testsite), I've changed urls.py to this:
from django.conf.urls.defaults import patterns, include, url
from testsite.views import index
urlpatterns = patterns('',
url(r'^(\d+)$', index),
)
And views.py to this:
from django.http import HttpResponse
from xml.dom.minidom import parseString
import xml
import urllib
def index(request, number):
data = open('myfile.xml', 'r').read()
dom = parseString(data)
rows = (dom.getElementsByTagName("card")[0]
.getElementsByTagName("markers")[0]
.getElementsByTagName("marker"))
for row in rows:
if row.getAttribute("number") == str(number):
return HttpResponse(str(xml.dumps({'long': row.getAttribute("lng"),
'lat': row.getAttribute("lat")}, sort_keys=True, indent=4)))
return HttpResponse("Not Found")
Caveat: I've not tested the XML code, only Django-related one, which I've tested via python manage.py runserver.
The Django Book contains a lot of information, including how to deploy this on a production server.
Is it possible to open a file on GAE just to read its contents and get the last modified tag?
I get a IOError: [Errno 13] file not accessible:
I know that i cannot delete or update but i believe reading should be possible
Has anyone faced a similar problem?
os.stat(f,'r').st_mtim
You've probably declared the file as static in app.yaml. Static files are not available to your application; if you need to serve them both as static files and read them as application files, you'll need to include 2 copies in your project (ideally using symlinks, so you don't actually have to maintain an actual copy.)
Update Nov 2014:
As suggested in the comments, you can now do this with the application_readable flag:
application_readable
Optional. By default, files declared in static file handlers are
uploaded as static data and are only served to end users, they cannot
be read by an application. If this field is set to true, the files are
also uploaded as code data so your application can read them. Both
uploads are charged against your code and static data storage resource
quotas.
See https://cloud.google.com/appengine/docs/python/config/appconfig#Static_Directory_Handlers
You can read files, but they're on Goooogle's wacky GAE filesystem so you have to use a relative path. I just whipped up a quick app with a main.py file and test.txt in the same folder. Don't forget the 'e' on st_mtime.
import os
from google.appengine.ext import webapp
from google.appengine.ext.webapp import util
class MainHandler(webapp.RequestHandler):
def get(self):
path = os.path.join(os.path.split(__file__)[0], 'test.txt')
self.response.out.write(os.stat(path).st_mtime)
def main():
application = webapp.WSGIApplication([('/', MainHandler)],
debug=True)
util.run_wsgi_app(application)
if __name__ == '__main__':
main()
+1 for the new "application_readable: true" feature. Before using this new feature I did run into an issue with GAEs' "wacky" file system while getting the NLP Montylingua to import.
Issue: Monty uses the open(filename,'rb') and a file pointer to file_ptr.read() in bytes from the static files. My implementation worked on my local windows system but failed upon deployment!
The fix: Specify the expected bytes to read file_ptr.read(4) #4 binary bytes
Appears to be something related to the 64 bit GAE server wanting to read in more (8 by default) bytes. Anyways, took a while to find that issue. Montylingua loads now.
I came up strange but working solution :) Jinja :)
Serving static files directly sometimes become a headache with GAE. Possible trade-off from performance let you move straigh forward with Jinja
- url: /posts/(.*\.(md|mdown|markdown))
mime_type: text/plain
static_files: static/posts/\1
upload: posts/(.*\.(md|mdown|markdown))
from jinja2 import Environment
from jinja2.loaders import FileSystemLoader
posts = Environment(loader=FileSystemLoader('static/posts/')) # Note that we use static_files folder defined in app.yaml
post = posts.get_template('2013-11-13.markdown')
import markdown2 # Does not need of course
class Main(webapp2.RequestHandler):
def get ( self ):
self.response.headers[ 'Content-Type' ] = 'text/html'
self.response.write ( markdown2.markdown( post.render()) ) # Jinja + Markdown Render function
Did you get it ;) I tested and It worked.
With webapp2, supposing you have pages/index.html at the same path as main.py:
#!/usr/bin/env python
import webapp2, os
class MainHandler(webapp2.RequestHandler):
def get(self):
path = os.path.join(os.path.split(__file__)[0], 'pages/index.html')
with open(path, 'r') as f:
page_content = f.read()
self.response.write(page_content)
app = webapp2.WSGIApplication([
('/', MainHandler)
], debug=True)
I can't see an answer for when the file hasn't been marked as static, and you're trying to read it in mode 'rt'; apparently that doesn't work. You can however open files just fine in mode 'rb', or just plain 'r'. (I wasted about 10 minutes on that 't'.)