Python class attribute 'is not defined' when referenced by another class attribute - python

Using the following, I am able to successfully create a parser and add my arguments to self._parser through the __init()__ method.
class Parser:
_parser_params = {
'description': 'Generate a version number from the version configuration file.',
'allow_abbrev': False
}
_parser = argparse.ArgumentParser(**_parser_params)
Now I wish to split the arguments into groups so I have updated my module, adding some classes to represent the argument groups (in reality there are several subclasses of the ArgumentGroup class), and updating the Parser class.
class ArgumentGroup:
_title = None
_description = None
def __init__(self, parser) -> ArgumentParser:
parser.add_argument_group(*self._get_args())
def _get_args(self) -> list:
return [self._title, self._description]
class ArgumentGroup_BranchType(ArgumentGroup):
_title = 'branch type arguments'
class Parser:
_parser_params = {
'description': 'Generate a version number from the version configuration file.',
'allow_abbrev': False
}
_parser = argparse.ArgumentParser(**_parser_params)
_argument_groups = [cls(_parser) for cls in ArgumentGroup.__subclasses__()]
However, I'm now seeing an error.
Traceback (most recent call last):
...
File "version2/args.py", line 62, in <listcomp>
_argument_groups = [cls(_parser) for cls in ArgumentGroup.__subclasses__()]
NameError: name '_parser' is not defined
What I don't understand is why _parser_params do exist when they are referred by another class attribute, but _parser seemingly does not exist in the same scenario? How can I refactor my code to add the parser groups as required?

This comes from the confluence of two quirks of Python:
class statements do not create a new local scope
List comprehensions do create a new local scope.
As a result, the name _parser is in a local scope whose closest enclosing scope is the global scope, so it cannot refer to the about-to-be class attribute.
A simple workaround would be to replace the list comprehension with a regular for loop.
_argument_groups = []
for cls in ArgumentGroup.__subclasses()__:
_argument_groups.append(cls(_parser))
(A better solution would probably be to stop using class attributes where instance attributes make more sense.)

Related

how to inherit __init__ attributes from parent class to __init__ in the child class?

I'm trying to inherit the attributes from parent class:
class Human:
def __init__(self,name,date_of_birth,gender,nationality):
self.name = name
self.date_of_birth = date_of_birth
self.gender = gender
self.nationality = nationality
To the child class Student:
class Student(Human):
def __init__(self,university,std_id,first_year_of_registration,study_program):
super(Student,self).__init__(name,date_of_birth,gender,nationality)
self.university = university
self.std_id = std_id
self.first_year_of_registration = first_year_of_registration
self.study_program = study_program
def select(c):
pass
def drop(c):
pass
def __str__(self):
return 'Student ID {self.std_id},and student name is {self.name} and his study program is {self.study_program}'.format(self=self)
So i can create an object using both (parent,student) attributes like So:
s = Student('mark','2000-1-1','M','country','school',2017159,2017,'SE')
then i can:
print(s)
and invoke __str__ function like so:
Student ID 2017159,and student name is mark and his study program is SE
but whenever i create the object it give me error:
Traceback (most recent call last):
Python Shell, prompt 7, line 1
builtins.TypeError: __init__() takes 5 positional arguments but 9 were
given
i'm new to python. So i searched the internet and tried to do like some of the inheritance examples, like so:
Human.__init__()
but nothing worked, also i checked many answers here but none of them solved my problem.
hope anyone can help and point out what is wrong here.
def __init__(self,university,std_id,first_year_of_registration,study_program)
but
Student('mark','2000-1-1','M','country','school',2017159,2017,'SE')
?
Well, you see, Python is not a mind-reader. You need to tell it what you want.
Right now Python wants all and only university,std_id,first_year_of_registration,study_program, nothing more, nothing less.
This means, you need to tell it to get other elements:
class Student(Human):
def __init__(self,name,date_of_birth,gender,nationality, university,std_id,first_year_of_registration,study_program):
...
or by saying "and get some other elements". But remember! Those other elements must be at the end of the constructor!
class Student(Human):
def __init__(self,university,std_id,first_year_of_registration,study_program, *args, **kwargs):
super(Student,self).__init__(*args, **kwargs)
...
It basically catches all positional arguments (args) and keyword arguments (kwargs) and passes them further.
As I said, it only takes argument from the end, so you need to do:
Student('school',2017159,2017,'SE', 'mark','2000-1-1','M','country')
The way interpreter sees it, it will take 1st argument and put it in university, then 2nd in std_id... up to study_program, and then put the rest in the list args.

