Python UiPath - How to use Classes with UiPath.Python.Activities - python

Here is an image showing Python scope activity (version 3.6 and target x64):
Python Scope
The main problem is the relation between both invoke python methods, the first one is used to start the class object, and the second one to access a method of that class. Here is an image of the first invoke python properties:
Invoke Python init method
And the getNumberPlusOne activity call:
Invoke Python getNumberPlusOne method
The python code being executed:
class ExampleClass:
def __init__(self,t,n):
self.text = t
self.number = n
def getNumberPlusOne(self):
return (self.number+1)
And finally, the error when executing the second Invoke Python Method:
An ExceptionDetail, likely created by IncludeExceptionDetailInFaults=true, whose value is:
System.InvalidOperationException: Error invoking Python method ----> System.Runtime.Serialization.InvalidDataContractException: Type 'UiPath.Python.PythonObject' cannot be serialized. Consider marking it with the DataContractAttribute attribute, and marking all of its members you want serialized with the DataMemberAttribute attribute. If the type is a collection, consider marking it with the CollectionDataContractAttribute. See the Microsoft .NET Framework documentation for other supported types.
Any idea about where is the mistake and how to interact with the output object created in the init method?

I believe that this activity was designed with simple scripts in mind, not with entire classes. Here's an article on their Community Forum where user Sergiu.Wittenberger goes into more details.
Let's start with the Load Python Script activity:
In my case the local variable "pyScript" is a pointer to the python object, i.e. an instance of ExampleClass.
Now, there is the Invoke Python Method activity - this one allows us to call a method by name. It seems however that methods on the class are inaccessible to UiPath - you can't just type pyScript.MethodName().
So it seems that we can't access class methods (please proof me wrong here!), but there's a workaround as shown by Sergio. In your case, you would add another method outside your class in order to access or manipulate your object:
class ExampleClass:
def __init__(self,t,n):
self.text = t
self.number = n
def getNumberPlusOne(self):
return (self.number+1)
foo = ExampleClass("bar", 42)
def get_number_plus_one():
return foo.getNumberPlusOne()
Note that this also means that the object is instantiated within the very same file: foo. At this point this seems to be the only option to interact with an object -- again, I'd hope somebody can prove me wrong.
For the sake of completeness, here's the result:

