Home > Enterprise >  'None' value given as an argument when instantiating from a csv file
'None' value given as an argument when instantiating from a csv file

Time:08-24

#weapon class
import csv

class weapon:

discount = 0.8 # 20% 

purchase_log = []

def __init__(self, name: str, weapontype : str, range : str, material : str, price : float, quantity=0):

    assert weapontype in ["bladed", "blunt", "polearm", "ranged"], f"{weapontype} is not a valid weapontype"
    assert range in ["close range", "medium range", "long range"], f"{range} is not a valid range"
    assert material in ["iron", "steel", "wood"], f"{material} is not a valid material type"
    
    self.name = name
    self.weapontype = weapontype
    self.range = range
    self.material = material
    self.price = price
    self.quantity = quantity
    
    weapon.purchase_log.append(self)

@classmethod
def instantiate_weapon_orders(cls):
    
    with open('weapons.csv', 'r') as f:
        
        item_reader = csv.DictReader(f) 
        items = list(item_reader) 
    
    for item in items:
        
        weapon(
            name=item.get('name'),
            weapontype=item.get('weapontype'),
            range=item.get('range'),
            material=item.get('material'),
            price=item.get('price'),
            quantity=item.get('quantity')
            )

def __repr__(self):
    
    return f"Weapon({self.name}, {self.weapontype}, {self.range}, {self.material}, 

{self.price}, {self.quantity})"
        
weapon.instantiate_weapon_orders()

print(weapon.purchase_log)

Here is the CSV file content:

name, weapontype, range, material, price, quantity
"Dagger", "bladed", "close range", "steel", 50, 4
"Mace", "blunt", "close range", "steel", 200, 5
"Longsword", "bladed", "medium range", "steel", 350, 3
"Halberd", "polearm", "long range", "steel", 500, 1
"Crossbow", "ranged", "long range", "wood", 500, 3

I receive this error whenever i try to run this code. I figured out that it was passing 'None' as an argument value when I commented out the assert statements

