Tuple index out of range in Airflow XCom - airflow-scheduler

I am working with Airflow and XComs and want to return multiple values from the function, however, I am facing the problem. The following is my code:
def authenticate_api():
#Define the global variables
# API authentication
url = 'odoo'
db = 'db'
username = 'admin'
password = 'user'
logging.info("Variables assigned")
common = xmlrpclib.ServerProxy('{}/xmlrpc/2/common'.format(url))
uid = common.authenticate(db, username, password, {})
models = xmlrpclib.ServerProxy('{}/xmlrpc/2/object'.format(url))
return db, models, uid, password
def get_max_date_from_odoo(**context):
# Variables
list = []
list2 = []
db = context['task_instance'].xcom_pull(key=None, task_ids='authenticate_api')
models = context['task_instance'].xcom_pull(key=None, task_ids='authenticate_api')
uid = context['task_instance'].xcom_pull(key=None, task_ids='authenticate_api')
password = context['task_instance'].xcom_pull(key=None, task_ids='authenticate_api')
#Get the customer id and date to use in the query
datesandids = models.execute_kw(db, uid, password,
'res.partner', 'search_read',
[[['is_company', '=', False]]],
{'fields': ['x_customer_register_date', 'x_customer_id']})
It returns:
('database', <ServerProxy for odoo069/xmlrpc/2/object>, 1, '1234')
as a tuple. Therefore I am getting an error of:
(db, uid, passwd ) = params[0], int(params[1]), params[2]\nIndexError: tuple index out of range\n'>
Any help would be really appreciated

Instead of getting the individual values, you are returning the tuple containing all values and assigning it to all of the variables.
Try this:
def get_max_date_from_odoo(**context):
# Variables
list = []
list2 = []
db, models, uid, password = context['task_instance'].xcom_pull(key=None, task_ids='authenticate_api')
...
That should save you hitting the database 4 times to get the same value.
Alternatively, since we are unsure of the type that is returned from the XCOM (expected tuple, could be json encoded).
def get_max_date_from_odoo(**context):
# Variables
list = []
list2 = []
values = context['task_instance'].xcom_pull(key=None, task_ids='authenticate_api')
if isinstance(values, tuple):
db, models, uid, password = values
elif isinstance(values, str):
import json
values = json.loads(values)
db, models, uid, password = values

Related

how to correctly use connection pool get & close w/ mysql.connector in python

I'm new to Python. I learned the concept of the connection pool recently, and I want to add it to my code, but have no idea about how to add get_connection() and .close() to my app...
from mysql.connector import pooling
poolname ="mysqlpool"
poolsize = 3
connectionpool = mysql.connector.pooling.MySQLConnectionPool(
pool_name =poolname,pool_size=poolsize, pool_reset_session=True, host='localhost',user='root',password=mySqlPassword())
#choose the database
conn = connectionpool.get_connection()
with conn.cursor() as cursor:
cursor.execute("USE website;")
conn.close
#session key
app =Flask(__name__)
app.secret_key= secret_key()
#homepage
#app.route("/")
def index():
return render_template("register.html")
#handling registering
#app.route("/signup",methods=["POST"])
def signup():
conn = connectionpool.get_connection()
with conn.cursor() as cursor:
nickname = request.form["nickname"]
username = request.form["username"]
password = request.form["password"]
sql = "SELECT username FROM member where username = %s"
user = (username,)
cursor.execute(sql, user)
result = cursor.fetchall()
if (not nickname or not username or not password):
return redirect("/error?message=empty")
if (result):
return redirect("/error?message=registered")
else:
hashed_password = bcrypt.generate_password_hash(password=password)
sql = "Insert into member (name, username, password ) values (%s, %s, %s)"
userInfo = (nickname, username, hashed_password)
cursor.execute(sql, userInfo)
conn.commit()
return redirect("/")
conn.close
There are many functions in my app. Once I add get_connection() and .close(), the next function can't get the database from pool.
err: mysql.connector.errors.ProgrammingError: 1046 (3D000): No database selected

Need to know where is the problem with bulk import and how to fix it

