How to store values in a pyramid session? - session

Let's assume that I use the default pyramid UnencryptedCookieSessionFactory
...
my_session_factory = UnencryptedCookieSessionFactoryConfig('itsaseekreet')
config = Configurator(settings=settings)
config.set_session_factory(my_session_factory)
...
and define two views with a link to each other:
#view_config(route_name='t1')
def t1(request):
session = request.session
session['fred'] = '***'
session['abc'] = '&&&'
return Response(str(session.__dict__) + 't2')
#view_config(route_name='t2')
def t2(request):
session = request.session
return Response(str(session.__dict__) + 't1')
If I visit t1 in browser I get the following output:
{'accessed': 1377760577, '_dirty': True, 'request': , 'new': False, 'created': 1377760540.30155}t2
and if i follow the link to t2:
{'accessed': 1377760577, 'request': , 'new': False, 'created': 1377760540.30155}t1
But I would expect something different for t1 and t2:
{ ..., 'fred': '***', 'abc': '&&&', ...}
Why are the values not stored in the session? And what does the _dirty flag mean?

session.__dict__ is not the api for dealing with sessions. The session underneath is implemented as a dict object which does not use __dict__ to store its contents. You're simply printing out the attributes on the class which are unrelated. Print out something like session.items() instead or just session since its a dict.

Related

Data Store - dash_table conditional formatting failing

#dashapp.callback(
Output(component_id='data-storage', component_property='data'),
Input(component_id='input', component_property='n_submit')
.
.
.
return json_data
#dashapp.callback(
Output('table', component_property='columns'),
Output('table', component_property='data'),
Output('table', component_property='style_cell_conditional'),
Input(component_id='data-storage', component_property='data'),
.
.
.
column_name = 'Target Column'
value = 'This value is a string'
table_columns = [{"name": i, "id": i} for i in df.columns]
table_data = df.to_dict("records")
conditional_formatting = [{
'if': {
'filter_query': f'{{{column_name}}} = {value}'
},
'backgroundColor': 'white',
'color' : 'black',
}
]
return table_columns, table_data, conditional_formatting
When the code above is used WITH the conditional_formatting part - it works for some 'value's, and does not work for other 'value's
When the code above is used WITHOUT the conditional_formatting part - it works as expected for all 'value's
To be noted that when the conditional_formatting part is used, all callbacks are triggered twice. After this happens, the Data Store acts as if it has been infected by the "sick" value and does not allow new data.
Example:
Step 1. Use working input -> All callbacks triggered once -> Data Store is populated -> Data is displayed as expected
Step 2. Use working input -> All callbacks triggered once -> Data Store is populated -> Data is displayed as expected
Step 3. Use not working input -> All callbacks triggered once -> All callbacks are triggered again -> Data related to Input from b) is displayed
Step 4. Use working input -> All callbacks triggered once -> All callbacks are triggered again -> Data related to Input from b) is displayed
Any ideas why does this happen?
Any feedback is appreciated!
conditional_formatting = [{
'if': {
'filter_query': f'{{{column_name}}} = "{value}"'
},
'backgroundColor': 'white',
'color' : 'black',
}
]
Issue was because the failing values had empty space (e.g. San Francisco). Adding quotes around solved the issue.

Any ways to use "space:delete" by part of partial key in Tarantool?

