Assume I have a code with a button coded in ipyvuetify
v_btn_load = vue.Btn(class_='mx-2 light-red darken-1',
children=[vue.Icon(left=True, children=['get_app']),'Load data'])
def on_click_load(widget, event, data):
#pseudo code: load file
print("button run")
v_btn_load.on_event('click', on_click_load)
How do I run (click) programmatically the v_btn_load button?
v_btn_load.click() does not work
Thanks
the "on_click_load" is still a local python function, so you can simple access it in your script. Just fill out the variables you do not need with dummies (probably widget and event) and fill the data variable according to your needs.
If you need some input from the client, than it is more difficult. I know no way to remote control the client side. The only thing I got working so far is to extend VuetifyTemplate with a private class and specify some JS code to be run when 'Mounted'. This will run the code on display, but is not the same as triggering a click act:
Here is a simple example which directly copies the content of a variable to the local clipboard without any display element:
import ipyvuetify as v
from traitlets import Unicode, observe
class toClipboard(v.VuetifyTemplate):
"""Copies a given string directly to the users clipboard.
Parameters:
clipboardValue - The value to offer for copying to the clipboard
Example:
tunnel = toClipboard(clipboardValue='VALUE_TO_COPY')
Upon change of the variable 'clipboardValue', it's content will be automatically pushed to the clipboard
"""
clipboardValue = Unicode('').tag(sync=True)
template = Unicode('''
<script>
export default {
mounted () {
var tmpElement = $('<textarea>').val(this.clipboardValue).appendTo('body').select();
document.execCommand('copy');
$(tmpElement).remove();
},
}
</script>''').tag(sync=True)
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.observe(self.pushToClipboard, names=('clipboardValue'))
display(self)
def pushToClipboard(self, change):
display(self)
As an additional bonus this example uses the observe function of traitlets to redisplay the JS as soon as the value of the variable changes. This is a cheap workaround to create a bit similar behaviour.
I use the example above not in real GUIs, but as a lazy way in a Jupyther Notebook to automatically copy the result of a calculation to my local clipboard.
looking at the description of the v.Btn class I found this :
| ----------------------------------------------------------------------
| Methods inherited from ipyvue.VueWidget.Events:
|
| fire_event(self, event, data)
|
| on_event(self, event_and_modifiers, callback, remove=False)
I then assume that
v_btn_load.fire_event('click', None)
should do trick
Related
ok, I am not even entirely sure if my title is completely accurate as I completely do not understand class inheritance and instances at that moment but understand it is something that I need or should grasp moving forward.
Background: attempting to create a custom importer for my bank to be used with the popular Beancount/fava double entry ledger accounting system. I originally reported to fava as a bug but then realized its not a bug and its more my lack of general understanding of Python classes so thought it would be better to post here.
So...I have created the following import script file which as I understand is a sub class of beancount csv.Importer (https://github.com/beancount/beancount/blob/master/beancount/ingest/importers/csv.py) which is a sub class of beancount Importer (https://github.com/beancount/beancount/blob/master/beancount/ingest/importer.py)
In my importer I over ride 2 methods of csv.Importer, name() and file_account(). My goal is to derive the source account associated to input file based on file name and dictionary look-up. The extract() method I do not wish to over-ride in my sub class, however in the csv.Importer extract() method there is reference to self.account that represents the source account to use for extracted transactions. Currently the way my script is if I feed it a file named 'SIMPLII_9999_2018-01-01.csv' the account will be properly derived as 'Assets:Simplii:Chequing-9999'. However, if I stop short of actually importing the transactions in fava and instead attempt to extract the transactions again from the same file the derived account then becomes 'Assets:Simplii:Chequing-9999 :Chequing-9999'.
What I am trying to do is derive the source account from the input file and pass this information as the self.account variable in the parent class (csv.Importer) for my class instance (I think). What is it that I am doing wrong in my class that is causing the derived source account to be carried over to the next instance?
#!/usr/bin/env python3
from beancount.ingest import extract
from beancount.ingest.importers import csv
from beancount.ingest import cache
from beancount.ingest import regression
import re
from os import path
from smart_importer.predict_postings import PredictPostings
class SimpliiImporter(csv.Importer):
'''
Importer for the Simplii bank.
Note: This undecorated class can be regression-tested with
beancount.ingest.regression.compare_sample_files
'''
config = {csv.Col.DATE: 'Date',
csv.Col.PAYEE: 'Transaction Details',
csv.Col.AMOUNT_DEBIT: 'Funds Out',
csv.Col.AMOUNT_CREDIT: 'Funds In'}
account_map = {'9999':'Chequing-9999'}
def __init__(self, *, account, account_map=account_map):
self.account_map = account_map
self.account = 'Assets:Simplii'
super().__init__(
self.config,
self.account,
'CAD',
['Filename: .*SIMPLII_\d{4}_.*\.csv',
'Contents:\n.*Date, Transaction Details, Funds Out, Funds In'],
institution='Simplii'
)
def name(self):
cls = self.__class__
return '{}.{}'.format(cls.__module__, cls.__name__)
def file_account(self, file):
__account = None
if file:
m = re.match(r'.+SIMPLII_(\d{4})_.*', file.name)[1]
if m:
sub_account = self.account_map.get(m)
if sub_account:
__account = self.account + ':' + sub_account
return __account
def extract(self, file):
self.account = self.file_account(file)
return super().extract(file)
#PredictPostings(training_data='/beancount/personal.beancount')
class SmartSimpliiImporter(SimpliiImporter):
'''
A smart version of the Simplii importer.
'''
pass
so I have managed to get this working however I don't think its the proper way to do it...
I changed the extract function like this
def extract(self, file):
self.account = self.file_account(file)
postings = super().extract(file)
self.account = 'Assets:Simplii'
return postings
basically I set the self.account to the value I need to, call the parent class extract function saving results to variable, reset the self.account variable and return results. Seems more of a work around than the proper way but at least its here in case it helps someone else out...
NOTE: This question concerns the "first generation" Bokeh server, which has been deprecated and removed for several years. Nothing in this question or its answers is relevant to any version of Bokeh >= 0.11
For detailed information about using the modern, supported Bokeh Server, see the Running a Bokeh Server chapter of the User's Guide.
I'm trying to understand Bokeh for an interactive app that I'm building. I'm looking at the Bokeh examples, and I see that most of the examples are written all in the global namespace, but the ones in the "app" subdirectory are written in a nice, object-oriented style, where the main class inhereits from a Property class like HBox.
This is going to be a mish-mash of questions because I don't think this way of programming Bokeh was very well-documented. The first thing I encountered was that the plot didn't draw unless I included extra_generated_classes.
What does extra_generated_classes do?
Secondly, it looks like the event loop setup_events is called on startup before create and subsequently every time the plot triggers an event.
Why does setup_events need to register callbacks each time an event is triggered? And why doesn't it wait for create to finish before attempting to register them the first time?
The last thing I'm unsure about is how to force a redraw of a Glyph here. The slider demo works for me, and I'm trying to do basically the same thing, except with a scatterplot instead of a line.
I set a pdb trace at the very end of my update_data, and I can guarantee that self.source matches self.plot.renderers[-1].data_source and that both of them have been tweaked from the start. However, self.plot itself doesn't change.
What is the object-oriented approach's equivalent to calling store_objects to update the plot?
I'm especially confused by this third one, because it doesn't look like the sliders_app example needs anything like that. For clarification, I'm trying to make a variable number of widgets/sliders, so this is what my code looks like:
class attributes:
extra_generated_classes = [['ScatterBias', 'ScatterBias', 'HBox']]
maxval = 100.0
inputs = Instance(bkw.VBoxForm)
outputs = Instance(bkw.VBoxForm)
plots = Dict(String, Instance(Plot))
source = Instance(ColumnDataSource)
cols = Dict(String, String)
widgets = Dict(String, Instance(bkw.Slider))
# unmodified source
df0 = Instance(ColumnDataSource)
initialize method
#classmethod
def create(cls):
obj = cls()
##############################
## load DataFrame
##############################
df = pd.read_csv('data/crime2013_tagged_clean.csv', index_col='full_name')
obj.cols = {'x': 'Robbery',
'y': 'Violent crime total',
'pop': 'Population'
}
cols = obj.cols
# only keep interested values
df2= df.ix[:, cols.values()]
# drop empty rows
df2.dropna(axis=0, inplace=True)
df0 = df2.copy()
df0.reset_index(inplace=True)
# keep copy of original data
obj.source = ColumnDataSource(df2)
obj.df0 = ColumnDataSource(df0)
##############################
## draw scatterplot
##############################
obj.plots = {
'robbery': scatter(x=cols['x'],
y=cols['y'],
source=obj.source,
x_axis_label=cols['x'],
y_axis_label=cols['y']),
'pop': scatter(x=cols['pop'],
y=cols['y'],
source=obj.source,
x_axis_label=cols['pop'],
y_axis_label=cols['y'],
title='%s by %s, Adjusted by by %s'%(cols['y'],
cols['pop'], cols['pop'])),
}
obj.update_data()
##############################
## draw inputs
##############################
# bokeh.plotting.scatter
## TODO: refactor so that any number of control variables are created
# automatically. This involves subsuming c['pop'] into c['ctrls'], which
# would be a dictionary mapping column names to their widget titles
pop_slider = obj.make_widget(bkw.Slider, dict(
start=-obj.maxval,
end=obj.maxval,
value=0,
step=1,
title='Population'),
cols['pop'])
##############################
## make layout
##############################
obj.inputs = bkw.VBoxForm(
children=[pop_slider]
)
obj.outputs = bkw.VBoxForm(
children=[obj.plots['robbery']]
)
obj.children.append(obj.inputs)
obj.children.append(obj.outputs)
return obj
update_data
def update_data(self):
"""Update y by the amount designated by each slider"""
logging.debug('update_data')
c = self.cols
## TODO:: make this check for bad input; especially with text boxes
betas = {
varname: getattr(widget, 'value')/self.maxval
for varname, widget in self.widgets.iteritems()
}
df0 = pd.DataFrame(self.df0.data)
adj_y = []
for ix, row in df0.iterrows():
## perform calculations and generate new y's
adj_y.append(self.debias(row))
self.source.data[c['y']] = adj_y
assert len(adj_y) == len(self.source.data[c['x']])
logging.debug('self.source["y"] now contains debiased data')
import pdb; pdb.set_trace()
Note that I am sure that the event handler gets setup and triggered correctly. I just don't know how to make the changed source data reflect in the scatterplot.
I'm searching for the same answers (lack of documentation makes it difficult).
In answer, to question #1, what is the utility of "extra_generated_classes":
tl;dr extra_generated_classes defines a modulename, classname, and parentname used in template generating js/html code, and extends the parent class passed into the app class (usually HBox or VBox in the examples).
Longer answer. Look at the source code in bokeh/server/utils/plugins.py, this is the code that is run on code passed to bokeh-server using the --script command line argument. At the end of plugins.py, you can see that extra_generated_classes is passed to the flask method render_template, which renders a Jinja2 template. Looking inside the template, oneobj.html, extra_generated_classes is an array of arrays of three things: modulename, classname, and parentname, which are passed into bokeh.server.generatejs:
{% block extra_scripts %}
{% for modulename, classname, parentname in extra_generated_classes %}
<script
src="{{ url_for('bokeh.server.generatejs', modulename=modulename, classname=classname, parentname=parentname) }}"
></script>
{% endfor %}
{% endblock %}
bokeh.server.generatejs is a Python code in bokeh/server/views/plugins.py, and only calls render_template for a template app.js, which you can find in bokeh/server/templates. This template takes the modulename, classname, and parentname, and basically creates js code which extends the parentname (e.g. HBox or VBox) to the classname (your app).
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.
I have an add-on configuration page/form generated by plone.app.registry.browser.controlpanel
Using these Docs:
http://plone.org/documentation/kb/how-to-create-a-plone-control-panel-with-plone.app.registry
https://pypi.python.org/pypi/plone.app.registry#control-panel-widget-settings
On this form, I have an integer field:
from zope import schema
from plone.app.registry.browser import controlpanel
class MyAddonSettings(Interface):
partnerId = schema.Int(title=u"Partner Id",
description=u"enter your Partner ID",
required=True,
default=54321)
class SettingsEditForm(controlpanel.RegistryEditForm):
schema = MyAddonSettings
label = u"My settings"
description = u""""""
def updateFields(self):
super(SettingsEditForm, self).updateFields()
def updateWidgets(self):
super(SettingsEditForm, self).updateWidgets()
class SettingsControlPanel(controlpanel.ControlPanelFormWrapper):
form = SettingsEditForm
When the form renders, I get the integer field auto-filled with '54,321' I don't want the comma.
How to I specify "Don't do that!"
So, I think I went pretty deep down the rabbit hole, but here is what I came up with.
1) The default widget for zope.schema.Int is the TextWidget
2) z3c.form.converter.IntegerDataConverter Adapts itself to zope.schema.interfaces.IInt and ITextWidget
3) the IntegerDataConverter calls upon the locale to 'format the integer' for you, giving you a nice pretty representation of an int - with commas.
My choice was to create a new widget 'IntWidget' and a new converter 'NoFormatIntegerDataConverter', adapt these. Then manually set the field in question to my new widget:
I'm sure there is a less 'rabbit hole' way to do this, but I found myself at the bottom, so I completed the journey. I'll let a zope guru follow up with the 'right' way to do it.
=========================
create the new widget based on TextWidget
so we don't tie our new converter to everyone's TextWidget and break someone else's stuff
import zope.interface
import zope.component
import zope.schema.interfaces
import z3c.form.interfaces
from z3c.form.widget import FieldWidget
from z3c.form.browser.text import TextWidget
from z3c.form import converter
class IIntWidget(z3c.form.interfaces.ITextWidget):
"""Int Widget"""
class IntWidget(TextWidget):
zope.interface.implementsOnly(IIntWidget)
klass = u'int-widget'
value = u''
#zope.component.adapter(zope.schema.interfaces.IField,
z3c.form.interfaces.IFormLayer)
#zope.interface.implementer(z3c.form.interfaces.IFieldWidget)
def IntFieldWidget(field, request):
"""IFieldWidget factory for IntWidget."""
return FieldWidget(field, IntWidget(request))
zope.component.provideAdapter(IntFieldWidget)
Create the 'dumb' converter, and adapt it to our new widget 'IntWidget'
class NoFormatIntegerDataConverter(converter.IntegerDataConverter):
""" data converter that ignores the formatter,
simply returns the unicode representation of the integer value
The base class for this calls upon the locale for a formatter.
This completely avoids calling the locale.
"""
zope.component.adapts(zope.schema.interfaces.IInt, IIntWidget)
def toWidgetValue(self, value):
if value is self.field.missing_value:
return u''
#go look at z3c.form.converter.IntegerDataConverter
#to see what it used to return here.
return unicode(value)
zope.component.provideAdapter(NoFormatIntegerDataConverter)
Finally, update the field widget factory to use our new widget
class SettingsEditForm(controlpanel.RegistryEditForm):
...
def updateFields(self):
super(SettingsEditForm, self).updateFields()
self.fields['partnerId'].widgetFactory = IntFieldWidget #<----- Here
...
I just started with envisage framework. In the 4.x version I saw a few example, but I need a good documentation: link.
How can I add custom buttons to the envisage workbench, or how can I create a similar one?
The best place look for documentation is the Acmelab example in the Envisage source tree.
I'm assuming when you talk about custom buttons you mean buttons on a toolbar. First you need to create a WorkbenchActionSet, add your toolbar there, and then define your actions and assign them a button image. Here is the (slightly modified) Acmelab example with non-relevant parts taken out:
test_action_set.py
# Enthought library imports.
from envisage.ui.action.api import Action, Group, Menu, ToolBar
from envisage.ui.workbench.api import WorkbenchActionSet
class TestActionSet(WorkbenchActionSet):
""" An action test useful for testing. """
#### 'ActionSet' interface ################################################
tool_bars = [
ToolBar(name='Fred', groups=['AToolBarGroup']),
ToolBar(name='Wilma'),
ToolBar(name='Barney')
]
actions = [
Action(
path='ToolBar',
class_name='acme.workbench.action.new_view_action:NewViewAction'
),]
new_view_action.py
""" An action that dynamically creates and adds a view. """
# Enthought library imports.
from pyface.api import ImageResource
from pyface.action.api import Action
from pyface.workbench.api import View
class NewViewAction(Action):
""" An action that dynamically creates and adds a view. """
#### 'Action' interface ###################################################
# A longer description of the action.
description = 'Create and add a new view'
# The action's name (displayed on menus/tool bar tools etc).
name = 'New View'
# A short description of the action used for tooltip text etc.
tooltip = 'Create and add a new view'
image = ImageResource(Your Image File Name Goes Here)
###########################################################################
# 'Action' interface.
###########################################################################
def perform(self, event):
""" Perform the action. """
# You can give the view a position... (it default to 'left')...
view = View(id='my.view.fred', name='Fred', position='right')
self.window.add_view(view)
# or you can specify it on the call to 'add_view'...
view = View(id='my.view.wilma', name='Wilma')
self.window.add_view(view, position='top')
return
#### EOF ######################################################################