Error on Python DB Connection PostgreSQL (Module) - python

Currently, I am learning about databases with Python.
I am trying to make postgresql database connection under the OOP paradigm.
I followed all the steps from this article, but I got an error when I run my code.
All the code is the same, I just modified the database.ini file with my DB setting.
** database.ini code:
[postgresql]
host = localhost
port = 5432
database = dvdrental
user = postgres
password = 1234
** config.py code:
# import libraries
from configparser import ConfigParser
import configparser
from pathlib import Path
def get_project_root() -> Path:
''' Return project root folder '''
return Path(__file__).parents[1]
def config(config_db):
section = 'postgresql'
config_file_path = 'config/' + config_db
if (len(config_file_path) > 0 and len(section) > 0):
# create an instance of ConfigParser class
config_parser = ConfigParser()
# read the configuration file
config_parser.read(config_file_path)
# if the configuration file contains the provided section name
if(config_parser.has_section(section=section)):
# read options of the sections
config_params = config_parser.items(section=section)
# convert the list object to a python dictionary object
# define an empty dict
db_conn_dict = {}
# loop in the list
for config_param in config_params:
# get options key and value
key = config_params[0]
value = config_params[1]
# add the key value pair in the dictionary object
db_conn_dict[key] = value
# get connection object use above dictionary object
return db_conn_dict
** db_conn.py code:
# import libraries
import pandas as pd
import psycopg2
from config.config import config
# take in a PostgreSQL table and outputs a pandas dataframe
def load_db_table(config_db, query):
params = config(config_db)
engine = psycopg2.connect(**params)
data = pd.read_sql(query, con = engine)
return data
** main.py code:
# import library
from src.data.db_conn import load_db_table
from config.config import get_project_root
# project root
PROJECT_ROOT = get_project_root()
# read database
df = load_db_table(config_db = 'database.ini', query = 'SELECT * FROM actor LIMIT 5')
print(df)
The problem is, when I run the program I got the error:
TypeError: connect() keywords must be strings
PS D:\ASUS\MY CODES PYTHON\Iochordxsyy\db_connection> python main.py
Traceback (most recent call last):
File "main.py", line 9, in <module>
df = load_db_table(config_db = 'database.ini', query = 'SELECT * FROM actor LIMIT 5')
File "D:\ASUS\MY CODES PYTHON\Iochordxsyy\db_connection\src\data\db_conn.py", line 9, in load_db_table
engine = psycopg2.connect(**params)
TypeError: connect() keywords must be strings
This is the message when I debugged my code:
Exception has occurred: TypeError
connect() argument after ** must be a mapping, not NoneType
File "D:\ASUS\MY CODES PYTHON\Iochordxsyy\db_connection\src\data\db_conn.py", line 9, in load_db_table
engine = psycopg2.connect(**params)
File "D:\ASUS\MY CODES PYTHON\Iochordxsyy\db_connection\main.py", line 9, in <module>
df = load_db_table(config_db = 'database.ini', query = 'SELECT * FROM actor LIMIT 5')
I have checked all the code is the same as the article but I have no ideas why the error still occurs. Do you have any ideas?
If you have any ideas/solutions, it will be much appreciated.
Thank you.
Credit:
Thank you for the authors of the articles mentioned above.

I think "username" keyword in database.ini must be "user".
** database.ini code:
[postgresql]
host = localhost
port = 5432
database = dvdrental
user = postgres
password = 1234

[Solved]
Hi all, I got the answer. There is a mistake script on the config.ini file.
I change the script from "config_params[]" to "config_param[]"
** the correct script:
...
key = config_param[0]
value = config_param[1]
...
Thank you for all the comments.

Align the indentation of this: config.py, as shown below.
if (len(config_file_path) > 0 and len(section) > 0):
# create an instance of ConfigParser class
config_parser = ConfigParser()
# read the configuration file
config_parser.read(config_file_path)
# if the configuration file contains the provided section name
if(config_parser.has_section(section=section)):
# read options of the sections
config_params = config_parser.items(section=section)
# convert the list object to a python dictionary object
# define an empty dict
db_conn_dict = {}
# loop in the list
for config_param in config_params:
# get options key and value
key = config_params[0]
value = config_params[1]
# add the key value pair in the dictionary object
db_conn_dict[key] = value
# get connection object use above dictionary object
return db_conn_dict

Related

python unittest : mock cursor.fetchall() to return a dummy value inside a function

