Throw blank even-numbered/left pages - python

I am trying to typeset a large document using ReportLab and Python 2.7.
It has a number of sections (about 6 in a 1,000 page document) and I would like each to start on odd-numbered/right-hand page. I have no idea though whether the preceding page will be odd or even and so need the ability to optionally throw an additional blank page before a particular paragraph style (like you sometimes get in manuals where some pages are "intentionally left blank"). Can anyone suggest how this could be done, as the only conditional page break I can find works on the basis of the amount of text on the page not a page number.
I also need to make sure that the blank page is included in the PDF so that double-sided printing works.

If you can keep track of page numbers, then just add a PageBreak or canvas.showPage() command at the appropriate times.

If you're using the platypus engine within reportlab, you could try overriding the BaseDocTemplate class and using the afterPage and beforePage hooks to keep track of page numbers. Then you can use showPage() whenever you encounter an even page.
For example:
from reportlab.platypus import BaseDocTemplate
from reportlab.lib.pagesizes import A4
from reportlab.platypus import PageTemplate
class MyDocTemplate(BaseDocTemplate):
"""Override the BaseDocTemplate class to split even/odd pages"""
def __init__(self, *args, **kwargs):
BaseDocTemplate.__init__(self, *args, **kwargs)
self.__pageNum = 1
def afterPage(self):
"""Called after all flowables have been drawn on a page"""
# Increment pageNum since the page has been completed
self.__pageNum += 1
def beforePage(self):
"""Called before any flowables are drawn on a page"""
# If the page number is even, force a page break
if self.__pageNum % 2 == 0:
self.canv.showPage()
# Increment pageNum again since we've added a blank page
self.__pageNum += 1
Then you can use the new MyDocTemplate class to create your document:
if __name__ == "__main__":
doc = MyDocTemplate(
'filename.pdf',
pagesize=A4,
rightMargin=.3*inch,
leftMargin=.3*inch,
topMargin=.3*inch,
bottomMargin=.3*inch
)
# Your flowables go here
elements = []
# Your PageTemplates go here
doc.addPageTemplates([])
doc.build(elements)

Related

gradio refresh interface when selecting File

