Call python object - odoo 9 - python

In python console(jupyter) I use a python library in the form:
class SomeClass(object)
def __init__(self, arg1, arg2):
...
def fct1(self):
...
return something
And I get no problem creating an object with:
x = SomeClass(arg1,arg2)
I would like to use those methods in Odoo.
I tried the following:
class SomeClass(**models.Model**)
def **connect**(self, arg1, arg2):
...
def fct1(self):
...
return something
Replacing "object" with "model,Models" to have it as an odoo class + renaming init with a method name.
But
x = connect(arg1,arg2)
returns :
NameError: global name 'connect' is not defined
How would I use my python library in Odoo (new API)?
TIA
UPDATE:
I also tried calling
x= self.connect(arg1,arg2) or
x=SomeClass.connect(arg1,arg2)
but it return "None" when I "print x". I think an instance is not created

thank you to zbik for the answer:
myclass.py in folder myaddons
class MyClass:
def __init__(self, name):
self.name = name
def _test(self,a,b):
return a+b
in other Odoo class:
from openerp.addons.myaddons.myclass import MyClass
...
x = MyClass('Hello')
y = x._test(2,3)
...
print x.name
> Hello
print y
> 5

Related

How to get class name from class method?

Please check the simple code below:
def extract_class_from_func(func_var):
# should return class of the func_var
return ...
class A:
def m(self):
print(self, "m")
func_var = A.m
# This check should succeed
assert A == extract_class_from_func(func_var)
Please help me in implementing method extract_class_from_func
You can't. In Python 2, this reference was available at A.m.im_class. But, to quote from PEP 3155 - Qualified name for classes and functions:
This possibility is gone in Python 3.
There is no longer any such thing as an "unbound method" and the function A.m is no different from a regular function - it does not hold any reference to the class object. In fact, you can even delete the class and see the "method" still works:
>>> class Ameta(type):
... def __del__(self):
... print("goodbye A")
...
>>> class A(metaclass=Ameta):
... def m(self):
... print(self, "m")
...
>>> f = A.m
>>> import gc
>>> del A
>>> gc.collect()
goodbye A
6
>>> f("👻")
👻 m
However, the PEP did provide some limited support for what you wanted: if you look in A.m.__qualname__ you will find a string from which you may be able to introspect the class A.
The module can be found using func_var.__module__ and class name can be found using __qualname__. Then you just perform string import as below:
import importlib
def extract_class_from_func(func_var):
className = func_var.__qualname__.split('.')[0]
return getattr(importlib.import_module(func_var.__module__), className)
class Greet:
def __init__(self):
pass
def sayHi(self):
print("Hi!")
>>> Greet == extract_class_from_func(Greet.sayHi)
>>> True
You can do like this.
def extract_class_from_func(func_var):
return func_var.__qualname__.split('.')[0]

How to initialize a class member using a classmethod

I have a class, which holds some member x (say, some data that is needed by all instances, but independent of them):
class Foo(object):
x = 23
# some more code goes here
Now, the procedure of determining x became more complex plus I wanted to be able to "refresh" x at certain times, so I decided to write an extra function for it
class Foo(object):
#classmethod
def generate_x(cls):
cls.x = 23
# some more code goes here
However, this class definition lacks an initialization call of generate_x.
What I tried so far:
This does not work:
class Foo(object):
# generate_x() # NameError: name 'generate_x' is not defined
# Foo.generate_x() # NameError: name 'Foo' is not defined
#classmethod
def generate_x(cls):
cls.x = 23
This works but less clear, because code is used outside the class definition
class Foo(object):
#classmethod
def generate_x(cls):
cls.x = 23
# ...
Foo.generate_x()
Are there better alternatives to this? Is using #classmethod the best approach here? What I'm searching is a class-equivalent of __init__.
Considering code clarity, is there a better way than the latter to instantiate Foo.x automatically using a function?
One way to achieve this is by using a decorator:
def with_x(cls):
cls.generate_x()
return cls
#with_x
class Foo(object):
#classmethod
def generate_x(cls):
cls.x = 23
(That said, I personally would just call Foo.generate_x explicitly after the class declaration, and avoid all the magic altogether.)
Use a descriptor.
class Complicated:
def __init__(self, location, get_value):
self.location =location
self.get_value = staticmethod(get_value)
def __get__(self, obj, owner):
try:
a = getattr(owner, self.location)
except AttributeError:
a = self.get_value()
setattr(owner, self.location, a)
return a
class My class:
x = Complicated ('_x', get_x)