BDD behave Python need to create a World map to hold values

I'm not too familiar with Python but I have setup a BDD framework using Python behave, I now want to create a World map class that holds data and is retrievable throughout all scenarios.
For instance I will have a world class where I can use:
World w
w.key.add('key', api.response)
In one scenario and in another I can then use:
World w
key = w.key.get('key').
Edit:
Or if there is a built in way of using context or similar in behave where the attributes are saved and retrievable throughout all scenarios that would be good.
Like lettuce where you can use world http://lettuce.it/tutorial/simple.html
I've tried this between scenarios but it doesn't seem to be picking it up
class World(dict):
def __setitem__(self, key, item):
self.__dict__[key] = item
print(item)
def __getitem__(self, key):
return self.__dict__[key]
Setting the item in one step in scenario A: w.setitem('key', response)
Getting the item in another step in scenario B: w.getitem('key',)
This shows me an error though:
Traceback (most recent call last):
File "C:\Program Files (x86)\Python\lib\site-packages\behave\model.py", line 1456, in run
match.run(runner.context)
File "C:\Program Files (x86)\Python\lib\site-packages\behave\model.py", line 1903, in run
self.func(context, *args, **kwargs)
File "steps\get_account.py", line 14, in step_impl
print(w.__getitem__('appToken'))
File "C:Project\steps\world.py", line 8, in __getitem__
return self.__dict__[key]
KeyError: 'key'
It appears that the World does not hold values here between steps that are run.
Edit:
I'm unsure how to use environment.py but can see it has a way of running code before the steps. How can I allow my call to a soap client within environment.py to be called and then pass this to a particular step?
Edit:
I have made the request in environment.py and hardcoded the values, how can I pass variables to environment.py and back?
It's called "context" in the python-behave jargon. The first argument of your step definition function is an instance of the behave.runner.Context class, in which you can store your world instance. Please see the appropriate part of the tutorial.
Have you tried the
simple approach, using global var, for instance:
def before_all(context):
global response
response = api.response
def before_scenario(context, scenario):
global response
w.key.add('key', response)
Guess feature can be accessed from context, for instance:
def before_feature(context, feature):
feature.response = api.response
def before_scenario(context, scenario):
w.key.add('key', context.feature.response)
You are looking for:
Class variable: A variable that is shared by all instances of a class.
Your code in Q uses Class Instance variable.
Read about: python_classes_objects
For instance:
class World(dict):
__class_var = {}
def __setitem__(self, key, item):
World.__class_var[key] = item
def __getitem__(self, key):
return World.__class_var[key]
# Scenario A
A = World()
A['key'] = 'test'
print('A[\'key\']=%s' % A['key'] )
del A
# Scenario B
B = World()
print('B[\'key\']=%s' % B['key'] )
Output:
A['key']=test
B['key']=test
Tested with Python:3.4.2
Come back and Flag your Question as answered if this is working for you or comment why not.
Defining global var in before_all hook did not work for me.
As mentioned by #stovfl
But defining global var within one of my steps worked out.
Instead, as Szabo Peter mentioned use the context.
context.your_variable_name = api.response
and just use
context.your_variable_name anywhere the value is to be used.
For this I actually used a config file [config.py] I then added the variables in there and retrieved them using getattr. See below:
WSDL_URL = 'wsdl'
USERNAME = 'name'
PASSWORD = 'PWD'
Then retrieved them like:
import config
getattr(config, 'USERNAME ', 'username not found')

Python: Static method inside private inner Enum class