I would like to add to what the above user said that you have to make sure that the imports you use are in the global site-packages, and not in a venv as Studio doesn't have access to that.
Moreoever, always add this:
import os
import sys
sys.path.append(os.path.dirname(os.path.realpath(__file__)))
to the beginning of your code. Again, a limitation of the implementation. (docs here: https://docs.uipath.com/activities/docs/load-script)
Doing this you might be able to do more complicated structures I think, but I haven't tested this out.

Related

Recognising method was called by instance

I am currently trying to make some decorators helping users of my software to create code which will inform them about some issues.
Doing classes, I sometimes work with methods which I would like to use only within the class, but not to be called in instance. I know this can be worked out with underscores and dunders, but I don't want to make user's experience a hell, just a little nudge with warning that they used it in scope which is not intended to have such method used.
Let me explain on code block:
class Example:
def __init__(self):
self.sth = 0
def callableMethod(self, is_true):
if is_true:
self.otherMethod()
print (self.sth)
#NoInstanceMethod
def otherMethod(self):
self.sth = 1
Basically what I would like to achieve is that user can create object and use both methods, but when they try to use otherMethod on instance, like that:
i = Example()
i.otherMethod()
I would be able to recognise it and do something to warn the user (through print or logging message, it doesn't matter).
Is there a way to recognise that the method is used on instance in such a way, but not raise the warning on callableMethod (as it is correctly used scope)?

In Python 2 do we need a self keyword for a function even if the function isn't part of a class?

So I'm looking through some old python 2 code and I see this function
def manage_addMapSamlPlugin(self, id, title='', delegate_path='', REQUEST=None):
""" Factory method to instantiate a MapSamlPlugin """
# Make sure we really are working in our container (the
# PluggableAuthService object)
self = self.this()
# Instantiate the adapter object
lmp = MapSamlPlugin(id, title=title, delegate_path=delegate_path )
self._setObject(id, lmp)
if REQUEST is not None:
REQUEST.RESPONSE.redirect('%s/manage_main' % self.absolute_url())
Now this function is outside of a class, the code compiles and doesn't give any errors. My understanding is that the self keyword in this case is just anything that gets passed in, but self.this() and self._setObject(id, lmp) that shouldn't be a thing right? Shouldn't the compiler throw an error? The code is run on a terminal in a ssh server I don't know what compiler it uses.
At the end of the file this is where the function gets called.
def initialize(context):
registerMultiPlugin(MapSamlPlugin.meta_type)
context.registerClass(
MapSamlPlugin,
constructors=(manage_addMapSamlPluginForm, manage_addMapSamlPlugin),
permission=ManageUsers,
icon=os.path.join(mgr_dir, "saml_icon.png"),
visibility=None,
)
And this is also a standalone function "context" isn't derived from any imports or class.
The comment is an important clue:
def manage_addMapSamlPlugin(self, id, title='', delegate_path='', REQUEST=None):
""" Factory method to instantiate a MapSamlPlugin """
# Make sure we really are working in our container (the
# PluggableAuthService object)
self = self.this()
self is expected to be an object which has a this() method -- it sounds like that method returns a PluggableAuthService object. If you grep the rest of the code for def this you'll probably find it. Looking for class PluggableAuthService might also shed some light.
If you call this function and pass it a self that doesn't implement the expected interface, you'll get an AttributeError at runtime. Since there are no type annotations here, there's not really a way to catch errors statically (at "compile time" -- although typically compiling Python doesn't in itself enforce any static type checks).
My suspicion is that this function was originally a method of that class, and got refactored out of it for some reason (maybe as the first step in some larger refactor that was never finished). A class method works just fine if you yank it out of a class, provided that you explicitly provide the self parameter when you call it.

Python: How to get all of the local variables defined in another module

Is there a way to get a reference to the local variables defined in a different module?
for example, I have two files: framework.py and user_code.py:
framework.py:
from kivy.app import App
class BASE_A:
pass
class MyApp(App):
def on_start(self):
'''Here I'd like to get a reference to sub-classes of BASE_A and
instantiated objects of these sub-classes, defined in the file
"user_code.py" such as a1, a2, as well as the class A itself,
without explicitly passing them to MyApp's instance.
'''
user_code.py:
from framework import MyApp
class A(BASE_A):
pass
app = MyApp()
a1 = A()
a2 = A()
app.run()
What I'd like to do is to somehow get a reference to the objects a1 and a2, as well as the class A, that were all defined in user_code.py. I'd like to use them in the method on_start, which is invoked in app.run().
Is it possible, for example, to get a reference to the scope in which the MyApp object was defined (user_code.py)?
Some background for anyone who's interested:
I know it's a bit of an odd question, but the reason is:
I'm writing a python framework for creating custom-made GUI control programs for self-made instruments, based on Arduino. It's called Instrumentino (sitting in GitHub) and I'm currently developing version 2.
For people to use the framework, they need to define a system description file (user_code.py in the example) where they declare what parts they're using in their system (python objects), as well as what type of actions the system should perform (python classes).
What I'm trying to achieve is to automatically identify these objects and classes in MyApp's on_start without asking the user to explicitly pass these objects and classes, in order to make the user code cleaner. Meaning to avoid code such as:
app.add_object(a1)
app.add_object(a2)
app.add_class(A)
New-style classes in Python have a method named __subclasses__ which returns a list of all direct subclasses that have been defined so far. You can use that to get a hold of the A class in your example, just call BASE_A.__subclasses__() (if you're using Python 2, you'll also need to change BASE_A to inherit from object). See this question and its answers for more details (especially the functions to recursively get all subclasses).
As for getting access to the instances, for that you probably should add some code to the base class, perhaps saving the instances created by __new__ into some kind of data structure (e.g. a weakset). See this question and its answers for more on that part. Actually, now that I think about it, if you put your instances into a centralized data structure somewhere (e.g. not in an attribute of each subclass), you might not need the function to search for the classes, since you can just inspect the type of the instances and find the subclasses that are being used.
Your question is a bit illogical.
Since Python interprets the code sequentially: b is not defined before a initialization.
If you can set b before a then:
b = None # global variable
class A():
global b
def __init__(self):
'''Here I'd like to get a reference to b (of type B) without passing it as an argument'''
class B_BASE():
pass
class B(B_BASE):
def __init__(self):
pass
if __name__ == '__main__':
b = B()
a = A()
I wouldn't recommend doing this because I find that this isn't clean. Since you have a dependency on b in a you should pass it as a parameter to the A class

Python/Django OOP modify the following code to show get/set and constructor

Case. I want to modify and add the following behavior to the code below (it's a context processor):
After checking if a user is authenticated check the last time the balance was updated (cookie maybe) if it was updated in the last 5 mins do nothing, else get the new balance as normal.
def get_balance(request):
if request.user.is_authenticated():
balance = Account.objects.get(user=request.user).balance
else:
balance = 0
return {'account_balance': balance}
HOWEVER:
I want to learn a little more about OOP in Django/Python can some modify the example to achieve my goal include the use of:
Property: I come from Java, I want to set and get, it makes more sense to me. get balance if does not exist else create new one.
Constructor method: In Python I think I have to change this to a class and use init right?
UPDATE:
To use a construct I first think I need to create a class, I'm assuming this is ok using as a context processor in Django to do something like this:
class BalanceProcessor(request):
_balance = Account.objects.get(user=request.user).balance
#property
def get_balance(self):
return return {'account_balance': _balance}
#setter???
Python is not Java. In Python you don't create classes for no reason. Classes are for when you have data you want to encapsulate with code. In this case, there is no such thing: you simply get some data and return it. A class would be of no benefit here whatsoever.
In any case, even if you do create a class, once again Python is not Java, and you don't create getters and setters on properties unless you actually need to do some processing when you get and set. If you just want to access an instance attribute, then you simply access it.
Finally, your proposed code will not work for two reasons. Firstly, you are trying to inherit from request. That makes no sense: you should inherit from object unless you are subclassing something. Secondly, how are you expecting your class to be instantiated? Context processors are usually functions, and that means Django is expecting a callable. If you give the class as the context processor, then calling it will instantiate it: but then there's nothing that will call the get_balance method. And your code will fail because Django will pass the request into the instantation (as it is expecting to do with a function) and your __init__ doesn't expect that parameter.
It's fine to experiment with classes in Python, but a context processor is not the place for it.

In Python, how can I determine which class a method was declared in?

How can I get a reference to the class a method was declared in? In the code below, I'm trying to get a reference to Classical in test.
class Classical:
def method():
pass
def test(func):
# How can I get a reference to 'Classical' using only 'func'?
pass
test(Classical.method)
I've tried dir()ing and searching, to no avail. Any ideas? (If it matters, I'm running Python 3.1)
EDIT: Changed the code to make more sense.
The function decorator test() is executed in the context of the class Classical while this class is being created. While executing the code in the class body, the class does not exist yet, so there is no means of accessing it. You should use a class decorator instead of a function decorator to work around this.
Alternatively, you can tell us what you are actually trying to achieve. Most probably, there will be a simple solution.
Edit: To answer your edited question: To access the class an unbound method belongs to, you can use unbound_method.im_class in CPython 2.x. I don't know if this is portable to other Python implementations, and most probably there is a better way of achieving whatever you are trying to achieve.

Categories

Resources