StateAccessViolation: Value must be a literal - Vyper Ethereum smart contract - ethereum

Version Information
vyper Version (output of vyper --version): 0.2.8+commit.069936f
OS: osx
Python Version (output of python --version): Python 2.7.16
Environment (output of pip freeze):
altgraph==0.10.2
bdist-mpkg==0.5.0
bonjour-py==0.3
macholib==1.5.1
matplotlib==1.3.1
modulegraph==0.10.4
numpy==1.8.0rc1
py2app==0.7.3
pyobjc-core==2.5.1
pyobjc-framework-Accounts==2.5.1
pyobjc-framework-AddressBook==2.5.1
pyobjc-framework-AppleScriptKit==2.5.1
pyobjc-framework-AppleScriptObjC==2.5.1
pyobjc-framework-Automator==2.5.1
pyobjc-framework-CFNetwork==2.5.1
pyobjc-framework-Cocoa==2.5.1
pyobjc-framework-Collaboration==2.5.1
pyobjc-framework-CoreData==2.5.1
pyobjc-framework-CoreLocation==2.5.1
pyobjc-framework-CoreText==2.5.1
pyobjc-framework-DictionaryServices==2.5.1
pyobjc-framework-EventKit==2.5.1
pyobjc-framework-ExceptionHandling==2.5.1
pyobjc-framework-FSEvents==2.5.1
pyobjc-framework-InputMethodKit==2.5.1
pyobjc-framework-InstallerPlugins==2.5.1
pyobjc-framework-InstantMessage==2.5.1
pyobjc-framework-LatentSemanticMapping==2.5.1
pyobjc-framework-LaunchServices==2.5.1
pyobjc-framework-Message==2.5.1
pyobjc-framework-OpenDirectory==2.5.1
pyobjc-framework-PreferencePanes==2.5.1
pyobjc-framework-PubSub==2.5.1
pyobjc-framework-QTKit==2.5.1
pyobjc-framework-Quartz==2.5.1
pyobjc-framework-ScreenSaver==2.5.1
pyobjc-framework-ScriptingBridge==2.5.1
pyobjc-framework-SearchKit==2.5.1
pyobjc-framework-ServiceManagement==2.5.1
pyobjc-framework-Social==2.5.1
pyobjc-framework-SyncServices==2.5.1
pyobjc-framework-SystemConfiguration==2.5.1
pyobjc-framework-WebKit==2.5.1
pyOpenSSL==0.13.1
pyparsing==2.0.1
python-dateutil==1.5
pytz==2013.7
scipy==0.13.0b1
six==1.4.1
xattr==0.6.4
this call of a for loop:
for i in range(self.some_uint256):
# do something...
is throwing the error:
StateAccessViolation: Value must be a literal
full error output:
vyper.exceptions.StateAccessViolation: Value must be a literalvyper.exceptions.StateAccessViolation: Value must be a literal
contract "vyper-farm/contracts/Farm.vy", function "_employ", line 152:4
151
---> 152 for i in range(self.num_employees):
-------------^
153 pass
what exactly am i doing wrong?
is this a misunderstanding as to what a literal is on my part?

Look at the description of range-function, there just one way to pass a variable to it:
for i in range(a, a + N):
pass
In your case it should be like this (not sure that it be useful):
num_employees: public(uint256)
#external
def __init__():
self.num_employees = 16
#external
def do_smth():
for i in range(self.num_employees, self.num_employees + 10):
pass

the issue above is not one of misunderstanding the for loop's use, instead it is a result of incompatible coding style with the security measures of vyper
the reason the for loop was being created was to make sure when an 'employee' was 'fired' or 'quit' then there wouldn't be an empty record in the list of 'employee's which was being maintained
instead, in order to avoid using a for loop altogether, and with a small sacrifice of not being able to remove no longer 'active employee's, best practice is to just track the 'employee' in a hashmap:
idToEmployee: HashMap[uint256, employee]
and when tracking the employees, simply assign an id attribute to the 'employee' using a global variable called num_employees
ex:
def employ():
new_employee: employee = employee ({
id: self.num_employees
})
self.idToEmployee[self.num_employees] = new_employee
when attempting to view or update that employee's info simply use:
self.idToEmployee[id]
#vladimir has a good explanation of how range is passed variables if there is still confusion about for loops in vyper for the reader