I'm having trouble implementing an inner private enum class called: "LineCode" inside a class named Parser.
LineCode: Private Enum class that defines 6 types of general possible line of codes. I use Enum instantiation to send a Regex Pattern and compile it in the constructor, __init__, and then holds the Regex Matcher as a class variable.
Parser: Parses a programming language, irrelevant what language. Parser is using LineCode to identify the lines and proceed accordingly.
Problem: I can't access the enum members of __LineCode from a Static method.
I wish to have a Static method inside __LineCode, "matchLineCode(line)" that receives a string from the Parser, it then iterates over the Enum members in the following logic:
If Match is found: Return the enum
If no more enums left: Return None
It doesn't seem trivial, I can't access the enum members to do this.
Attempts: I tried iterating over the enums using:
__LineCode.__members__.values()
Parser.__lineCode.__members__.values()
Both failed since it can't find __lineCode.
Ideally: LineCode class must be private, and not be visible to any other class importing the Parser. Parser must use the static method that LineCode class provides to return the Enum. I am willing to accept any solution that solves this issue or one that mimics this behavior.
I omitted some of the irrelevant Parser methods to improve readability.
Code:
class Parser:
class __LineCode(Enum):
STATEMENT = ("^\s*(.*);\s*$")
CODE_BLOCK = ("^\s*(.*)\s*\{\s*$")
CODE_BLOCK_END = ("^\s*(.*)\s*\}\s*$")
COMMENT_LINE = ("^\s*//\s*(.*)$")
COMMENT_BLOCK = ("^\s*(?:/\*\*)\s*(.*)\s*$")
COMMENT_BLOCK_END = ("^\s*(.*)\s*(?:\*/)\s*$")
BLANK_LINE = ("^\s*$")
def __init__(self, pattern):
self.__matcher = re.compile(pattern)
#property
def matches(self, line):
return self.__matcher.match(line)
#property
def lastMatch(self):
try:
return self.__matcher.groups(1)
except:
return None
#staticmethod
def matchLineCode(line):
for lineType in **???**:
if lineType.matches(line):
return lineType
return None
def __init__(self, source=None):
self.__hasNext = False
self.__instream = None
if source:
self.__instream = open(source)
def advance(self):
self.__hasNext = False
while not self.__hasNext:
line = self.__instream.readline()
if line == "": # If EOF
self.__closeFile()
return
lineCode = self.__LineCode.matchLineCode(line)
if lineCode is self.__LineCode.STATEMENT:
pass
elif lineCode is self.__LineCode.CODE_BLOCK:
pass
elif lineCode is self.__LineCode.CODE_BLOCK_END:
pass
elif lineCode is self.__LineCode.COMMENT_LINE:
pass
elif lineCode is self.__LineCode.COMMENT_BLOCK:
pass
elif lineCode is self.__LineCode.COMMENT_BLOCK:
pass
elif lineCode is self.__LineCode.BLANK_LINE:
pass
else:
pass # TODO Invalid file.
I already implemented it in Java, I want to reconstruct the same thing in Python:
private enum LineCode {
STATEMENT("^(.*)" + Syntax.EOL + "\\s*$"), // statement line
CODE_BLOCK("^(.*)" + Syntax.CODE_BLOCK + "\\s*$"), // code block open line
CODE_BLOCK_END("^\\s*" + Syntax.CODE_BLOCK_END + "\\s*$"), // code block close line
COMMENT_LINE("^\\s*" + Syntax.COMMENT + "(.*+)$"), // comment line
BLANK_LINE("\\s*+$"); // blank line
private final static int CONTENT_GROUP = 1;
private Pattern pattern;
private Matcher matcher;
private LineCode(String regex) {
pattern = Pattern.compile(regex);
}
boolean matches(String line) {
matcher = pattern.matcher(line);
return matcher.matches();
}
String lastMatch() {
try {
return matcher.group(CONTENT_GROUP);
} catch (IndexOutOfBoundsException e) {
return matcher.group();
}
}
static LineCode matchLineCode(String line) throws UnparsableLineException {
for (LineCode lineType : LineCode.values())
if (lineType.matches(line)) return lineType;
throw new UnparsableLineException(line);
}
Thanks.
You could change the staticmethod to a classmethod, that way the first argument passed to matchLineCode would be the __lineCode class and you would be able to iterate over it
Edit
I've decided to add a more detailed explanation as to why the matchLineCode using the #staticmethod decorator was unable to see the __lineCode class. First I recommend you read some questions posted on SO that talk about the difference between static and class methods. The main difference is that the classmethod is aware of the Class where the method is defined, while the staticmethod is not. This does not mean that you are unable to see the __lineCode class from the staticmethod, it just means that you will have to do some more work to do so.
The way in which you organized your code, the class __lineCode is a class attribute of class Parser. In python, methods are always public, there are no private or protected class members as in Java. However, the double underscore at the beginning of a class attribute's name (or an instance's attribute's name) mean that the name will be mangled with the class name. This means that any function defined outside of the class Parser could access the __lineCode class as
Parser._Parser__lineCode
This means that using the #staticmethod decorator you could iterate over the __lineCode by doing
#staticmethod
def matchLineCode(line):
for lineType in Parser._Parser__lineCode:
if lineType.matches(line):
return lineType
return None
However, it is much more readable and, in my opinion, understandable to use the #classmethod decorator to allow the function to be aware of the __lineCode class.

python defining multiple classes with decorators

I have the base class:
class BaseGameHandler(BaseRequestHandler):
name = 'Base'
def get(self):
self.render(self.name + ".html")
Now, I need to define a few subclasses of this but the thing is, they have to have a decorator. Equivalent code would be:
#route('asteroid')
class AsteroidGameHandler(BaseGameHandler):
name = 'asteroid'
#route('blah')
class BlahGameHandler(BaseGameHandler):
name = 'blah'
and maybe a few more.
A little background here: This is a tornado web app and the #route decorator allows you to map /blah to BlahGameHandler. This code maps /blah to BlahGameHandler and /asteroid to AsteroidGameHandler.
So I thoughtI should use metaprogramming in python and define all these classes on the fly. I tried the following which doesn't work(and by doesn't work I mean the final web-app throws 404 on both /asteroid and /blah):
game_names = ['asteroid', 'blah']
games = list([game, type('%sGameHandler' % (game.title()), (BaseGameHandler,), {'name': game})] for game in game_names)
for i in xrange(len(games)):
games[i][1] = route(games[i][0])(games[i][1])
What am I missing? Aren't these two codes equivalent when run?
The library that you use only looks for global class objects in your module.
Set each class as a global; the globals() function gives you access to your module namespace as a dictionary:
for i in xrange(len(games)):
globals()[games[i][1].__name__] = route(games[i][0])(games[i][1])
The include() code does not look for your views in lists.
To be specific, include() uses the following loop to detect handlers:
for member in dir(module):
member = getattr(module, member)
if isinstance(member, type) and issubclass(member, web.RequestHandler) and hasattr(member, 'routes'):
# ...
elif isinstance(member, type) and issubclass(member, web.RequestHandler) and hasattr(member, 'route_path'):
# ...
elif isinstance(member, type) and issubclass(member, web.RequestHandler) and hasattr(member, 'rest_route_path'):
# ...
dir(module) only considers top-level objects.

