0

I have a function that is taking arguments from a web form (optional, with default values).

async def _overall(ctx,region="All",mode="All"):
  await ctx.send("Running Stats... Region:  "+region+", Mode: "+mode)

  if os.path.isdir(latest_run):                          
    if region=="All":
      r="all"
    if mode=="All":
      m="All-Modes"
    jsonfile = latest_run+"/en/"+r+"/Week."+m+".json"
    print(jsonfile)
  else:
    print("Directory not found.")

When I run this, I get:

UnboundLocalError: local variable 'r' referenced before assignment

I have attempted moving the if statements to the outside, but it gives me the same error:

async def _overall(ctx,region="All",mode="All"):
  await ctx.send("Running Stats... Region:  "+region+", Mode: "+mode)
  
  if region=="All":
    r="all"
  if mode=="All":
    m="All-Modes"
  if os.path.isdir(latest_run):                          
    jsonfile = latest_run+"/en/"+r+"/Week."+m+".json"
    print(jsonfile)
  else:
    print("Directory not found.")

Please advise.

Gino Mempin
  • 25,369
  • 29
  • 96
  • 135
p3hndrx
  • 103
  • 9

2 Answers2

1

You need to define the variables when the defaults aren't true.

You also shouldn't use string concatenation to generate filesystem paths

import os, pathlib

async def _overall(ctx,region="All",mode="All"):
  await ctx.send("Running Stats... Region:  "+region+", Mode: "+mode)

  r = "all" if region == "All" else region
  m = "All-Modes" if mode == "All" else mode

  if os.path.isdir(latest_run):                          
    jsonfile = pathlib.Path(latest_run) / "en" / r / "Week." / m / ".json"
    print(os.fspath(jsonfile))
  else:
    print("Directory not found.")
OneCricketeer
  • 179,855
  • 19
  • 132
  • 245
1

When your code gets to here:

jsonfile = latest_run+"/en/"+r+"/Week."+m+".json"

It is possible that r and/or m are still undefined, because they only get assigned a value if region is "All" and mode is "All". So, you reference them in that line of code before it gets assigned a value, hence the UnboundLocalError message.

The easy fix is to set a default value that does not depend on any inputs:

if os.path.isdir(latest_run):    
  r = "not-all"                      
  if region=="All":
    r="all"
    
  m = "not-all-modes"
  if mode=="All":
    m="All-Modes"

  jsonfile = latest_run+"/en/"+r+"/Week."+m+".json"

so that whatever happens they will always have a value when you reference them.

If you want it as one-line (arguably, to make it more "pythonic"):

if os.path.isdir(latest_run):    
  r = "all" if region == "All" else "not-all" 
  m = "All-Modes" if mode == "All" else "not-all-modes"                        

  jsonfile = latest_run+"/en/"+r+"/Week."+m+".json"

This kind of error is easy to understand when you use a debugger, which goes through your code line-by-line. It depends on your IDE, but I use VS Code's Debugger and I can see something like this:

screenshot of VS Code debugger 1

where I can see that by the time it gets to that code, both r and m are both undefined (it's not listed on the left-hand side under Local variables (hence the UnboundLocalError error).

This is opposed to when they are defined:

screenshot of VS Code debugger 2

As a final, unrelated note, look into other ways of formatting strings. Since the introduction of f-strings in Python 3.6, that is now the preferred way because it's more readable than concatenating with +:

jsonfile = f'latest_run/en/{r}/Week.{m}.json'
Gino Mempin
  • 25,369
  • 29
  • 96
  • 135