In fact, you can't use variables in range() directly, but we can use other method.
Here is my advice:
for i in range(999999):
if i < self.some_uint256:
# do something...
else:
break

Related

Count the number of people having a property bounded by two numbers

The following code goes over the 10 pages of JSON returned by GET request to the URL.
and checks how many records satisfy the condition that bloodPressureDiastole is between the specified limits. It does the job, but I was wondering if there was a better or cleaner way to achieve this in python
import urllib.request
import urllib.parse
import json
baseUrl = 'https://jsonmock.hackerrank.com/api/medical_records?page='
count = 0
for i in range(1, 11):
url = baseUrl+str(i)
f = urllib.request.urlopen(url)
response = f.read().decode('utf-8')
response = json.loads(response)
lowerlimit = 110
upperlimit = 120
for elem in response['data']:
bd = elem['vitals']['bloodPressureDiastole']
if bd >= lowerlimit and bd <= upperlimit:
count = count+1
print(count)
There is no access through fields to json content because you get dict object from json.loads (see translation scheme here). It realises access via __getitem__ method (dict[key]) instead of __getattr__ (object.field) as keys may be any hashible objects not only strings. Moreover, even strings cannot serve as fields if they starts with digits or are the same with built-in dictionary methods.
Despite this, you can define your own custom class realising desired behavior with acceptable key names. json.loads has an argument object_hook wherein you may put any callable object (function or class) that take a dict as the sole argument (not only the resulted one but every one in json recursively) & return something as the result. If your jsons match some template, you can define a class with predefined fields for the json content & even with methods in order to get a robust Python-object, a part of your domain logic.
For instance, let's realise the access through fields. I get json content from response.json method from requests but it has the same arguments as in json package. Comments in code contain remarks about how to make your code more pythonic.
from collections import Counter
from requests import get
class CustomJSON(dict):
def __getattr__(self, key):
return self[key]
def __setattr__(self, key, value):
self[key] = value
LOWER_LIMIT = 110 # Constants should be in uppercase.
UPPER_LIMIT = 120
base_url = 'https://jsonmock.hackerrank.com/api/medical_records'
# It is better use special tools for handling URLs
# in order to evade possible exceptions in the future.
# By the way, your option could look clearer with f-strings
# that can put values from variables (not only) in-place:
# url = f'https://jsonmock.hackerrank.com/api/medical_records?page={i}'
counter = Counter(normal_pressure=0)
# It might be left as it was. This option is useful
# in case of additional counting any other information.
for page_number in range(1, 11):
records = get(
base_url, data={"page": page_number}
).json(object_hook=CustomJSON)
# Python has a pile of libraries for handling url requests & responses.
# urllib is a standard library rewritten from scratch for Python 3.
# However, there is a more featured (connection pooling, redirections, proxi,
# SSL verification &c.) & convenient third-party
# (this is the only disadvantage) library: urllib3.
# Based on it, requests provides an easier, more convenient & friendlier way
# to work with url-requests. So I highly recommend using it
# unless you are aiming for complex connections & url-processing.
for elem in records.data:
if LOWER_LIMIT <= elem.vitals.bloodPressureDiastole <= UPPER_LIMIT:
counter["normal_pressure"] += 1
print(counter)

Django bulk update setting each to different values? [duplicate]