The documentation says "delete cannot work with partial keys". What is your recommendation how to solve it. For example create new index, use cycle delete or any way?
You can delete values in a loop using a primary key.
#!/usr/bin/env tarantool
local json = require('json')
local function key_from_tuple(tuple, key_parts)
local key = {}
for _, part in ipairs(key_parts) do
table.insert(key, tuple[part.fieldno] or box.NULL)
end
return key
end
box.cfg{}
box.once('init', function()
box.schema.space.create('s')
box.space.s:create_index('pk')
box.space.s:create_index('sk', {
unique = false,
parts = {
{2, 'number'},
{3, 'number'},
}
})
end)
box.space.s:truncate()
box.space.s:insert{1, 1, 1}
box.space.s:insert{2, 1, 1}
print('before delete')
print('---')
box.space.s:pairs():each(function(tuple)
print(json.encode(tuple))
end)
print('...')
local key_parts = box.space.s.index.pk.parts
for _, tuple in box.space.s.index.sk:pairs({1}) do
local key = key_from_tuple(tuple, key_parts)
box.space.s.index.pk:delete(key)
end
print('after delete')
print('---')
box.space.s:pairs():each(function(tuple)
print(json.encode(tuple))
end)
print('...')
os.exit()
In the example above a common case is handled using key_from_tuple function. Things may be simpler when you know which fields form a primary key. Say, if it is the first field:
for _, tuple in box.space.s.index.sk:pairs({1}) do
box.space.s.index.pk:delete(tuple[1])
end
The new key_def module that was added in tarantool-2.2.0-255-g22db9c264 (not released yet, but availiable from our 2.2 repository) simplifies extracting a key from a tuple, especially in case of json path indexes:
#!/usr/bin/env tarantool
local json = require('json')
local key_def_lib = require('key_def')
box.cfg{}
box.once('init', function()
box.schema.space.create('s')
box.space.s:create_index('pk')
box.space.s:create_index('sk', {
unique = false,
parts = {
{2, 'number', path = 'a'},
{2, 'number', path = 'b'},
}
})
end)
box.space.s:truncate()
box.space.s:insert{1, {a = 1, b = 1}}
box.space.s:insert{2, {a = 1, b = 2}}
print('before delete')
print('---')
box.space.s:pairs():each(function(tuple)
print(json.encode(tuple))
end)
print('...')
local key_def = key_def_lib.new(box.space.s.index.pk.parts)
for _, tuple in box.space.s.index.sk:pairs({1}) do
local key = key_def:extract_key(tuple)
box.space.s.index.pk:delete(key)
end
print('after delete')
print('---')
box.space.s:pairs():each(function(tuple)
print(json.encode(tuple))
end)
print('...')
os.exit()
(source of the code)
Starting from Tarantool 2.1, you can use SQL syntax for that ('delete from ... where ...').
However, be aware that Tarantool will try to perfrom this in a transaction, so if you're trying to delete too many tuples, it will lock transaction thread for some time.

How to update bokeh active interaction with GeoJSON as data source?

I have made an interactive choropleth map with bokeh, and I'm trying to add active interactions using the dropdown widget (Select). However, most tutorials and SO questions about active interactions use ColumnDataSource, and not GeoJSONDataSource.
The issue is that GeoJSONDataSource doesn't have a .data method like ColumnDataSource does, so idk exactly how the syntax works when updating it.
My dataset is a dictionary in the form of city_dict = {'Amsterdam': <some data frame>, 'Antwerp': <some data frame>, ...}, where the dataframe is in geojson format. I have already confirmed that this format works when making glyphs.
def update(attr, old, new):
s_value = dropdown.value
p.title.text = '%s', s_value
new_src1 = make_dataset(s_value)
val1 = GeoJSONDataSource(new_src1)
r1.data_source = val1
where make_dataset is a function that transforms my original dataset into a dataset that can feed into the GeoJSONDataSource function. make_dataset requires a string (name of the city) to work eg. 'Amsterdam'. It works on passive interactions.
The main plot code (removed unnecessary stuff) is:
dropdown = Select(value='Amsterdam', options = cities)
controls = WidgetBox(dropdown)
initial_city = 'Amsterdam'
a = make_dataset(initial_city)
src1 = GeoJSONDataSource(a)
p = figure(title = 'Amsterdam', plot_height = 750 , plot_width = 900, toolbar_location = 'right')
r1 = p.patches('xs','ys', source = src1, fill_color = {'field' :'norm', 'transform' : color_mapper})
dropdown.on_change('value', update)
layout = row(controls, p)
curdoc().add_root(layout)
I've added the error I get. error handling message Message 'PATCH-DOC' (revision 1) content: {'events': [{'kind': 'ModelChanged', 'model': {'type': 'Select', 'id': '1147'}, 'attr': 'value', 'new': 'Antwerp'}], 'references': []}: ValueError("expected a value of type str, got ('%s', 'Antwerp') of type tuple",)

How to save and display Dashing historical values?

