NameError when defining a class variable - python

Obviously I'm doing something stupid. But what?
I get:
File "<path>", line 71, in args
filename = filename
NameError: name 'filename' is not defined
...on the next-to-last line below ("filename = filename"):
def parseLog(filename, explain=False, omitminor=False, omitexpected=False,
omitgdocs=False, args=None):
print(filename)
if not args:
class args:
filename = filename
explain = explain
Yet the 2nd line above ("print(filename)") works fine. So, why the error?
In case you're wondering why I'm doing this in the first place, it's because the function parseLog() can also be called by the command line, like so:
def parseLogCLI():
''' parse command line for arguments '''
parser = argparse.ArgumentParser()
parser.add_argument('filename')
parser.add_argument('-explain', action="store_true", help='Explain what program has done')
parser.add_argument('-omitminor', action="store_true", help='Omit minor errors ' + repr(minor_errors))
parser.add_argument('-omitexpected', action="store_true", help='Omit machines expected to be often offline')
parser.add_argument('-omitgdocs', action="store_true", help='Omit errors on Google Docs native files (not copyable) ' + repr(gdocs))
args = parser.parse_args()
parseLog(arg.filename, args=args)
...so I'm trying to construct an 'arg' class (as argparse does) to pass to my function. If there's a better way to do this, I'm interested.

With class args: you are starting the definition of a class.
In that context, the first occurrence of filename defines a class attribute, which you are trying to assign from its own value before it is fully defined.
First of all, I think you should investigate in more details the concepts of classes, scopes, and instances.
This will help you understand why your function argument filename is hidden by the new definition inside the class scope.

It seems to me like you have a scope issue, in that the inner class 'arg' doesn't have access to the scope of the outer class. One solution would be to use the 'global' keyword like so:
def parseLog(filename, explain=False, omitminor=False, omitexpected=False,
omitgdocs=False, args=None):
global fname, expl
fname = filename
expl = explain
print(filename)
if not args:
class args:
filename = fname
explain = expl
You can read more about Python variable scopes here.

Related

Dynamically create class instance with complex Class input parameters in Python using reflection

I am trying to make design metadata driven data pipelines, so I define in external textual metadata (json, yaml) things like:
dataFunctionSequence = DataFunctionSequence(
functions=[
Function(
functionClass="Function1",
functionPackage="pipelines.experiments.meta_driven.function_1",
parameters=[
Parameter(name="param1", dataType="str", value="this is my function str value")
]
)
]
)
Now with help of importlib i can get class:
functionMainClass = getattr(
importlib.import_module(
functionMeta.functionPackage), functionMeta.functionClass)
But I want real instance, so I got it working with this piece of code which utilizes on top of importlib as well eval builtin function:
def create_instance(class_str:str):
"""
Create a class instance from a full path to a class constructor
:param class_str: module name plus '.' plus class name and optional parens with arguments for the class's
__init__() method. For example, "a.b.ClassB.ClassB('World')"
:return: an instance of the class specified.
"""
try:
if "(" in class_str:
full_class_name, args = class_name = class_str.rsplit('(', 1)
args = '(' + args
else:
full_class_name = class_str
args = ()
# Get the class object
module_path, _, class_name = full_class_name.rpartition('.')
mod = importlib.import_module(module_path)
klazz = getattr(mod, class_name)
# Alias the the class so its constructor can be called, see the following link.
# See https://www.programiz.com/python-programming/methods/built-in/eval
alias = class_name + "Alias"
instance = eval(alias + args, { alias: klazz})
return instance
except (ImportError, AttributeError) as e:
raise ImportError(class_str)
And I can construct a string that will construct the class and it works like charm.
Now my problem is that the class requires another parameter which is complex Spark DataFrame object which is not loaded from metadata but from some database or s3 bucket for example. Here I fail to be able to create dynamically instance with non-string variable.
I am failing here:
instance = eval(alias + args, { alias: klazz})
I tried to extend the create_instance() fnc with **kwargs, so I can dynamically search for parameter by name eg kwargs["dataFrame"], but how to assign it dynamically to init?
evel is not the right way probably or my expression is not correct?
NOTE: Another possible approach was to iterate somehoe over init object where I will get all params of constructor, but still I don't know what python reflection fuction to use to make a real instance.
Workaround: What I can do is that I can simply remove the dataFrame from class constructor, create instance only on simple params (eg. strings) and call method:
instance.setDataFrame(dataFrame)
And it will work. but I wanted some reflection base approach if possible.
Thank you very much.
Ladislav

How to solve class objecto has no atribute

