Understanding Python Bugs

platyping

Sleeping Dragon
Joined
Oct 22, 2010
Messages
4,626
Location
Emerald Dreams
For modders with basic python modding skills trying to figure out what went wrong with their python codes.

1) Activate python exceptions
Locate the CivilizationIV config ini file in My Documents/My Games/Beyond the Sword folder and set HidePythonExceptions = 0

2) Reading the python errors
error2_zpsd63476e9.jpg

Now when you encounter a python bug, you will get error messages like this. Read it bottom up. The last sentence tells you what is wrong with the code, in this case, undefined variable error. The next sentence tells you which line and file to locate the error.
You can pretty much ignore the rest, because the rest are usually errors due to the initial error.

P.S.
Error Messages only pop up for errors due to coding, such as the above, indentation error etc.
It will not pop up for logic errors, such as instead of "i + 5", it executes "i - 5", because the codes run fine.

3) Basic Errors

I) "XXX" is not defined
"XXX" would refer to a variable name, so step 1 is to locate the file and line where it is referenced. All variable names are case sensitive, so "Cow", "COW" and "cow" are 3 different variables.
Once you locate the error, read upwards and see if it is defined somewhere before in the same section, unless it is a global variable such as "gc" or defined in the ini section such as "self.xxx".

Code:
	def onUnitBuilt(self, argsList):
		'Unit Completed'
		city = argsList[0]
		unit = argsList[1]
		[COLOR="Red"]pUnit.setName("Cow")[/COLOR]
A simple one will be as above. "pUnit" is definitely not defined anywhere above the error line. In this case, "unit" should be used instead.

Code:
	def onBeginPlayerTurn(self, argsList):
		'Called at the beginning of a players turn'
		iGameTurn, iPlayer = argsList
		pPlayer = gc.getPlayer(iPlayer)
		if pPlayer.isHuman():
			iGold = 100
		pPlayer.changeGold([COLOR="red"]iGold[/COLOR])
A more problematic one is when the variable is defined, but only under certain conditions. In this case, iGold is defined only for human players.

Thus, the obvious solution for this error is to make sure the variable is defined somewhere above, for all conditions.

II) "XXX" object has no attribute "YYY"
Code:
pTeam.changeGold(100)
CyTeam object has no attribute "changeGold"
In this case, changeGold can only be used for CyPlayer, not CyTeam.
You can find most functions in the API.

A special case is when "Nonetype" object has no attribute "YYY"
Code:
pPlayer = gc.getPlayer(iPlayer)
pPlayer.changeGold(100)
If iPlayer is within the limits of 0 and max players, then pPlayer will be a valid CyPlayer object. If iPlayer is -1 or 1546346745, you will expect pPlayer to be None.

Code:
iTech = gc.getInfoTypeForString("TECH_HUNTING")
sType = gc.getTechInfo(iTech).getType()
Again, by right you can use getType for a Tech Info, but what if iTech is invalid?
This can easily happen with hard coded codes as above, where there may be a spelling error, "TECH_HUNTTING" or "TECH_HUNTING" has been removed from the game, but nobody bothers to remove the codes.

III) Integer Division or Modulo by Zero
Code:
x = cow / dog
y = cat % rat
Now simple mathematics will tell you, divide anything by 0 and you get an error. So the question is, are you sure under all circumstances "dog" and "rat" will never be 0?
Thus, see what "dog" refers to, maybe culture, gold or unit level whatever, or simply add a non zero check before executing it.
Code:
if dog != 0:
	x = cow / dog

IV) Indentation Error
Code:
if i > -1:
iGold = 100
This kind is obvious. Following a statement ending with a ":", such as if, else, for, while, def, the next statement has to be indented one additional level to the right generally.
Code:
if i > -1:
	iGold = 100
I prefer to use "TAB", while there are others who use "SPACE" etc

V) Syntax Error
Code:
if i > -1::
Syntax Error occurs when your fingers are itchy, and you added an extra ":", "," or ")" etc making the code problematic.

Code:
gc.getTeam(gc.getPlayer(CyGame().getActivePlayer()).getTeam()).setHasTech(gc.getInfoTypeForString("TECH_HUNTING"), gc.getTeam(gc.getPlayer(CyGame().getActivePlayer()).getTeam()).isHasTech(gc.getInfoTypeForString("TECH_HUNTING"), CyGame().getActivePlayer(), False, False)

This code works fine, but you are just making your life difficult, and it is prone to syntax error if you miss a "(" or ")" somewhere.
Thus, splitting it into smaller codes will make debugging easier.
Code:
iPlayer = CyGame().getActivePlayer()
iTeam = gc.getPlayer(iPlayer).getTeam()
pTeam = gc.getTeam(iTeam)
iTech = gc.getInfoTypeForString("TECH_HUNTING")
pTeam.setHasTech(iTech, pTeam.isHasTech(iTech), iPlayer, False, False)

VI) Type Object "XXX" has no attribute "YYY"
Code:
x = BonusTypes.BONUS_ALUMINUM
y = YieldTypes.YIELD_FOOD
z = UnitAITypes.NO_UNITAI
For certain Type Objects such as Yield and Commerce, you can use this method directly. For others like Bonus Types, it results in an error. For those that do not work, use gc.getInfoTypeForString("BONUS_ALUMINIUM")

VII) Mismatch Input Type
error0000_zpsf22f93ee.jpg

Code:
iGold = 10.5
pPlayer.changeGold(iGold)
This kind of error occurs when the input is of a wrong type.
changeGold is only meant to take in integers, but a float is given instead.

VIII) Import Error
For certain files like CvMainInterface, you notice there are some Import codes right at the top, such as "Import CvUtil".
These files are imported so that you can use the functions defined there. An import error means the file you are trying to import is invalid. Either a typo error, or you forgot to copy the file from a downloaded mod component.
 
Back
Top Bottom