File "c:\PythonProjects\expa\random\gw.py", line 58, in <module>
    weapon.instantiate_weapon_orders()
  File "c:\PythonProjects\expa\random\gw.py", line 45, in instantiate_weapon_orders
    weapon(
  File "c:\PythonProjects\expa\random\gw.py", line 12, in __init__
    assert weapontype in ["bladed", "blunt", "polearm", "ranged"], f"{weapontype} is not a valid weapontype"
AssertionError: None is not a valid weapontype

I was looking at another file i made with the csv and the with... as... set up the exact same way. Ive looked online and i can't find anything.

CodePudding user response:

The Issue:

The issue seems to be the spaces in the csv file. Look at the output, notice the spaces in front of most of the fieldnames and in front of many of the values:

{'name': 'Dagger', ' weapontype': ' "bladed"', ' range': ' "close range"', ' material': ' "steel"', ' price': ' 50', ' quantity': ' 4'}

' "bladed"' doesn't equal "bladed". and ' "bladed"' isn't in "bladed", because it has a space.

Solution:

try removing the spaces from the weaponds.csv:

weapons.csv
name,weapontype,range,material,price,quantity
"Dagger","bladed","close range","steel",50,4
"Mace","blunt","close range","steel",200,5
"Longsword","bladed","medium range","steel",350,3
"Halberd","polearm","long range","steel",500,1
"Crossbow","ranged","long range","wood",500,3

I also made a couple minor adjustments to gw.py:

gw.py
#weapon class
import csv

class weapon:

    discount = 0.8 # 20% 

    purchase_log = []

    def __init__(self, name: str, weapontype: str, range: str, material: str, price: float, quantity=0):

        assert weapontype in ["bladed", "blunt", "polearm", "ranged"], f"{weapontype} is not a valid weapontype."
        assert range in ["close range", "medium range", "long range"], f"{range} is not a valid range"
        assert material in ["iron", "steel", "wood"], f"{material} is not a valid material type"
        
        self.name = name
        self.weapontype = weapontype
        self.range = range
        self.material = material
        self.price = price
        self.quantity = quantity
        
        weapon.purchase_log.append(self)

    @classmethod
    def instantiate_weapon_orders(cls):
        
        with open('./weapons.csv', 'r') as f:
            
            item_reader = csv.DictReader(f) 
            items = list(item_reader) 
        
        for item in items:
            
            cls(
                name=item['name'],
                weapontype=item['weapontype'],
                range=item['range'],
                material=item['material'],
                price=item['price'],
                quantity=item['quantity']
                )

    def __repr__(self):
        
        return f"Weapon({self.name}, {self.weapontype}, {self.range}, {self.material}, {self.price}, {self.quantity})"
        
weapon.instantiate_weapon_orders()

print(weapon.purchase_log)
Output:
[Weapon(Dagger, bladed, close range, steel, 50, 4), Weapon(Mace, blunt, close range, steel, 200, 5), Weapon(Longsword, bladed, medium range, steel, 350, 3), Weapon(Halberd, polearm, long range, steel, 500, 1), Weapon(Crossbow, ranged, long range, wood, 500, 3)]

CodePudding user response:

#weapon class
import csv

class Weapon:

    discount = 0.8 # 20% 

    purchase_log = []

    def __init__(self, name: str, weapontype : str, weapon_range : str, material : str, price : float, quantity=0):

        assert weapontype in ["bladed", "blunt", "polearm", "ranged"], f"{weapontype} is not a valid weapontype"
        assert weapon_range in ["close range", "medium range", "long range"], f"{weapon_range} is not a valid range"
        assert material in ["iron", "steel", "wood"], f"{material} is not a valid material type"
        
        self.name = name
        self.weapontype = weapontype
        self.weapon_range = weapon_range
        self.material = material
        self.price = price
        self.quantity = quantity
        
        Weapon.purchase_log.append(self)

    @classmethod
    def instantiate_weapon_orders(cls):
    
        items = list()  # instatiate list
        
        with open('weapons.csv', 'r') as f:
            
            item_reader = csv.DictReader(f) 
            
            # iterate over all item rows
            for row in item_reader:

                new_data = dict()
                # !!!!!!!!!!!! this is the issue that was causing problems indexing
                # get rid of unecessary characters that make indexing the data a pain
                for k, v in row.items():
                    new_key = k.lstrip().strip("\"")
                    new_value = v.lstrip().strip("\"")
                    new_data[new_key] = new_value
                items.append(new_data)  # add dictionary of row data to items
        
        # iterate over all items
        for item in items:
        
            weapon_name = item['name']
            weapon_type = item['weapontype']
            weapon_range = item['range']
            weapon_material = item['material']
            weapon_price = item["price"]
            weapon_quantity = item['quantity']

            Weapon(
                name=weapon_name,
                weapontype=weapon_type,
                weapon_range=weapon_range,
                material=weapon_material,
                price=weapon_price,
                quantity=weapon_quantity
            )

    def __repr__(self):
        
        return f"Weapon({self.name}, {self.weapontype}, {self.weapon_range}, {self.material}, {self.price}, {self.quantity})"
        
Weapon.instantiate_weapon_orders()

print(Weapon.purchase_log)

Here is the script I edited. note that your weapon class should be uppercase:

class weapon:  # bad

#--------------------

class Weapon:  # good :)

What was causing issues to index was that there are a bunch of extra characters, like spaces and quotes, that made indexing a lot harder. These are removed in the code above. Another solution says to simply remove the extra whitespace/quotation marks, however in real life practice this will not always be feasible with large datasets. I am also guessing that you need to filter this csv file without changing the original file; this code will handle those pesky extra characters that are causing your problems.

Lastly, you want to avoid using the keyword "range" as any variable name, as it is a protected keyword in python; this is why 'range' in your code was changed to 'weapon_range'

  • Related