Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / Python

Python for .NET developer

4.65/5 (15 votes)
13 Feb 2018CPOL7 min read 49.5K   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.

Image 1

 

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

Image 2

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:

Image 3

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

Image 4

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.

Image 5

  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)

Image 6

Search and Install Falcon that we are going to use here

Image 7

 

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)

Image 8

  • Right-click in project and go to properties
  • Set main.py as startup file

Image 9Image 10

 

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

Python
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

Python
[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

Python
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

Python
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

Python
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

Python
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

Python
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

Python
resp.body = json.dumps(jsonRows, ensure_ascii=False)

also set response to 200 to make all happy

Python
resp.status = falcon.HTTP_200

m.        Exception handling

Just like C# Python also has more specific to more generic type of exception handling

Python
  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

Python
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

Python
from wsgiref.simple_server import make_server

srv = make_server('localhost', 8080, api)

srv.serve_forever()

Image 11

Check it out

Lest do some basic testing

A simple request to get all data

http://localhost:8080/secdata/all

Image 12

Get specific data

Image 13 

Test query string

http://localhost:8080/secdata/Test1?id=1

In server console

Image 14

 

Response

Image 15

 

<!--[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

Image 16

Name it and also have option to change Interpreter version

  Image 17

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.

Image 18

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

Image 19

Add requirements in it

Image 20

==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

Image 21

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.

Image 22

And write unit test to check db connection

test1.py

Python
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.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)