#file utils.py
def update_configuration(configuration, mysql_client):
query = "SELECT * from some database"
cursor = mysql_client.execute_query(query)
function_mapping = cursor.fetchall()
cursor.close()
configuration["mapping"] = {}
for (display_name, formula_name) in function_mapping:
configuration["formula_mapping"][formula_name] = display_name
#main.py
def main_func(configuration):
mysql_client = get_mysql_connection()
ut.update_configuration(configuration, mysql_client) #ut means utils.py
#test.py
#mock.patch("src.utils.cursor.fetchall",return_value = [1,2,3,4])
#mock.patch("src.main.get_sql_connection", return_value = mock.Mock())
def test_initiate_calc(self, dummy1):
# perform integration testing on "main_func"
The project structure is as shown below
--project
--src
--tests
--test_main.py
--main.py
--utils.py
When I try to mock the cursor.fetchall() to return some value I get an error saying "ModuleNotFoundError: No module named 'src.utils.cursor'; 'src.utils' is not a package"
Need help in finding a way to get the function_mapping = cursor.fetchall() value some return value
You can't patch the local variable cursor, nor do you need to. Configure the get_mysql_connection mock properly instead.
#mock.patch("src.main.get_sql_connection")
def test_initiate_calc(self, mock_conn):
mock_conn.return_value.execute_query.return_value.fetchall.return_value = [1,2,3,4]
# perform integration testing on "main_func"
You can also try cursor.fetchall.side_effect = "some-value"
Something like this:
#patch('connector')
def test_create_table(self, connector):
connection = MagicMock()
cursor = MagicMock()
connector.connect.return_value = connection
connection.cursor.return_value = cursor
cursor.fetchall.side_effect = "List of tuple"
connector.connect.assert_called_with("creds")
cursor.execute.assert_called_with("statements - you - are - trying - to - execute")
For multiple statements use assert_has_calls.

How can I pass a Python parameter in config.py to .sql file?

