Validasi Tipedata Pada Python

Tri Juhari
5 min readOct 24, 2021

--

Problem pada tipe data merupakan salah satu masalah terbesar yg biasa dihadapi saat kita melakukan pemrosesan data dengan python, misalnya saja

Bagaimana Memastikan bahwa setiap field atau kolom memilki tipe data tertentu. Misalnya saja kolom integer (int) tidak mengandung hal hal seperti, kutip, koma, spasi dan sebagainya.

Bagaimana memastikan bahwa tipe data yg digunakan sudah benar sebelum kita load ke dalam database.

Selain itu pada pembahasan kali ini juga kita akan mempelajari bagaimana melakukan parsing data berdasarkan tipe data yang di inginkan menggunakan python secara native. Kemudian kita akan mempelajari bagaimana membangun pola untuk parsing tipe data yang reusable. menggunakan pydantic.

Sebagai catatan : adanya perbedaan utama antara parsing dan validasi. Parsing mengacu pada konversi data ke tipe data tertentu, sedangkan validasi mengacu apakah input yang diberikan adalah tipe tertentu. Misalnya

>>> int("9231") # called parsing 
123
>>> isinstance("9231", int) # called validating\
False

Apa itu Validasi Data ?

Validasi data merupakan suatu proses yang membuat data kita sesuai dengan aturannya (rules), skema, atau batasan yang sebelumnya telah ditetapkan untuk masing masing atribut. Selain itu data validasi juga mencegah kesalahan kesalahan yang tidak terduga misalnya saja adanya input pengguna yang salah format. Misalkan ada problem case ketika kita sedang membangun sebuah API untuk kebutuhan credit scoring yang digunakan untuk evaluasi kelayakan kredit seseorang. Untuk membuat API ini dapat berfungsi kita harus mengirimkan sebuah request URL yang nantinya berisi data payloads.

Data data ini memuat terkait data data untuk kebutuhan credit scoring, ada yang bersifat wajib untuk diisi dan ada juga yang hanya optional. Misalkan individu ini harus memiliki NPWP yang mana fields ini wajib untuk diisi. Untuk mengidentifikasinya terdapat skema yang telah ditentukan contohnya harus berisi 13 digit angka, kemudian harus memberikan alamat lengkap dengan aturan skema harus memiliki nama jalan, nomor, dan kode pos . Kode pos harus terdiri dari 5 digit.

Problem case diatas hanya sebuah gambaran saja, maka dapat disimpulkan bahwa dengan adanya validasi data memastikan data yang dikirim ke API mengikuti aturan yang sudah ditentukan.

Pada pembahasan kali ini, kita akan menggunakan istilah “ memvalidasi” yang berarti bahwa data dapat di parsing menjadi tipe data yang diharapkan.

Kita asumsikan kita sedanga melakukan pemrosesan data data terkait marketing (pemasaran). metadanya terdiri atas user_id, nama, jumlah_pembayaran and user_status. Langkah kerja yang akan kita lakukan adalah :

  1. mengubah nama pengguna menjadi huruf kecil
  2. mengkonversikan jumlah_pembayaran kedalam bentuk decimal
  3. memastikan bahwa nilai pada user_status terdiri atas 3 tipe yaitu active , inactive dan suspended
  4. Mengkonversi baris data kedalam bentuk JSON
from  decimal  import Decimal

marketing_data = [
'uid,user_name,amount_spent,status',
'1,PeRSON1,100,ACTIVE',
'2,persOn2,100 USD,INACTIVE',
'3,persON3,100$,SUSPENDED',
'4,peRson4,10000.10,ACTIVE',
'5,PERson5,,ACTIVE',
'6,person6,20,ACTIVE',
]
output = []
for d in marketing_data[1:]:
uuid, user_name, amount_spent, status = d.split(',')
user_name = user_name.lower()
amount_spent = amount_spent.replace('$','').replace('USD','').strip()
op_amt = Decimal(amount_spent) if amount_spent else None
clean_status = ( status if status in {'ACTIVE','INACTIVE', 'SUSPENDED' } else None )
output.append({
'uid': uuid,
'user_name': user_name,
'amount_spent': amount_spent,
'status' : status

})