I'm trying to create a gradio User Interface which does the following
on the left panel I have a File control, that allows the selection of a local file (eg. a .csv)
when a file is selected a "Process" button should be made visible
when the "Process" button is pressed, a function is called, reading the contents of the file, and processing it in some ways, resulting in a string
the resulting string is shown in a TextArea in the right column
I'm stuck implementing point 2. I can select the file, but can't make the Process button become visible.
This is my code so far (not yet implementing points 3. a:
import gradio as gr
def file_selected(file_input):
print("yes, file_selected is invoked")
print(process_button)
process_button.visible=True
demo.render()
return process_button
with gr.Blocks() as demo:
with gr.Row():
with gr.Column(scale=1):
gr.Markdown("### Data")
file_input = gr.File(label="Select File")
process_button = gr.Button("Process", visible=False)
with gr.Column(scale=2, min_width=600):
gr.Markdown("### Output")
result_display = gr.TextArea(default="", label="Result", lines=10, visible=False)
file_input.change(fn=file_selected, inputs=file_input, outputs=process_button)
if __name__ == "__main__":
demo.launch()
I see that at file selection the message is printed (and print(process_button) prints "button" so I'm sure this variable is not None), but the button doesn't appear on the page.
edited: fixed some errors not directly related to the problem.
There were many problems with the code (I fixed those not related with the main issue in the original post), but in the end what solved my problem (making the button visible) was that instead to rerender,
def file_selected():
...
process_button.visible=True
demo.render()
I just had to return the process_button.update
def file_selected(file_input):
...
return gr.update(visible=True)
(Actually this was documented in gradio's online docs; sorry, I didn't notice it before)
This is the complete working code:
import gradio as gr
def file_selected(file_input):
print("yes, file_selected is invoked")
print(process_button)
return gr.update(visible=True)
with gr.Blocks() as demo:
with gr.Row():
with gr.Column(scale=1):
gr.Markdown("### Data")
file_input = gr.File(label="Select File")
process_button = gr.Button("Process", visible=False)
with gr.Column(scale=2, min_width=600):
gr.Markdown("### Output")
result_display = gr.TextArea(default="", label="Result", lines=10, visible=False)
file_input.change(fn=file_selected, inputs=file_input, outputs=process_button)
if __name__ == "__main__":
demo.launch()

PyQt Quickly Update QTextEdit like QAbstractItemModel

Is there any way to make a model to update a QTextEdit like the QAbstractItemModel.
The QAbstractItemModel/QAbstractTableModel has a data (index[, role=Qt.DisplayRole]) method which is called whenever the view needs to display something. This allows me to make my own data structure to save data in python quickly. Is there any way to make a QTextEdit, QTextDocument, or QTextDocumentLayout work this way?
Right now I save data to a queue and periodically display the data by running update_display on a timer.
class QuickTextEdit(QtWidgets.QTextEdit):
def update_display(self):
for _ in range(len(self.queue)):
text, fmt = self.queue.popleft()
cursor = QtGui.QTextCursor(self.textCursor())
cursor.beginEditBlock()
# Move and check the position
pos = cursor.position()
cursor.movePosition(QtGui.QTextCursor.End)
is_end = cursor.position() == pos
# Insert the text
cursor.setCharFormat(fmt)
cursor.insertText(text)
cursor.endEditBlock()
# Move the cursor
if is_end:
# Actually move the text cursor
cursor.movePosition(QtGui.QTextCursor.End)
self.setTextCursor(cursor)
I found that this is much slower than the way a QAbstractTableModel/QTableView works.
I would like the widget to request data (instead of inserting) like the QAbstractItemModel. I tried using an html string in a QLabel.paintEvent, but couldn't get that to work properly. I really would just like an HTML Text Viewer for some data structure/model.
class QuickTextEdit(QtWidgets.QTextEdit):
def data(self):
return ''.join(('<font color="{color}">{text}</font>'.format(color=color, text=text)
for color, text in self.queue))
You can implement a simple model view setup yourself.
Here is some pseudo code:
class TextEditView(QtWidgets.QTextEdit):
def __init__(self, model):
connect(model.dataChanged, self.update_display)
#SLOT
def update_display(self):
text = model.data()
self.setText(text)
class TextEditModel(QObject):
SIGNAL dataChanged
def data(self):
new_text = queue.get_nowait()
return new_text
class WorkerThread(QtCore.QThread):
def run(self):
queue.put(new_data)
model.dataChanged.emit(index, index)
Then in your thread you would first put the new data into the queue. And then issue a model.dataChanged signal. Then the view would poll the new data.
Alternatively you can skip the whole Model view separation and create a signal for TextEditView with the datatype you want.
Let me know how it goes.

Django/Python - Unwanted caching of instances in views.py

I'm having an issue with a page running on Django 2.1. My issue is that when a function is called from views.py to populate a template, an instance of a class seems to be cached. Every subsequent call to that function/every refresh of that page shows old data from the previous time that page/function was called.
The code in question:
projectroot/myapp/templates/myapp/bar.html
#this is bar.html
{{ MyTable.DataColumns }}
<br>
{{ MyTable.DataRows }}
projectroot/myapp/views.py
#this is a relevant snippet from views.py
#There isn't anything outside of the functions,
#with imports being the exception to this rule
import myownpackage.DataTable import DataTable
def list_page(request):
template = 'foo/bar.html'
connection = a_connection_here
query_results = connection.get_query_results(sql_query_here)
list_of_rows = [x for x in query_results]
dt = DataTable()
dt.DataColumns = [list_of_columns_here]
for each_row in list_of_rows:
dt.add(each_row)
return_dict = {"MyTable": dt}
return render(request, template, return_dict)
projectroot/myownpackage/DataTable.py
class DataTable:
DataColumns = []
DataRows = []
def add(self, data_row):
if len(self.DataColumns) != len(data_row):
raise IndexError("Target column count does not match DataTable's DataColumn count.")
else:
self.DataRows.append(data_row)
def remove(self, index):
self.DataRows.remove(index)
The first time this page is loaded, foo/bar.html appears to be just what I want. I can see the columns printed to the page, and the few rows in that table.
The problem is visible if you refresh the page. It's as if dt is being cached after the function has returned the render().
When you refresh the page, you'll see the columns, and the rows from the first request duplicated! If we refresh a third time, we'll see a third set of those same rows! This appending of the DataTable goes on for as many times as you refresh. Clearly, dt is being stored outside of this function after being instantiated within the function, and I'm not sure why, or how, this is happening.
NOTE: Only the rows are being added over and over again. The columns remain the same. This is because the columns are being set on the table, while the rows are being added.
Things I've tried:
After dt is assigned to that return_dict, I've tried dt = None and del dt. Neither of these worked, and the same results were shown when refreshing the page.
My questions to Stack Overflow:
Why isn't the instance of DataTable called dt being thrown away after the function returns?
If this (for whatever the reason may be) is normal, what can I do to destroy that instance of DataTable when I'm done with it?
It turns out, the issue was that the DataRows were static in the DataTable class. That class should look like this:
class DataTable:
def __init__(self):
self.DataColumns = []
self.DataRows = []

Why is a website's response in python's `urllib.request` different to a request sent directly from a web-browser?

I have a program that takes a URL and gets a response from the server using urllib.request. It all works fine, but I tested it a little more and realised that when I put in a URL such as http://google.com into my browser, I got a different page (which had a doodle and a science fair promotion etc.) but with my program it was just plain Google with nothing special on it.
It is probably due to redirection, but if the request from my program goes through the same router and DNS, surely the output should be exactly the same?
Here is the code:
"""
This is a simple browsing widget that handles user requests, with the
added condition that all proxy settings are ignored. It outputs in the
default web browser.
"""
# This imports some necessary libraries.
import tkinter as tk
import webbrowser
from tempfile import NamedTemporaryFile
import urllib.request
def parse(data):
"""
Removes junk from the data so it can be easily processed.
:rtype : list
:param data: A long string of compressed HTML.
"""
data = data.decode(encoding='UTF-8') # This makes data workable.
lines = data.splitlines() # This clarifies the lines for writing.
return lines
class Browser(object):
"""This creates an object for getting a direct server response."""
def __init__(self, master):
"""
Sets up a direct browsing session and a GUI to manipulate it.
:param master: Any Tk() window in which the GUI is displayable.
"""
# This creates a frame within which widgets can be stored.
frame = tk.Frame(master)
frame.pack()
# Here we create a handler that ignores proxies.
proxy_handler = urllib.request.ProxyHandler(proxies=None)
self.opener = urllib.request.build_opener(proxy_handler)
# This sets up components for the GUI.
tk.Label(frame, text='Full Path').grid(row=0)
self.url = tk.Entry(frame) # This takes the specified path.
self.url.grid(row=0, column=1)
tk.Button(frame, text='Go', command=self.browse).grid(row=0, column=2)
# This binds the return key to calling the method self.browse.
master.bind('<Return>', self.browse)
def navigate(self, query):
"""
Gets raw data from the queried server, ready to be processed.
:rtype : str
:param query: The request entered into 'self.url'.
"""
# This contacts the domain and parses it's response.
response = self.opener.open(query)
html = response.read()
return html
def browse(self, event=None):
"""
Wraps all functionality together for data reading and writing.
:param event: The argument from whatever calls the method.
"""
# This retrieves the input given by the user.
location = self.url.get()
print('\nUser inputted:', location)
# This attempts to access the server and gives any errors.
try:
raw_data = self.navigate(location)
except Exception as e:
print(e)
# This executes assuming there are no errors.
else:
clean_data = parse(raw_data)
# This creates and executes a temporary HTML file.
with NamedTemporaryFile(suffix='.html', delete=False) as cache:
cache.writelines(line.encode('UTF-8') for line in clean_data)
webbrowser.open_new_tab(cache.name)
print('Done.')
def main():
"""Using a main function means not doing everything globally."""
# This creates a window that is always in the foreground.
root = tk.Tk()
root.wm_attributes('-topmost', 1)
root.title('DirectQuery')
# This starts the program.
Browser(root)
root.mainloop()
# This allows for execution as well as for importing.
if __name__ == '__main__':
main()
Note: I don't know if it is something to do with the fact that it is instructed to ignore proxies? My computer doesn't have any proxy settings turned on by the way. Also, if there is a way that I can get the same response/output as a web browser such as chrome would, I would love to hear it.
In order to answer your general question you need to understand how the web site in question operates, so this isn't really a Python question. Web sites frequently detect the browser's "make and model" with special detection code, often (as indicated in the comment on your question) starting with the User-Agent: HTTP header.
It would therefor make sense for Google's home page not to include any JavaScript-based functionality if the User-Agent identifies itself as a program.

Django PDF: How to display progress in browser?

The file will not display until the whole file is loaded. How can i display the progress in browser?
from io import BytesIO
from reportlab.pdfgen import canvas
from django.http import HttpResponse
def some_view(request):
# Create the HttpResponse object with the appropriate PDF headers.
response = HttpResponse(mimetype='application/pdf')
response['Content-Disposition'] = 'attachment; filename="somefilename.pdf"'
buffer = BytesIO()
# Create the PDF object, using the BytesIO object as its "file."
p = canvas.Canvas(buffer)
p.drawString(**, **, "Hello world.") # draw pdf, size > 10M
# Close the PDF object cleanly.
p.showPage()
p.save()
# Get the value of the BytesIO buffer and write it to the response.
pdf = buffer.getvalue()
buffer.close()
response.write(pdf)
return response
Well, in your example I think it would be pretty simple (and almost instantaneous). You would just print out/return a progress indicator for drawString, showPage, etc. Assuming the actual PDF you're generating is more involved, you could use the setProgressCallBack method of the BaseDocTemplate class. Of course, this would require that you use the reportlab platypus engine.
There are a few methods/properties of note (see the comments), let's say you have a custom template class which overrides BaseDocTemplate:
from reportlab.platypus import BaseDocTemplate
class MyDocTemplate(BaseDocTemplate):
"""Override BaseDocTemplate for "progress bar" information"""
def __init__(self, *args, **kwargs):
BaseDocTemplate.__init__(self, *args, **kwargs)
# BaseDocTemplate keeps a "progress" dictionary for its own
# internal use, which is updated as various drawings are done.
# This directs reportlab to use your own custom method
# as the "callback" function when updates are made.
# Notice the use of the __ prefix for the method, which ensures
# that it calls *your* custom class's method, and not the default.
# Should match the signature of the original callback: (self, type, value)
self.setProgressCallBack(self.__onProgress)
def __onProgress(self, prog_type, value):
"""Progress monitoring"""
# One example "progress type" is the "PAGE" key. Which indicates
# which page reportlab is working on.
if prog_type == "PAGE":
print "Drawing page: %s" % value
elif prog_type == "FINISHED":
print "Drawing complete!"
Here are some more values (you can see the code in reportlab.platypus.doctemplate):
def progressCB(typ, value):
"""Example prototype for progress monitoring.
This aims to provide info about what is going on
during a big job. It should enable, for example, a reasonably
smooth progress bar to be drawn. We design the argument
signature to be predictable and conducive to programming in
other (type safe) languages. If set, this will be called
repeatedly with pairs of values. The first is a string
indicating the type of call; the second is a numeric value.
typ 'STARTING', value = 0
typ 'SIZE_EST', value = numeric estimate of job size
typ 'PASS', value = number of this rendering pass
typ 'PROGRESS', value = number between 0 and SIZE_EST
typ 'PAGE', value = page number of page
type 'FINISHED', value = 0
The sequence is
STARTING - always called once
SIZE_EST - always called once
PROGRESS - called often
PAGE - called often when page is emitted
FINISHED - called when really, really finished
some juggling is needed to accurately estimate numbers of
pages in pageDrawing mode.
NOTE: the SIZE_EST is a guess. It is possible that the
PROGRESS value may slightly exceed it, or may even step
back a little on rare occasions. The only way to be
really accurate would be to do two passes, and I don't
want to take that performance hit.
"""
print 'PROGRESS MONITOR: %-10s %d' % (typ, value)

Categories