beginner Python user here.
So, I´m trying to make a program that orders the files of my (many) Downloads folder.
I made a class object to work with the many folders:
class cContenedora:
def __int__(self, nCarp, dCarp): #nCarp Stands is the file name and dCarp Stands for file directory.
self.nCarp = nCarp
self.dCarp = dCarp
So, y wrote a instance like this:
Download = cContenedora()
Download.nCarp = "Downloads/"
#The side bar is for making a path to move my archives from with shutil.move(path, dest)
Download.dCarp = "/Users/MyName/Download/"
#This is for searching the folder with os.listdir(Something.dCarp)
Then, I wrote my function, and it goes something like this:
def ordenador(carpetaContenedora, formato, directorioFinal): #carpetaContenedora is a Download Folder
carpetaContenedora = cContenedora() #carpetaContenedora one of the class objects
dirCCont = os.listdir(carpetaContenedora.dCarp) #The to directory is carpetaContenedora.cCarp
for a in dirCCont:
if a.endswith(formato):
path = "/Users/Aurelio Induni/" + carpetaContenedora().nCarp + a
try:
shutil.move(path, directorioFinal)
print(Fore.GREEN + a + "fue movido exitosamente.")
except:
print(Fore.RED + "Error con el archivo" + a)
pass
for trys in range(len(listaCarpetasDestino)-1): #Is a list full of directories.
for container in listaCarpetasFuente: #A short list of all my Downloads Folder.
for formatx in listaFormatos: #listaFormatos is a list ful of format extensions like ".pdf"
#try: #I disabled this to see the error istead of "Error Total"
ordenador(container, formatx, listaCarpetasDestino[trys])
#except:
#print(Fore.RED + "Error Total") #I disabled this to see the error.
But every time I run it I get the following:
AttributeError: 'cContenedora' object has no attribute 'dCarp'
It says the error is in line 47 (the one with the os.listdir(carpetaContenedora.dCarp))
I´m sure is something small. Python is so amazing, but it also can be so frustrating not knowing what´s wrong.
There is a spelling mistake in the initialization of your instance. It should be "init" instead of "int".
In the class cContenedora, the function should be
class cContenedora:
def __init__(self, nCarp, dCarp):
self.nCarp = nCarp
self.dCarp = dCarp
Additionally, When you are passing in the parameter. Make sure to pass in both of the parameters in the line with Value.
CContenedora(nCarp="something",dCarp="something")
Your class initializer, i.e., __init__() function has 2 parameters nCarp and dCarp but when you are actually creating the object there are no parameters passed.
Your function ordenador takes the first parameter as carpetaContenedora, on the first line same variable is assigned a new object of cContenedora, at this line the original values you passed are lost forever.
This could be the reason it is giving for the error.
Refer this link for more details on how to create classes and instantiate the object.

python - Improve script and exception handling

I wrote my first python script which read a ini file using configparser.
First my ini file is define like:
;ini
[hypervisor1]
name = hyp1
how = ssh
vms = vm1 vm2 vm3
[hypervisor2]
name = hyp2
how = vpn
vms = vm4 vm5 vm6
Second my script:
import configparser
import os.path
import argparse
file_path = os.path.join(os.path.dirname(__file__),"config.ini")
parser = configparser.SafeConfigParser()
parser.read(file_path)
def get_args():
parser = argparse.ArgumentParser()
parser.add_argument("--vm", help="display info")
args = parser.parse_args()
vm = args.vm
return vm
vm = get_args()
def print_hyp(name_s):
for info in parser.sections():
for key, value, in parser.items(info):
for value in value.split(): # split whitespace vms value
if (value == name_s):
global info_s
info_s = info
print(name_s, "is deployed on", info)
if (print_hyp):
print_hyp(vm)
name = parser.get(info_s, 'name')
how = parser.get(info_s, 'how')
print("Name:", name)
print("How:", how)
So I need to get section which belongs to value: function print_hyp. And when I get it, I have to print other key with their value.
I'm sure my script is ugly, how can I improve it ?
And I have not errors management, for exemple the output with a vm that does not exist:
./script.py --vm stackoverflow
Traceback (most recent call last): File "script.py", line 43, in <module>
name = parser.get(info_s, 'name')
NameError: global name 'info_s' is not defined
Same thing without argument.
Could you help me?
Many thanks!
I would add
vm = get_args()
print('vm', vm) # to verify vm arg is what you want
This if doesn't make sense:
if (print_hyp):
print_hyp(vm)
...
Do you want something like if vm is not None:?
print_hyp(name_s) doesn't return anything. In prints something(s). It's use of global info_s is unwise. I use global so little that I don't even remember whether it has to also be initialized outside the function. I think your function should should return it, or a list of its values, rather than use global.
You should also be using the if __name__=='__main__:`. If you don't know what that is for, I'd suggest reviewing some basic script layout documentation.

Django ImageField upload_to custom path based on custom function