I'm building an app with Django and I need to import data using django-import-export.
I'm using the bulk import of this last package. I can import the data the first time, but when I try to import it the second time an error occurred. The expected behavior is to not import data and don't cause an error.
My view looks something like this(I simplified the code below since in the actual view I have four resources and four files to import)
def complete_import(request):
if request.method == 'POST':
offering_resource = OfferingResource()
issuer_resource = IssuerResource()
offering_dataset = Dataset()
issuer_dataset = Dataset()
offering = request.FILES['offering']
issuer = request.FILES['issuer']
offering_data = offering_dataset.load(offering.read().decode('utf-8'), format='csv', delimiter='\t', headers=True)
issuer_data = issuer_dataset.load(issuer.read().decode('utf-8'), format='csv', delimiter='\t', headers=True)
offering_data.append_col(get_quarter, header='quarter')
issuer_data.append_col(get_quarter, header='quarter')
offering_result = offering_resource.import_data(offering_data, dry_run=True, raise_errors=True)
issuer_result = issuer_resource.import_data(issuer_data, dry_run=True, raise_errors=True)
if not offering_result.has_errors() and issuer_result.has_errors():
offering_resource.import_data(offering_dataset, dry_run=False)
del offering_result
issuer_resource.import_data(issuer_dataset, dry_run=False)
del issuer_result
else:
print('an error occurred')
return render(request, 'index.html')
My resource looks like this:
class OfferingResource(ModelResource):
accession_number = Field(
attribute='company',
column_name='ACCESSIONNUMBER',
widget=ForeignKeyWidget(Company, 'accession_number'))
quarter = Field(attribute='quarter')
# other fields
class Meta:
model = Offering
use_bulk = True
skip_diff = True
batch_size = 1000
import_id_fields = ('accession_number', 'quarter')
def before_import_row(self, row, row_number=None, **kwargs):
total_offering_amount = row.get('TOTALOFFERINGAMOUNT')
try:
row['TOTALOFFERINGAMOUNT'] = int(total_offering_amount)
except ValueError:
row['TOTALOFFERINGAMOUNT'] = -1
Company.objects.get_or_create(accession_number=row.get('ACCESSIONNUMBER'))
class IssuerResource(ModelResource):
accession_number = Field(attribute='company',
column_name='ACCESSIONNUMBER',
widget=ForeignKeyWidget(Company, 'accession_number'))
quarter = Field(attribute='quarter')
issuer_seq_key = Field(attribute='issuer_seq_key', column_name='ISSUER_SEQ_KEY')
# other filds
class Meta:
model = Issuer
use_bulk = True
skip_diff = True
batch_size = 1000
import_id_fields = ('accession_number', 'issuer_seq_key', 'quarter')
When I comment the use_bulk in the Meta class I get the expected behavior.
Edit
The error that I get (I forgot to add it before)
bulk_update() cannot be used with primary key fields.
I want to know how can I fix this?
Presumably you are using a primary key field as one of the fields in your Resource list. You cannot use a primary key field with Django's bulk_update() (docs).
Can you remove the PK field from the list of fields? If not, is there some other unique field you can use to uniquely identify a record that should be updated.

REQUEST certain Elements in Django POST API from User

I want to Request a dictionary like
{
"username": "a",
"password": "b",
"year": "2019-20",
"start": 1,
"end": 2,
"reference_id": "two"
}
from a user so that a user can hit the API and get the desired result.
My view looks like
def post(self,request, *args, **kwargs):
# self.http_method_names.append("post")
user = request.POST.get("user")
pasd = request.POST.get("pasd")
year = request.POST.get("year")
start = request.POST.get("start")
end = request.POST.get("end")
reference_id = request.POST.get("reference_id")
#Passing the parameters to another function to get the result.
status = main_function(user=user,pasd=pasd,year=year,start=start,end=end,reference_id=reference_id)
return Response(status)
Now the problem when I'm posting something in Django like
I'm getting None in every field. Ideally, I should get the values passed in the Dictionary.
Can someone please help me here.
In django rest framework, you should use request.data instead of request.POST, as it requires parser to receive JSON data. More info can be found in drf docs.
Change your code to:
def post(self,request, *args, **kwargs):
# self.http_method_names.append("post")
user = request.data.get("username") # <-- this used incorrect key
pasd = request.data.get("password") # <-- this used incorrect key
year = request.data.get("year")
start = request.data.get("start")
end = request.data.get("end")
reference_id = request.data.get("reference_id")
#Passing the parameters to another function to get the result.
status = main_function(user=user,pasd=pasd,year=year,start=start,end=end,reference_id=reference_id)
return Response(status)
I Got The Answer. SO if You Want to take input from a user then You should write this in your views.py file.
But First you have to tell Django Which Fields input you want. So you have to create a serializer.py file in the Django APP.
from rest_framework import serializers
class userdetailSerializer(serializers.Serializer):
username = serializers.CharField(max_length=20)
password = serializers.CharField(max_length=20)
year = serializers.CharField(max_length=8)
start = serializers.IntegerField()
end = serializers.IntegerField()
reference_id = serializers.CharField(max_length=50)
I need all the Above values from the User that's why i have added all. If you want Only certain values you can delete it from your serializer file.
After this goto your Views.py file and get the response entered by user using below code.
Serializer will autovalidate the input and if the input is not correct it will give a dictionary of error(In else Statement)
def post(self,request, *args, **kwargs):
# self.http_method_names.append("post")
serializer = self.serializer_class(data=request.data)
if serializer.is_valid():
username = serializer.validated_data.get('username')
password = serializer.validated_data.get('password')
year = serializer.validated_data.get('year')
start = serializer.validated_data.get('start')
end = serializer.validated_data.get('end')
reference_id = serializer.validated_data.get('reference_id')
response_status = main_function(user=username, pasd=password,year=year,start=start,end=end,reference_id=reference_id)
return Response("The File Upload Response Will Come HEre",response_status)
# return Response({'name':username, 'pass':password,'year':year,'start':start,'end':end,'reference_id':reference_id})
else:
return Response(serializer.errors)
The POST API will LOOk Like this.
If you guys are facing an error here then Plese comment.
Upvote if it helps.

