65.9K
CodeProject is changing. Read more.
Home

Python for .NET developer

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.65/5 (14 votes)

Feb 6, 2018

CPOL

7 min read

viewsIcon

49542

downloadIcon

668

Python from the .NET developer point of view

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

  1. Get httpie to call Rest API from command prompt

pip install --upgrade httpie

  1. Get web server

pip install waitress

  1. 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") #Global level variable 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) # Create a JSON representation of the resource 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: # any code 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__": # Use Python's built-in WSGI reference implementation to run # a web server for the application. from wsgiref.simple_server import make_server # Run the web server on localhost:8080 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.

close