Make Python module classes able to be called from a separate class

I currently have a module, my_module, which contains classes.py:
from . import config
class Class1:
#staticmethod
def method_one(x)
return x + config.constant
#staticmethod
def method_two(y)
return x - config.constant
My problem is that I want to be able to have multiple instances of the module with different values for config.constant. Ideally, I'd have a new class called MyClass where the constant would be an instance variable, so that this would work:
instance1 = MyClass(5)
instance1.Class1.method_one(5) # 10
instance2 = MyClass(0)
instance2.Class1.method_one(5) # 5
Is there a way to do this without modifying the classes which are in my_module?
Make it a staticmethod.
class MyClass(object):
#staticmethod
def my_method(num):
return num + num
Then you can use it from another file by doing(assuming the file is my_module.py:
import my_module
my_module.MyClass.my_method(2)
>>>4
my_module.py
def __init__(self, constant):
self.constant = constant
def my_method(self, num):
return self.constant + num
some_other_file.py
import my_module
MyClass = type('MyClass', (), my_module.__dict__)
my_instance = MyClass(3)
my_instance.my_method(4)
>>> 7

How to add or change a Class (not an instance)?

I would like to set an attribute to an class object directly, without creating an instance, e.g. having an alternative name that can be accessed like the __ name __ attribute:
class Foo:
pass
> Foo.__name__
Foo
But this doesn't work:
some_file.py:
class Foo:
alternativ_name = __name__ + "_ending"
print(Foo.alternativ_name)
This prints:
__main___ending
If I try it in the interactive Console, it returns something else again:
>>> class Foo:
... alt_name = __name__ + "_ending"
...
>>> Foo.alt_name
'builtins_ending'
What I would like to achive is:
class Foo:
alt_name = __name__ + "_ending"
Foo.alt_name
should return:
'Foo_ending'
How do I do this?
The variables __name__ and Foo.__name__ actually point to two different things. Using __name__ within the Foo class still uses the global variable, and not Foo.__name__.
Within the class, it is not possible to explicitly reference the same class:
class Foo:
alt_name = Foo.__name__ + "_ending"
# raises NameError: name 'Foo' is not defined
If you want the property on objects, you can do it during runtime, e.g. in the __init__. If you really want the property on the class itself, you can do that using metaclasses:
class Foo:
class __metaclass__(type):
#property
def alt_name(cls):
return cls.__name__ + "_ending"
Foo.__name__ has not yet been created at the point you are trying to access it. Therefore, when you access __name__ it gets the module's __name__. There are several ways you can solve this. One is by using a metaclass, but this is pretty overkill for just adding an attribute to a class. The second is to use a decorator on the class, and the third is to make alt_name a non-data descriptor or maybe a property.
Using a decorator:
def add_alt_name(template):
def decorator(klass):
klass.alt_name = template.format(klass.__name__)
return klass
return decorator
#add_alt_name(template="{}_ending")
class Foo:
pass
print(Foo.alt_name)
Using a non-data descriptor:
class AlternativeName:
def __init__(self, template, name="alt_name"):
self.template = template
self.name = "_" + name
def __get__(self, instance, klass):
try:
return getattr(klass, self.name)
except AttributeError:
pass
alt_name = self.template.format(klass.__name__)
setattr(klass, self.name, alt_name)
return alt_name
class Foo:
alt_name = AlternativeName(template="{}_ending")
print(Foo.alt_name)
Much simpler just to use a decorator.

Get name of current class?

How do I get the name of the class I am currently in?
Example:
def get_input(class_name):
[do things]
return class_name_result
class foo():
input = get_input([class name goes here])
Due to the nature of the program I am interfacing with (vistrails), I cannot use __init__() to initialize input.
obj.__class__.__name__ will get you any objects name, so you can do this:
class Clazz():
def getName(self):
return self.__class__.__name__
Usage:
>>> c = Clazz()
>>> c.getName()
'Clazz'
Within the body of a class, the class name isn't defined yet, so it is not available. Can you not simply type the name of the class? Maybe you need to say more about the problem so we can find a solution for you.
I would create a metaclass to do this work for you. It's invoked at class creation time (conceptually at the very end of the class: block), and can manipulate the class being created. I haven't tested this:
class InputAssigningMetaclass(type):
def __new__(cls, name, bases, attrs):
cls.input = get_input(name)
return super(MyType, cls).__new__(cls, name, bases, newattrs)
class MyBaseFoo(object):
__metaclass__ = InputAssigningMetaclass
class foo(MyBaseFoo):
# etc, no need to create 'input'
class foo2(MyBaseFoo):
# etc, no need to create 'input'
PEP 3155 introduced __qualname__, which was implemented in Python 3.3.
For top-level functions and classes, the __qualname__ attribute is equal to the __name__ attribute. For nested classes, methods, and nested functions, the __qualname__ attribute contains a dotted path leading to the object from the module top-level.
It is accessible from within the very definition of a class or a function, so for instance:
class Foo:
print(__qualname__)
will effectively print Foo.
You'll get the fully qualified name (excluding the module's name), so you might want to split it on the . character.
However, there is no way to get an actual handle on the class being defined.
>>> class Foo:
... print('Foo' in globals())
...
False
You can access it by the class' private attributes:
cls_name = self.__class__.__name__
EDIT:
As said by Ned Batchelder, this wouldn't work in the class body, but it would in a method.
EDIT: Yes, you can; but you have to cheat: The currently running class name is present on the call stack, and the traceback module allows you to access the stack.
>>> import traceback
>>> def get_input(class_name):
... return class_name.encode('rot13')
...
>>> class foo(object):
... _name = traceback.extract_stack()[-1][2]
... input = get_input(_name)
...
>>>
>>> foo.input
'sbb'
However, I wouldn't do this; My original answer is still my own preference as a solution. Original answer:
probably the very simplest solution is to use a decorator, which is similar to Ned's answer involving metaclasses, but less powerful (decorators are capable of black magic, but metaclasses are capable of ancient, occult black magic)
>>> def get_input(class_name):
... return class_name.encode('rot13')
...
>>> def inputize(cls):
... cls.input = get_input(cls.__name__)
... return cls
...
>>> #inputize
... class foo(object):
... pass
...
>>> foo.input
'sbb'
>>>
#Yuval Adam answer using #property
class Foo():
#property
def name(self):
return self.__class__.__name__
f = Foo()
f.name # will give 'Foo'
I think, it should be like this:
class foo():
input = get_input(__qualname__)
import sys
def class_meta(frame):
class_context = '__module__' in frame.f_locals
assert class_context, 'Frame is not a class context'
module_name = frame.f_locals['__module__']
class_name = frame.f_code.co_name
return module_name, class_name
def print_class_path():
print('%s.%s' % class_meta(sys._getframe(1)))
class MyClass(object):
print_class_path()
I'm using python3.8 and below is example to get your current class name.
class MyObject():
#classmethod
def print_class_name(self):
print(self.__name__)
MyObject.print_class_name()
Or without #classmethod you can use
class ClassA():
def sayhello(self):
print(self.getName())
def getName(self):
return self.__class__.__name__
ClassA().sayhello()
Hope that helps others !!!

Categories

Resources