I am using Python Snowflake connector to extract data from tables in Snowflake. Here is my file structure:
sql
a.sql
b.sql
c.sql
configurations.py
data_extract.py
main.py
Here the sql folder contains all my sql queries in .sql files. I put these sql files separately because they are handreds of lines long each and looks messy if I put them into python files.
configuration.py contains datetime parameters I want to change every time I run the code. It looks like this:
START_TIME = '2018-10-01 00:00:00'
END_TIME = '2019-04-01 00:00:00'
I want to add these parameters into the .sql files. For example, a.sql includes the following content:
DECLARE
#START_PICKUP_DATE DATE,
#END_PICKUP_DATE DATE,
SET
#START_PICKUP_DATE = '2018-10-01'
SET
#END_PICKUP_DATE = '2019-04-01'
select supplier_confirmation_id, pickup_datetime, dropoff_datetime, pickup_station_distance
from SANDBOX.ZQIAN.V_PDL
where pickup_datetime >= START_PICKUP_DATE and pickup_datetime < END_PICKUP_DATE
and supplier_confirmation_id is not null;
I use a.sql in my python code in the following way:
def executeSQLScriptsFromFile(filepath):
# snowflake credentials, replace SECRET with your own
ctx = snowflake.connector.connect(
user='S_ANALYTICS_USER',
account=SECRET_A,
region='us-east-1',
warehouse=SECRET_B,
database=SECRET_C,
role=SECRET_D,
password=SECRET_E)
fd = open(filepath, 'r')
query = fd.read()
fd.close()
cs = ctx.cursor()
try:
cur = cs.execute(query)
df = pd.DataFrame.from_records(iter(cur), columns=[x[0] for x in cur.description])
finally:
cs.close()
ctx.close()
return df
def extract_data():
a_sqlpath = os.path.join(os.getcwd(), 'sql\a.sql')
a_df = executeSQLScriptsFromFile(a_sqlpath)
return a_df
The problem is I want START_PICKUP_DATE and END_PICKUP_DATE in a.sql file to be synced and equal to START_TIME and END_TIME in configurations.py file so that I only need to change START_TIME and END_TIME in configurations.py and extract data in different timeframe using a.sql in Snowflake.
I've been looking for solutions online for quite a long time, but still not able to find a good solution that is specific to my problem. Many thanks to anyone who can provide a hint!
You should be able to parameterize the sql statements so that instead of declaring in the SQL file you can just make it a parameter passed during execution.
select supplier_confirmation_id, pickup_datetime, dropoff_datetime, pickup_station_distance
from SANDBOX.ZQIAN.V_PDL
where pickup_datetime >= %(START_PICKUP_DATE)s and pickup_datetime < %(END_PICKUP_DATE)s and supplier_confirmation_id is not null;
Then when calling the function, just send the parameters START_PICKUP_DATE and END_PICKUP_DATE as parameters to the execute statement. One way to do this is to do a mapping from the parameter name to the value of the parameter. (In this example I'm assuming you have a function that will get the parameter value).
cur = cs.execute(query, {'START_PICKUP_DATE':get_value_from_config('start_pickup'), 'END_PICKUP_DATE':get_value_from_config('end_pickup')})
Or you can pass them by location
cur = cs.execute(query, [get_value_from_config('start_pickup'), get_value_from_config('end_pickup')])
Which in essense becomes
cur = cs.execute(query, ['2018-10-01 00:00:00','2019-04-01 00:00:00'])
To accomplish this, I would take your .sql files and extract the queries into triple-quoted python strings with format specifiers for your variables. Then import the queries into your main script just like you import your configuration:
sql_queries.py:
sql_a = """
DECLARE
#START_PICKUP_DATE DATE,
#END_PICKUP_DATE DATE,
SET
#START_PICKUP_DATE = {START_TIME}
SET
#END_PICKUP_DATE = {END_TIME}
select supplier_confirmation_id, pickup_datetime, dropoff_datetime, pickup_station_distance
from SANDBOX.ZQIAN.V_PDL
where pickup_datetime >= START_PICKUP_DATE and pickup_datetime < END_PICKUP_DATE
and supplier_confirmation_id is not null;
"""
main:
from sql_queries import sql_a
print(sql_a.format(configuration.START_TIME, configuration.END_TIME))

python dbus how to get object value

import dbus
session_bus = dbus.SessionBus()
print(session_bus)
serviceName = "com.qcom.QCAT"
service = session_bus.get_object(
serviceName, # Bus name
"/Applications/QCAT/QCAT/bin/QCAT", # Object path
)
print(service)
appVersion = service.get_dbus_method('AppVersion')
print(appVersion)
I want to print appVersion at this code, but it actually print object _DeferreMethod object
How can I get the value of AppVersion.(arguemnts)
pic
You are getting information about the method in appVersion, rather than calling it and getting its return value. Try adding something like:
service_application = dbus.Interface(service, 'com.qcom.Application')
appVersion = service_application.AppVersion()
print(appVersion)

add an array of linked document _ids to couchdb documents in python

I want to add a links property to each couchdb document based on data in a csv file.
the value of the links property is to be an array of dicts containing the couchdb _id of the linked document and the linkType
When I run the script i get a links error (see error info below)
I am not sure how to create the dict key links if it doesn't exist and add the link data, or otherwise append to the links array if it does exist.
an example of a document with the links will look like this:
{
_id: p_3,
name: 'Smurfette'
links: [
{to_id: p_2, linkType: 'knows'},
{to_id: o_56, linkType: 'follows'}
]
}
python script for processing the csv file:
#!/usr/bin/python
# coding: utf-8
# Version 1
#
# csv fields: ID,fromType,fromID,toType,toID,LinkType,Directional
import csv, sys, couchdb
def csv2couchLinks(database, csvfile):
# CouchDB Database Connection etc
server = couchdb.Server()
#assumes that couchdb runs on http://localhost:5984
db = server[database]
#assumes that db is already created
# CSV file
data = csv.reader(open(csvfile, "rb")) # Read in the CSV file rb=read/binary
csv_links= csv.DictReader(open(csvfile, "rb"))
def makeLink(from_id, to_id, linkType):
# get doc from db
doc = db[from_id]
# construct link object
link = {'to_id':to_id, 'linkType':linkType}
# add link reference to array at key 'links'
if doc['links'] in doc:
doc['links'].append(link)
else:
doc['links'] = [link]
# update the record in the database
db[doc.id] = doc
# read each row in csv file
for row in csv_links:
# get entityTypes as lowercase and entityIDs
fromType = row['fromType'].lower()
fromID = row['fromID']
toType = row['toType'].lower()
toID = row['toID']
linkType = row['LinkType']
# concatenate 'entity type' and 'id' to make couch '_id'
fromIDcouch = fromType[0]+'_'+fromID #eg 'p_2' <= person 2
toIDcouch = toType[0]+'_'+toID
makeLink(fromIDcouch, toIDcouch, linkType)
makeLink(toIDcouch, fromIDcouch, linkType)
# Run csv2couchLinks() if this is not an imported module
if __name__ == '__main__':
DATABASE = sys.argv[1]
CSVFILE = sys.argv[2]
csv2couchLinks(DATABASE,CSVFILE)
error info:
$ python LINKS_csv2couchdb_v1.py "qmhonour" "./tablesAsCsv/links.csv"
Traceback (most recent call last):
File "LINKS_csv2couchdb_v1.py", line 65, in <module>
csv2couchLinks(DATABASE,CSVFILE)
File "LINKS_csv2couchdb_v1.py", line 57, in csv2couchLinks
makeLink(fromIDcouch, toIDcouch, linkType)
File "LINKS_csv2couchdb_v1.py", line 33, in makeLink
if doc['links'] in doc:
KeyError: 'links'
Another option is condensing the if block to this:
doc.setdefault('links', []).append(link)
The dictionary's setdefault method checks to see if links exists in the dictionary, and if it doesn't, it creates a key and makes the value an empty list (the default). It then appends link to that list. If links does exist, it just appends link to the list.
def makeLink(from_id, to_id, linkType):
# get doc from db
doc = db[from_id]
# construct link object
link = {'to_id':to_id, 'linkType':linkType}
# add link reference to array at key 'links'
doc.setdefault('links', []).append(link)
# update the record in the database
db[doc.id] = doc
Replace:
if doc['links'] in doc:
With:
if 'links' in doc:

How can I check the value of a DNS TXT record for a host?

I'm looking to verify domain ownership via a script, specifically a Python script, and would like know how to lookup the value of a DNS TXT entry. I know there are services and websites out there for this, but I would like to do it with a script.
This is easy using dnspython. Here is an example:
import dns.resolver
print dns.resolver.resolve("aaa.asdflkjsadf.notatallsuspicio.us","TXT").response.answer[0][-1].strings[0]
This gives the following output:
PnCcKpPiGlLfApDbDoEcBbPjIfBnLpFaAaObAaAaMhNgNbIfPbHkMiEfPpGgJfOcPnLdDjBeHkOjFjIbPbIoKhIjHfJlAhAhFgGbGgNlMgKmFkLgNfBjMbCoBeNbGeOnAeHgLmKoFlLhLmDcKlEdEbDpFeHkFaBlGnHiOnChIoMlIhBgOnFfKoEhDnFkKfDaMgHbJhMgPgMjGiAoJpKjKkPaIcAdGiMbIbBbAfEiKjNbCeFoElKgOePmGjJaImL
Another option is to use dig in subprocess:
import subprocess
print subprocess.Popen(["dig","-t","txt","aaa.asdflkjsadf.notatallsuspicio.us","+short"], stdout=subprocess.PIPE).communicate()[0]
This may be overly simplified, but if all you want is a quick read of the TXT record and don't mind dealing with parsing the result separately:
nslookup -q=txt somedomain.com
I found this did what I needed, short & sweet.
Found another way to get list of all TXT records for a domain using dnspython.
import dns.resolver
[dns_record.to_text() for dns_record in dns.resolver.resolve("your-domain-here", "TXT").rrset]
update 2022/11/20
# -*- coding:utf-8 -*-
# Copyright (c) DadouLab.SIG MIT
import dns
import dns.query
import dns.resolver
import logging
logger = logging.getLogger(__name__)
class Digger(object):
def __init__(self, resolvers=["1.1.1.1"]):
self.mResolver = dns.resolver.Resolver()
self.mResolver.timeout = 1
self.mResolver.lifetime = 0.5
self.mResolver.nameservers = resolvers
self.spec_query_type = ['CNAME', 'TXT', 'MX', 'NS', 'SRV', 'CAA']
def query(self, domain, query_type="A"):
"""
answer = dns.resolver.resolve("_dnsauth.test.com", "TXT").rrset
for dns_record in answer:
print(dns_record.to_text())
"""
try:
query_type = query_type.upper()
answer = self.mResolver.resolve(domain, query_type, raise_on_no_answer=False)
answer_raw = answer.chaining_result.answer.to_text()
logger.info("resolved response data => {}".format(answer_raw))
if query_type in self.spec_query_type:
records = [data.to_text() for data in answer]
else:
records = [data.address for data in answer]
return records
except (dns.resolver.NXDOMAIN, dns.resolver.NoAnswer,
dns.resolver.NoNameservers, dns.exception.Timeout) as error:
logger.warning("resolved error => {}".format(error))
return
def is_valid(self, domain, query_type="A"):
try:
self.mResolver.resolve(domain, query_type, raise_on_no_answer=False)
return True
except (dns.resolver.NXDOMAIN, dns.resolver.NoAnswer,
dns.resolver.NoNameservers, dns.exception.Timeout) as error:
logger.warning("resolved error => {}".format(error))
return
if __name__ == '__main__':
dig = Digger()
print(dig.query("www.example.com", query_type="A"))
Something like this should work to at least get the value for the URL, I used google.com for the example.
import pycurl
import StringIO
url = "whatsmyip.us/dns_txt.php?host=google.com"
c = pycurl.Curl()
c.setopt(pycurl.URL, url)
c.setopt(pycurl.HTTPHEADER, ["Accept:"])
txtcurl = StringIO.StringIO()
c.setopt(pycurl.WRITEFUNCTION, txtcurl.write)
c.perform
data = txtcurl.getvalue()
data = data.replace("Done!", "")
print data
I did not test any of this but pulled it from a previous project.
Best of luck!

Categories