Error 1064 sql syntax error

I am trying to work on registration using WTF forms and I am facing a sql syntax error when I am trying to inject data through flask execution. But I can able to insert the data using normal sql query through mysql command line.
from wtforms import Form, BooleanField, StringField, PasswordField, validators
from MySQLdb import escape_string as thwart
class RegistrationForm(Form):
username = StringField('Username', [validators.Length(min=4, max=25)])
email = StringField('Email Address', [validators.Length(min=6, max=35)])
password = PasswordField('New Password', [validators.DataRequired(), validators.EqualTo('confirm', message='Passwords must match')])
confirm = PasswordField('Repeat Password')
accept_tos = BooleanField('I accept the TOS', [validators.DataRequired()])
# for registering the user
#app.route('/register/', methods = ['GET', 'POST'])
def register_page():
try:
form = RegistrationForm(request.form)
if request.method == 'POST' and form.validate():
username = form.username.data
email = form.email.data
password = sha256_crypt.encrypt(str(form.password.data))
c, conn = connection()
x = c.execute("SELECT * FROM users WHERE username = '(%s)'" %(thwart(username),))
#x = c.fetchone()
if int(x) > 0:
flash ("that username already taken, please take another")
return render_template("register.html", form =form)
else:
c.execute("INSERT INTO users (username, password, email, tracking) VALUES (%s, %s, %s, %s)" %(thwart(username), thwart(password), thwart(email), thwart('/home/')))
c.commit()
flash("Thanks for registering")
c.close()
conn.close()
gc.collect()
session['logged_in'] = True
session['username'] = username
return redirect(url_for('dashboard'))
return render_template("register.html", form = form)
except Exception as e:
return render_template("register.html", error = e, form = form)
The error can be found below
After entering the password and matching it with confirm and submitting it. I am getting an error. Can anyone please help me on this.
Your SQLite statements look wrong.
x = c.execute("SELECT * FROM users WHERE username = '(%s)'" %(thwart(username),))
The single quotes are already being handled as far as I know, but in any case you can just use a prepared statement:
x = c.execute("SELECT * FROM users WHERE username = ?", (thwart(username)))
The same is true regarding your INSERT statement:
c.execute("INSERT INTO users (username, password, email, tracking) VALUES (?, ?, ?, ?)" (thwart(username), thwart(password), thwart(email), thwart('/home/')))
c.
query = "SELECT * FROM users WHERE username = %s"
x = c.execute(query, (thwart(username),))
similarly
query2 = "INSERT INTO users (username, password, email, tracking) VALUES (%s, %s, %s, %s)"
c.execute(query2, (thwart(username), thwart(password), thwart(email), thwart('/home/'))
worked!

how to get the selected option from ChoiceField in Django Form?

i'm working on Forms in Django, i have a choice field which contain a list of continents and i need to work on the selected option
this is the Select request from my DB:
def Select_continent():
db = MySQLdb.connect("localhost", "root", "aqw", "PFE_Project")
cursor = db.cursor()
sql = "SELECT Continent FROM myform_servercomponents"
try:
cursor.execute(sql)
results = cursor.fetchall()
continents = []
i=0
for row in results:
continents[i]=row[0]
i+=1
except:
print "Error: unable to fetch data"
db.close()
return continents
and this is my form
def continents():
data = Select_continent()
i=0
continents=[]
for key,value in data:
continents.append(('i',value))
i +=1
return continents
class FilterForm(forms.Form):
Continent = forms.ChoiceField(choices=continents())
so the question is how can i use the selected option in my view
def affiche_all(request, currency):
if request.method == 'POST':
form = FilterForm(request.POST)
if form.is_valid() :
Continent = form.cleaned_data['Continent']
# here i need to send the selected choice to another view
# like this :
# continent == 'Europe'
#url = reverse('affiche_all', args=(), kwargs={'continent': continent})
#return HttpResponseRedirect(url)
any idea ???