print(output)
[{'uid': '1', 'user_name': 'person1', 'amount_spent': '100', 'status': 'ACTIVE'},
{'uid': '2', 'user_name': 'person2', 'amount_spent': '100', 'status': 'INACTIVE'},
{'uid': '3', 'user_name': 'person3', 'amount_spent': '100', 'status': 'SUSPENDED'},
{'uid': '4', 'user_name': 'person4', 'amount_spent': '10000.10', 'status': 'ACTIVE'},
{'uid': '5', 'user_name': 'person5', 'amount_spent': '', 'status': 'ACTIVE'},
{'uid': '6', 'user_name': 'person6', 'amount_spent': '20', 'status': 'ACTIVE'}]

Kita bisa lihat bagaimana proses validasi dan parsing data ketika digabungkan dengan pemrosesan data ( miosalnya : fungsi lower()) karena ini akan melibatkan banyak penulisan logika try… except untuk menangkap adanya kesalahan pada proses parsing. Coba kita jalankan iterasi menggunakan perintah for.. menggunakan data di bawah ini.

marketing_data = [
'uid,user_name,amount_spent,status',
'1,person1,x,ACTIVE',
]

akan muncul warning error seperti di bawah ini :

Warning error decimal.InvalidOperation ,Sehingga harus menggunakan try..exceptblok atau logika kondisional untuk mengatasi masalah ini. Meskipun ini mungkin akan sulit untuk memvalidasi tipe data secara manual dan menangani semua problem tersebut.

Percobaan mengunakan Pydantic

Pydanticmerupakan library populer yang digunakan untuk melakukan parsing data kita ke dalam tipe data yang diharapkan. Kita dapat mendefinisikan tipe data menggunakan a dataclassdan let, selain itu Pydantic dapat melakukan handling pada proses parsing data. Mari kita coba bagaimana kita dapat menangani data marketing menggunakan library ini.

import json
import logging
from decimal import Decimal, InvalidOperation
from enum import Enum
from typing import Any, Optional

from pydantic import ValidationError
from pydantic.dataclasses import dataclass
from pydantic.json import pydantic_encoder
marketing_data = [
'uid,user_name,amount_spent,status',
'1,PeRSON1,100,ACTIVE',
'2,persOn2,100 USD,INACTIVE',
'3,persON3,100$,SUSPENDED',
'4,peRson4,10000.10,ACTIVE',
'5,PERson5,,ACTIVE',
'6,person6,x,ACTIVE',
'7,person7,200,',
]

# status can only be one of these 3
class StatusType(Enum):
ACTIVE = "ACTIVE"
INACTIVE = "INACTIVE"
SUSPENDED = "SUSPENDED"

class ExcelNumber:
@classmethod
def __get_validators__(cls):
yield cls.validate

@classmethod
def validate(cls,v:Any) -> Optional[Decimal]:
if v is not None and str(v) != '':
try:
return Decimal(
str(v)
.replace(',','')
.replace('$', '')
.replace('USD', '')
.strip()
)
except InvalidOperation as io :
logging.error(f"Error while parsing {str(v)} to decimal. Error : {io}")
raise ValidationError
return True

@dataclass
class MarketData:
uid: int
user_name: str
amount_spent: Optional[
ExcelNumber
] # optional means that this field can be None
status: StatusType

error_count = 0
output_data =[]
for idx,d in enumerate(marketing_data[1:]):
try:
market_data = MarketData(*d.split(','))
market_data.user_name = market_data.user_name.lower()
output_data.append(json.dumps(market_data, default=pydantic_encoder))
except ValidationError as ve:
logging.error((f"row_number :{idx+1}, row:{d}, error {ve}"))
error_count +=1

print(f'Error count : {error_count}')
print(output_data)

Output yang dihasilkan ternyata adanya log error di baris ke 6 dan ke 7,

kesalahan baris ke- 6 yaitu dikarenakan nilai ‘x’ bukan merupakan sebuah integer sehingga kita akan dilakukan parsing kedalam bentuk decimal yang ada malahan menghasilkan sebuah eror. Kemudian untuk baris ke -7 kesalahannya yaitu harusnya berisi nilai salah satu dari ketiga kategori ACTIVE ,INACTIVE , dan SUSPENDED.

Pydantic

Library pydantic memudahkan saat :

  1. Menentukan tipe data pada dataset yang kita gunakan
  2. Melakukan parsing data untuk mencocokkan tipe data yang ditentukan
  3. Mengidentifikasi kesalahan tipe data dengan a ValidationError
  4. Menentukan tipe data khusus
  5. Mengidentifikasi jenis kesalahan menggunakan mypy.

Untuk lebih lanjut bisa dibaca dokumentasi dari library ini pydantic

--

--

No responses yet