I'd like to update a table with Django - something like this in raw SQL:
update tbl_name set name = 'foo' where name = 'bar'
My first result is something like this - but that's nasty, isn't it?
list = ModelClass.objects.filter(name = 'bar')
for obj in list:
obj.name = 'foo'
obj.save()
Is there a more elegant way?
Update:
Django 2.2 version now has a bulk_update.
Old answer:
Refer to the following django documentation section
Updating multiple objects at once
In short you should be able to use:
ModelClass.objects.filter(name='bar').update(name="foo")
You can also use F objects to do things like incrementing rows:
from django.db.models import F
Entry.objects.all().update(n_pingbacks=F('n_pingbacks') + 1)
See the documentation.
However, note that:
This won't use ModelClass.save method (so if you have some logic inside it won't be triggered).
No django signals will be emitted.
You can't perform an .update() on a sliced QuerySet, it must be on an original QuerySet so you'll need to lean on the .filter() and .exclude() methods.
Consider using django-bulk-update found here on GitHub.
Install: pip install django-bulk-update
Implement: (code taken directly from projects ReadMe file)
from bulk_update.helper import bulk_update
random_names = ['Walter', 'The Dude', 'Donny', 'Jesus']
people = Person.objects.all()
for person in people:
r = random.randrange(4)
person.name = random_names[r]
bulk_update(people) # updates all columns using the default db
Update: As Marc points out in the comments this is not suitable for updating thousands of rows at once. Though it is suitable for smaller batches 10's to 100's. The size of the batch that is right for you depends on your CPU and query complexity. This tool is more like a wheel barrow than a dump truck.
Django 2.2 version now has a bulk_update method (release notes).
https://docs.djangoproject.com/en/stable/ref/models/querysets/#bulk-update
Example:
# get a pk: record dictionary of existing records
updates = YourModel.objects.filter(...).in_bulk()
....
# do something with the updates dict
....
if hasattr(YourModel.objects, 'bulk_update') and updates:
# Use the new method
YourModel.objects.bulk_update(updates.values(), [list the fields to update], batch_size=100)
else:
# The old & slow way
with transaction.atomic():
for obj in updates.values():
obj.save(update_fields=[list the fields to update])
If you want to set the same value on a collection of rows, you can use the update() method combined with any query term to update all rows in one query:
some_list = ModelClass.objects.filter(some condition).values('id')
ModelClass.objects.filter(pk__in=some_list).update(foo=bar)
If you want to update a collection of rows with different values depending on some condition, you can in best case batch the updates according to values. Let's say you have 1000 rows where you want to set a column to one of X values, then you could prepare the batches beforehand and then only run X update-queries (each essentially having the form of the first example above) + the initial SELECT-query.
If every row requires a unique value there is no way to avoid one query per update. Perhaps look into other architectures like CQRS/Event sourcing if you need performance in this latter case.
Here is a useful content which i found in internet regarding the above question
https://www.sankalpjonna.com/learn-django/running-a-bulk-update-with-django
The inefficient way
model_qs= ModelClass.objects.filter(name = 'bar')
for obj in model_qs:
obj.name = 'foo'
obj.save()
The efficient way
ModelClass.objects.filter(name = 'bar').update(name="foo") # for single value 'foo' or add loop
Using bulk_update
update_list = []
model_qs= ModelClass.objects.filter(name = 'bar')
for model_obj in model_qs:
model_obj.name = "foo" # Or what ever the value is for simplicty im providing foo only
update_list.append(model_obj)
ModelClass.objects.bulk_update(update_list,['name'])
Using an atomic transaction
from django.db import transaction
with transaction.atomic():
model_qs = ModelClass.objects.filter(name = 'bar')
for obj in model_qs:
ModelClass.objects.filter(name = 'bar').update(name="foo")
Any Up Votes ? Thanks in advance : Thank you for keep an attention ;)
To update with same value we can simply use this
ModelClass.objects.filter(name = 'bar').update(name='foo')
To update with different values
ob_list = ModelClass.objects.filter(name = 'bar')
obj_to_be_update = []
for obj in obj_list:
obj.name = "Dear "+obj.name
obj_to_be_update.append(obj)
ModelClass.objects.bulk_update(obj_to_be_update, ['name'], batch_size=1000)
It won't trigger save signal every time instead we keep all the objects to be updated on the list and trigger update signal at once.
IT returns number of objects are updated in table.
update_counts = ModelClass.objects.filter(name='bar').update(name="foo")
You can refer this link to get more information on bulk update and create.
Bulk update and Create

How to call a function with less arguments that is set (Python 3)

