Introduction
We are going to explor Python from the .NET developer point of view. It's my experience that whenever we learn something new but similar we, always try to find things which we already know and check how same can be done here.
Using the code
Download PCC.DataAPI.zip
Download PCC.DataAPI-v1-withNoVE.zip
Installation and Setup
There are basically two ways to install and setup Python. As we all know Microsoft make lots of things easy for us so, let's take a look at first
a.The .NET Way
Microsoft's Flagship VS2017 comes with an inbuilt option for Python. Checked option to install same and update setup and pretty much it will do all things for you.
b.Rest of the world
Believe it or not but there are developer who doesn't use Visual Studio ;)
- Download latest stable version from https://www.python.org/downloads/ and install same
- After installation, open command prompt and type pip –version, this command should recognize and expect to see Python version installed
c.MySQL
Let's be fully open source, get MySQL also that we are going to use for Rest API
Get setup from here and install it
https://dev.mysql.com/downloads/windows/installer/
And create a table and insert some test data
CREATE TABLE `graphdata` (
`id` int(11) NOT NULL,
`descrption` varchar(45) DEFAULT NULL,
`value` decimal(10,0) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
Default server:
d.Some common packages
- Get httpie to call Rest API from command prompt
pip install --upgrade httpie
- Get web server
pip install waitress
- Connection to MySQL
pip install pymysql
Jump start a sanity check
- Create “Hellp.py” text file and write
- print("Hello Python! I am from .NET world")
- Open command prompt
- Go to file location
- Type file name- “Hellp.py and enter
Wow, it ran and I can see the result in the console, at this point it got my attention. I mean really just one line of code work with no import/ using/class or function.
Oky its just console, let's see what it can do with Rest API, let’s park this for now and continue with main topics
Project templets in Visual Studio
Visual Studio comes with some nice and popular inbuilt Python project templets. You can select anyone from this and start writing code, these comes with all package required.
I gave try to Django, just because catchy name but didn't like it much.
Install Python package in Visual Studio
If you like to install any package in Visual Studio, can also be done easily right in VS and it comes with IntelliSense (the first love of all bad spellers)
Search and Install Falcon that we are going to use here
My choice- The Falcon
I found (or at least felt) Falcon is easy and fast, you can get good reading here https://falconframework.org/
Now we are done with story building, it’s time to get into action
a. Solution structure
- Let's create a solution structure like this (add folder and file with same name)
- Right-click in project and go to properties
- Set main.py as startup file
b. Before you write code
- Python doesn't use { } for scope, instead, it uses TAB so careful with tabbing and intending.
- One py file cannot have both tab andmanual spacing
c. Class creation
Let's create a common class which uses to encode decimal for JSON, surprisingly Python’s JSON package can't handle decimal in json.dumps(..)
decimalEncoder.py
import falcon
import json
from decimal import Decimal as D
class DecimalEncoder(json.JSONEncoder):
def default(self, obj):
if isinstance(obj, D):
return float(obj)
return json.JSONEncoder.default(self, obj)
In this file:
- Import= using c#
- decimal import Decimal as D
- D = using alias in c#
- Decimal is class from decimal file/package
d. Configuration file
We have many choices of config files, We are using sweet simple ini file.
It's simple key-value pair file with different sections. [DEV] and [QA]
Config.ini
[DEV]
DBServer = localhost
User=root
Password=admin
Db=db1
[QA]
DBServer = localhost
User=root
Password=admin
Db=db1
We will be going to use it in secData.py
e. Module
Let's add code in secData.py which is the module with most of the code
secData.py
import json
import falcon
import pymysql
import configparser
from Utilities.decimalEncoder import DecimalEncoder
class SecData(object):
def __init__(self,comingFrom):
print("__init__, comingFrom:",comingFrom)
config = configparser.ConfigParser()
config.sections()
config.read("config.ini")
self.DBServer = config['DEV']['DBServer']
self.Db = config['DEV']['Db']
self.User = config['DEV']['User']
self.Password = config['DEV']['Password']
def getData(self,companyName):
try:
dbConnetion = pymysql.connect(host=self.DBServer,user=self.User,password=self.Password,db=self.Db)
cursor = dbConnetion.cursor()
sql = sql = "SELECT * FROM db1.table1"
if (companyName.lower() != "all"):
sql = "SELECT * FROM db1.table1 where descrption ='" + companyName + "'"
print("sql:",sql)
rowCount = cursor.execute(sql)
rows = cursor.fetchall()
jsonRows = []
for row in rows:
jsonRow = {
'id':row[0]
,'descrption':row[1]
,'value':DecimalEncoder().encode(row[2])}
jsonRows.append(jsonRow)
except OSError as err:
print("OS error: {0}".format(err))
except:
print("Unexpected error:", sys.exc_info()[0])
finally:
cursor.close()
return (jsonRows)
def on_get(self, req, resp,companyName):
print("companyName:",companyName)
print("req.query_string:",req.query_string)
jsonRows = self.getData(companyName)
resp.body = json.dumps(jsonRows, ensure_ascii=False)
resp.status = falcon.HTTP_200
Now will walk-thru code and explain some key things
f. Which code execute first
def __init__(self,comingFrom):
I added comingFrom, just to track who it instantiating this.
It reminds me page life-cycle of ASP.NET
g. Global variable
Anything using self.xyz
Just like ViewBag in ASP.NET MVC
h. Read confi file
self.DBServer = config['DEV']['DBServer']
Just like getting data from C# DataTable
i. Routing
def on_get(self, req, resp,companyName):
First three are standers parameters; fourth one is for getting value from routing
Will use it on main.py
j. Query string
def on_get(self, req, resp,companyName):
req has lots of information about request, for now req.query_string will get you query string
k. DB Connection
It's pretty state forward to connect DB
dbConnetion = pymysql.connect(host=self.DBServer,user=self.User,password=self.Password,db=self.Db)
is our connection object and cursor = dbConnetion.cursor() is data reader
l. JSON output
json.dumps(..) will create JSON from object and assign it to response object
resp.body = json.dumps(jsonRows, ensure_ascii=False)
also set response to 200 to make all happy
resp.status = falcon.HTTP_200
m. Exception handling
Just like C# Python also has more specific to more generic type of exception handling
try:
except OSError as err:
print("OS error: {0}".format(err))
except:
print("Unexpected error:", sys.exc_info()[0])
finally:
cursor.close()
n. Code execution entry point
As we already made main.py our startup, let's see whats inside it
main.py
import falcon
from SecDataModule.secData import SecData
api = application = falcon.API()
secData = SecData("main")
api.add_route('/secdata', secData)
api.add_route('/secdata/{companyName}', secData)
if __name__ == "__main__":
from wsgiref.simple_server import make_server
print("Starting web app server")
srv = make_server('localhost', 8080, api)
srv.serve_forever()
- .secData is way to import files in different folder
- '/secdata/{companyName}', secData) just like MVC routing. secData is the one which is going to handle request coming from this route.
o. Start own web server
Start wsgiref console base server
from wsgiref.simple_server import make_server
srv = make_server('localhost', 8080, api)
srv.serve_forever()
Check it out
Lest do some basic testing
A simple request to get all data
http://localhost:8080/secdata/all
Get specific data
Test query string
http://localhost:8080/secdata/Test1?id=1
In server console
Response
<!--[if !supportLists]--> <!--[endif]--><o:p>
Virtual Environments
As a wise man said, “Setting up and using virtual envt for python as its very standard practice” so let's touch base on adding new virtual environments.
As name imply virtual environments let us create environments where we can have set of different versions of packages, library other than installed in Global environments without causing any conflict.
a. Add Virtual Environment
Lucky VS got it cover too, just right click on Python Environments and select Add Virtual Environment
Name it and also have option to change Interpreter version
b. Quick fail test
At this point code is not going to run and should throw error for falcon ModuleNotFoundError. Remember we installed two packages Falcon and PyMySQL, now there are in separate environment. In order to get it working we need to get these two package added in our v.e.
c. Requirements.txt
It’s like packages.config of C# which contains all required package although I found it much simple and cleaner.
Add requirements.txt
Add requirements in it
==x.x is use to specify package version, if no version given it always install latest version.
Then right click on your v.e and select Install from requirements.txt
All set it’s ready to roll now.
You can also check where it’s dumping package files
Unit testing
It’s always good idea to unit test our code. We can add Python unit test file in our project and write C# like unit test and run it thru default Text Explorer.
And write unit test to check db connection
test1.py
import unittest
from SecDataModule.secData import SecData
class Test_test1(unittest.TestCase):
def test_A(self):
jsonRows = []
secData = SecData("FromUnitTest")
jsonRows = secData.getData("Test2")
self.assertIsNotNone(jsonRows)
if __name__ == '__main__':
unittest.main()
Run test
Download PCC.DataAPI.zip
TODO
So there are lots to do, but I am stopping here. Setup is done, a barer minimum code is up and running, the wheel is started rolling in the right direction. I believe any experience .NET developer can pull it forward.
Thanks for reading it thru, feel free to shoot any questions (I can handle .22LR but not ready for magnum round yetJ)
Points of Interest
Reference
Python official tutorial:
https://docs.python.org/3.7/tutorial/index.html
Falcon:
https://falconframework.org
VS 2017-Python
https://docs.microsoft.com/en-us/visualstudio/python/managing-python-environments-in-visual-studio
History
Keep a running update of any changes or improvements you've made here.