I am trying to set upload paths in Django ImageField with the upload_to attribute with similar to below.
Model
image = models.ImageField(upload_to=image_upload_location(image="logo"))
Function
def image_upload_location(filename, instance, *args, **kwargs):
if image:
defaultFolder = "images/default"
logoFolder = "images/logo"
generalFolder = "images/general"
productsFolder = "images/products"
if image == "logo":
folder = logoFolder
elif image == "general":
folder = generalFolder
elif image == "products":
folder = "productsFolder"
else:
folder = defaultFolder
return "%s/%s" % (folder, filename)
I get the following error:
TypeError: image_upload_location() missing 2 required positional arguments: 'filename' and 'instance'
I've tried to pass instance and filename but can't work out how to make this work. Any ideas on how to make this work so that I can use the same function for ImageField as I'm trying to follow the DRY principal by making a function to handle all the "set" locations.
I also don't want the date fields that Django adds.
[edit]
The main thing I need to know here is how to pass the required variable "instance and filename" plus an additional variable "image" to the function from the model ImageField. :-)
You have both filename and instance as parameters of your function, which you are not passing. I recommend doing this instead, if they aren't required.
def image_upload_location(*args, **kwargs):
filename=kwargs.pop('filename', 'DEFAULT')
instance=kwargs.pop('instance', 'DEFAULT')
or give them defaults
def image_upload_location(filename='DEFAULT', instance='DEFAULT', *args, **kwargs):
[edit]
Also, you never instance/grab/set "Image" in your function. Either set it as a parameter, or pop it from kwargs.
[edit on 2016-01-15] - This is what I think you want.
image = models.ImageField(upload_to=image_upload_location(image_type='logo', filename='filename.jpg'))
or
image = models.ImageField(upload_to=image_upload_location(filename='filename.jpg'))
or
image = models.ImageField(upload_to=image_upload_location('filename.jpg', 'logo'))
See below for all the different combination examples
def image_upload_location(filename, image_type='', *args, **kwargs):
if image_type=='logo':
folder = 'images/logo'
elif image_type=='general':
folder = 'images/general'
elif image_type=='products':
folder = 'images/products'
else:
folder = 'images/default'
return '%s/%s' % (folder, filename)
#All of the different ways to call it
print(image_upload_location('test.jpg')); #1 indexed argument, 1 default argument
print(image_upload_location('test2.jpg', 'logo')); #2 indexed arguments
print(image_upload_location('test3.jpg', image_type='logo')); #1 indexed argument, 1 named argument (indexed arguments can't come after named arguments)
print(image_upload_location(image_type='general', filename='test4.jpg')); #2 named arguments
print(image_upload_location(filename='test5.jpg', image_type='products')); #2 named arguments in a different order
Also, you don't need to include args and kwargs as parameters if you aren't using them.

python google closure compiler Source class question

This code is copy from http://code.google.com/p/closure-library/source/browse/trunk/closure/bin/build/source.py
The Source class's __str
__method referred self._path
Is it a special property for self?
Cuz, i couldn't find the place define this variable at Source Class
import re
_BASE_REGEX_STRING = '^\s*goog\.%s\(\s*[\'"](.+)[\'"]\s*\)'
_PROVIDE_REGEX = re.compile(_BASE_REGEX_STRING % 'provide')
_REQUIRES_REGEX = re.compile(_BASE_REGEX_STRING % 'require')
# This line identifies base.js and should match the line in that file.
_GOOG_BASE_LINE = (
'var goog = goog || {}; // Identifies this file as the Closure base.')
class Source(object):
"""Scans a JavaScript source for its provided and required namespaces."""
def __init__(self, source):
"""Initialize a source.
Args:
source: str, The JavaScript source.
"""
self.provides = set()
self.requires = set()
self._source = source
self._ScanSource()
def __str__(self):
return 'Source %s' % self._path #!!!!!! what is self_path !!!!
def GetSource(self):
"""Get the source as a string."""
return self._source
def _ScanSource(self):
"""Fill in provides and requires by scanning the source."""
# TODO: Strip source comments first, as these might be in a comment
# block. RegExes can be borrowed from other projects.
source = self.GetSource()
source_lines = source.splitlines()
for line in source_lines:
match = _PROVIDE_REGEX.match(line)
if match:
self.provides.add(match.group(1))
match = _REQUIRES_REGEX.match(line)
if match:
self.requires.add(match.group(1))
# Closure's base file implicitly provides 'goog'.
for line in source_lines:
if line == _GOOG_BASE_LINE:
if len(self.provides) or len(self.requires):
raise Exception(
'Base files should not provide or require namespaces.')
self.provides.add('goog')
def GetFileContents(path):
"""Get a file's contents as a string.
Args:
path: str, Path to file.
Returns:
str, Contents of file.
Raises:
IOError: An error occurred opening or reading the file.
"""
fileobj = open(path)
try:
return fileobj.read()
finally:
fileobj.close()
No, _path is just an attribute that may or me not be set on an object like any other attribute. The leading underscore simply means that the author felt it was an internal detail of the object and didn't want it regarded as part of the public interface.
In this particular case, unless something is setting the attribute from outside that source file, it looks like it's simply a mistake. It won't do any harm unless anyone ever tries to call str() on a Source object and probably nobody ever does.
BTW, you seem to be thinking there is something special about self. The name self isn't special in any way: it's a convention to use this name for the first parameter of a method, but it is just a name like any other that refers to the object being processed. So if you could access self._path without causing an error you could access it equally well through any other name for the object.

Categories