2

The following python code will set a secret key if the user does not provide one

Code with NameError:

import secrets
import string
import os

class Config:
    secret = os.environ.get('SECRET')
    if not secret:
        alphabet = string.ascii_letters + string.digits + string.punctuation
        secret = ''.join(secrets.choice(alphabet) for _ in range(256))

However, if secret is not set, this will result in a NameError: name 'alphabet' is not defined. What confuses me most is that the following variations of Config work properly:

Config without join (no error):

class Config:
    secret = os.environ.get('SECRET')
    if not secret:
        alphabet = string.ascii_letters + string.digits + string.punctuation
        secret = alphabet * 10   # just repeat the alphabet 10 times as the password

Config with alphabet in main scope (no error)

alphabet = string.ascii_letters + string.digits + string.punctuation

class Config:
    secret = os.environ.get('SECRET')
    if not secret:
        secret = ''.join(secrets.choice(alphabet) for _ in range(256))

Troubleshooting I've tried

  1. Verify all indentation is correct (each block uses 4 spaces)
  2. Test on python 3.7, 3.8, and 3.9 (all show identical results)
  3. Test code in Python REPL to check for errors (identical results again)
  4. Test simpler variations (remove os, string, etc.)

Question

What is causing the NameError? Am I misunderstanding how the class scope behaves or is this a bug in python?

Joe
  • 497
  • 1
  • 3
  • 11
  • 2
    Essentially, the generator expression you use creates its own scope, it literally creates a function which gets called. Like any function in a class block, the function local scope does not have access to the class block scope. In a nutshell, class blocks are not enclosing scopes, but you are trying to rely on an enclosing scope in your generator expression – juanpa.arrivillaga Jan 14 '21 at 14:54

0 Answers0