I am making a terminal emulator in Python 3. The commands are being stored in functions, like:
def rd(os_vartmp, os_vartmp2):
if os_vartmp == None:
print('rd [path] [-S]')
print('Delete a folder')
else:
if os.path.isfile(os_vartmp) == True:
if os_vartmp2 == '-S': print('a')
else:
print(ERR5)
a = input('Command: ')
The terminal works like this:
Asks user for input
Splits the input
Uses the first part of input to search a function in locals
If there is one, uses the rest part of input as argument
Calls the function
The thing here is, when i call the function 'rd' with, for example, 'rd "boot.py" -S' it works just fine. But if i need to call it like this: rd "boot.py", it throws me a error about 1 argument given when 2 are required. Is there a fix for that?
You can make an argument optional by assigning a value in the method definition. For example:
def Add(x=0, y=0):
return x+y
If you input only one value, y will default to 0. If I wanted to give y a value but have x fall back on it's default value I could do Add(y=10). I hope this helped!
Have you tried this?
def rd(os_vartmp, os_vartmp2="-S"):
Instead of trying to get null value, which would require rd("boot.py",null), you can ser default value and then you can do rd("boot.py").
Hope it works.

lua : passing parameter to other function problem

not sure did anyone ever face this kind of problem. here is my code
in main.lua :
local highScore = require("highScore")
local username = "myName"
local finishedTime = 12345
highScore:InsertHighScore(userName, finishedTime)
in highScore.lua
function InsertHighScore(name,time)
print(name)
print(time)
-- other code
end
it look simple and shouldn't be wrong, but in my console out put it show :
table: 0x19e6340
myName
after a day of testing, i found that before the 2 parameter that i pass, it actually passing another table to me, so do these changes on highScore.lua:
function InsertHighScore(table,name,time)
print(table)
print(name)
print(time)
-- other code
end
so now my "other code" can work nicely, but why it pass me a table before my parameter ?
In Lua, a call to an object/table with a colon instead of a dot indicates that the object/table should be passed into the function as the first parameter (e.g, as a self). If you don't care about that, then call the function with a dot instead:
highScore.InsertHighScore(userName, finishedTime)

Using functions on callbacks of a GUI

I'm using GUIDE to create an interface where a function [x,y]=function(a,b,c,d) will be executed when the button is clicked. Im having problems to get this to work. GUIDE creates an autogenerated function with the syntax varargout = LineasA(varargin).
I'm calling the GUI using this syntax [x,y]=LineasA(a,b,c,d).
Errors I get are:
Error in ==> LineasA>LineasA_OutputFcn at 73
varargout{1} = handles.output;
??? Error using ==> feval
Output argument "varargout{2}" (and maybe others) not assigned during call to
"C:\Users\ZeTa\Documents\MATLAB\ImagenB\LineasA.m>LineasA_OutputFcn".
Error in ==> gui_mainfcn at 263
[varargout{1:nargout}] = feval(gui_State.gui_OutputFcn, gui_hFigure, [],
gui_Handles);
Error in ==> LineasA at 40
[varargout{1:nargout}] = gui_mainfcn(gui_State, varargin{:});
Error in ==> ImagenB at 17
[MatrizB,Cuenta]=LineasA(Cuenta,waveformObj,channelObj,MatrizB);
You have to be clear where you are getting the inputs to this function, and where you want the outputs to go. It is proper coding to store the inputs and outputs in the handles struct that is passed into the callback. Also, the proper callback structure is:
LineasA(hObject, eventdata, handles)
However, if you insist on calling and storing from the base workspace, you can do as follows:
LineasA(hObject, eventdata, handles)
% grab values from base workspace
Cuenta = evalin('base', 'Cuenta');
waveformObj = evalin('base', 'waveformObj');
channelObj = evalin('base', 'channelObj');
MatrizB = evalin('base', 'MatrizB');
% the rest of your code
% assign outputs
assignin('base', 'MatrizB', matrizB);
assignin('base', 'Cuenta', Cuenta);
end
However I recommend getting those values in the handles structure and not to use evalin and assignin, they are usually bad coding techniques.