Python - get static information

i have to get static information from one 'module' to another. I'm trying to write logger with information about code place from where we're logging.
For example, in some file:
LogObject.Log('Describe error', STATIC_INFORMATION)
Static information is class name, file name and function name.
I get it from this:
__file__
self.__class__.__name__
sys._getframe().f_code.co_name
But i don't want to write this variables during logging. Can i create some function and call it. For example:
LogObject.Log('Describe error', someFunction())
How can i use it for getting static information?
I don't think "static" is the world you're looking for. If I understand you correctly, you want to write a function that will return the filename, class name and method name of the caller.
Basically, you should use sys._getframe(1) to access the previous frame, and work from there.
Example:
def codeinfo():
import sys
f = sys._getframe(1)
filename = f.f_code.co_filename
classname = ''
if 'self' in f.f_locals:
classname = f.f_locals['self'].__class__.__name__
funcname = f.f_code.co_name
return "filename: %s\nclass: %s\nfunc: %s" % (filename, classname, funcname)
Then from a method somewhere you can write
logger.info("Some message \n %s" % codeinfo())
First, please use lower-case names for objects and methods. Only use UpperCase Names for Class definitions.
More importantly, you want a clever introspective function in every class, it appears.
class Loggable( object ):
def identification( self ):
return self.__class__.__module__, self.__class__.__name__, sys._getframe().f_code.co_name
class ARealClass( Loggable ):
def someFunction( self ):
logger.info( "Some Message from %r", self. identification() )
If all of your classes are subclasses of Loggable, you'll inherit this identification function in all classes.

Categories

Resources