Currently to setup a graph widget, the job should pass all values to be displayed:
data = [
{ "x" => 1980, "y" => 1323 },
{ "x" => 1981, "y" => 53234 },
{ "x" => 1982, "y" => 2344 }
]
I would like to read just current (the latest) value from my server, but previous values should be also displayed.
It looks like I could create a job, which will read the current value from the server, but remaining values to be read from the Redis (or sqlite database, but I would prefer Redis). The current value after that should be saved to the database.
I never worked with Ruby and Dashing before, so the first question I have - is it possible? If I will use Redis, then the question is how to store the data since this is key-value database. I can keep it as widget-id-1, widget-id-2, widget-id-3 ... widget-id-N etc., but in this case I will have to store N value (like widget-id=N). Or, is there any better way?
I came to the following solution:
require 'redis' # https://github.com/redis/redis-rb
redis_uri = URI.parse(ENV["REDISTOGO_URL"])
redis = Redis.new(:host => redis_uri.host, :port => redis_uri.port, :password => redis_uri.password)
if redis.exists('values_x') && redis.exists('values_y')
values_x = redis.lrange('values_x', 0, 9) # get latest 10 records
values_y = redis.lrange('values_y', 0, 9) # get latest 10 records
else
values_x = []
values_y = []
end
SCHEDULER.every '10s', :first_in => 0 do |job|
rand_data = (Date.today-rand(10000)).strftime("%d-%b") # replace this line with the code to get your data
rand_value = rand(50) # replace this line with the code to get your data
values_x << rand_data
values_y << rand_value
redis.multi do # execute as a single transaction
redis.lpush('values_x', rand_data)
redis.lpush('values_y', rand_value)
# feel free to add more datasets values here, if required
end
data = [
{
label: 'dataset-label',
fillColor: 'rgba(220,220,220,0.5)',
strokeColor: 'rgba(220,220,220,0.8)',
highlightFill: 'rgba(220,220,220,0.75)',
highlightStroke: 'rgba(220,220,220,1)',
data: values_y.last(10) # display last 10 values only
}
]
options = { scaleFontColor: '#fff' }
send_event('barchart', { labels: values_x.last(10), datasets: data, options: options })
end
Not sure if everything is implemented correctly here, but it works.

ajax and ruby script only returning 1 record instead of many

I am doing an Ajax call, using Ruby and Sinatra. The query should return multiple rows, it only returns one though.
The ajax script is:
$(document).ready(function() {
$(".showmembers").click(function(e) {
e.preventDefault();
alert('script');
var short_id = $('#shortmembers').val();
console.log(short_id);
$.getJSON(
"/show",
{ 'id' : short_id },
function(res, status) {
console.log(res);
$('#result').html('');
$('#result').append('<input type=checkbox value=' + res["email"] + '>');
$('#result').append( res["first"] );
$('#result').append( res["last"] );
$('#result').append( res["email"] );
});
});
});
and the Ruby script is:
get '/show' do
id = params['id']
DB["select shortname, first, last, email from shortlists sh JOIN shortmembers sm ON sm.short_id = sh.list_id JOIN candidates ca ON ca.id = sm.candidate_id where sh.list_id = ?", id].each do |row|
#shortname = row[:shortname]
#first = row[:first]
#last = row[:last]
#email = row[:email]
puts #shortname
puts #first
puts #last
puts #email
halt 200, { shortname: #shortname, first: #first, last: #last, email: #email }.to_json
end
end
If I run the query directly in the terminal on postgres I get 9 rows returned but, as above on my website, it just returns the first row only.
What's the problem? No error in the console, just one record.
You have halt 200 inside your loop. This will cause Sinatra to terminate the request processing and return the result back up the stack.
To return a full set of results, you will need to do something like the following:
get '/show' do
id = params['id']
results = DB["select shortname, first, last, email from shortlists sh
JOIN shortmembers sm ON sm.short_id = sh.list_id
JOIN candidates ca ON ca.id = sm.candidate_id
where sh.list_id = ?", id].map do |row|
{
:short_name => row[:shortname],
:first=>row[:first],
:last=>row[:last],
:email=>row[:email]
}
end
halt 200, results.to_json
end
This will return the selected fields from each row as an array of hashes.
In fact, as I look at the above, the solution might even be as simple as:
get '/show' do
id = params['id']
results = DB["select shortname, first, last, email from shortlists sh
JOIN shortmembers sm ON sm.short_id = sh.list_id
JOIN candidates ca ON ca.id = sm.candidate_id
where sh.list_id = ?", id]
halt 200, results.to_json
end
since you don't seem to be selecting anything but the columns you desire in the first place.

Resources