Ensuring objects passed into imported module have the same methods and attributes
I am writing a series of modules that:
- contain functions to automate common activities in Spaceclaim (V232)
- create some standard workflows
I would like to write the module functions as if they're in the main script, but will work turnkey when moved into a module (easier for debugging). I had two issues with writing simple function modules that meet my above goals:
When scripting in the main module, it has access to an extensive list of globals that imported modules do not have access to. This can be overcome with a function that creates module level globals from the main script (shown below). This feels like a messy solution, but seems to work.
When inspecting objects, I found they have different methods / attributes depending on whether they were in the main script or the module. I'm sure the way around this is to assign a type to the module level, but I was curious about a more global solution.
The example I've shown is for a straight line curve object from GetRootPart(). I'd like my modules to have access to the EvalMid() method without recreating the functionality or getting it from somewhere else. Another annoying difference between the main script and the module is the Get/Set and Name methods. Object.Name() works everywhere, but Object.GetName() works only in the main script.
I've made it pretty far by writing the modules differently from the main script and getting around these limitations, but I'd like to establish best practices before I'm too far down the line. Open to any suggestions / improvements.
Best Answer
-
Hi All! I met with a connection of a connection who was an OG developer for Spaceclaim.
Anyone encountering this issue can:
a) Trace all your dependencies in the module and import them individually (along with the C# .dll's) to make it all work (don't do this)
b) use the DocumentHelper.ImportScript("my_module.py"), which handles the problems of importing for you
0
Answers
-
Hi @temptemp4567 thanks for your question! I think there are 2 ways to answer your question. The first from a SpaceClaim point of view which unfortunately I can't help with, but @AKD-Scripting-Team might...
However the second is from a Python/Programming development point of view which I definitely can help with! In general, the best practice in Python development is to avoid using globals where possible and make sure to explicitly pass objects a function needs directly to it in its signature.
This attitude comes from the second line of "The Zen of Python" which is sort of like an official 'mindset' or 'attitude' to have when developing in Python. It is well worth a read if you've not seen it before.
Beautiful is better than ugly.
Explicit is better than implicit.
Simple is better than complex.
Complex is better than complicated.
Flat is better than nested.
Sparse is better than dense.
Readability counts.
Special cases aren't special enough to break the rules.
Although practicality beats purity.
Errors should never pass silently.
Unless explicitly silenced.
In the face of ambiguity, refuse the temptation to guess.
There should be one-- and preferably only one --obvious way to do it.
Although that way may not be obvious at first unless you're Dutch.
Now is better than never.
Although never is often better than right now.
If the implementation is hard to explain, it's a bad idea.
If the implementation is easy to explain, it may be a good idea.
Namespaces are one honking great idea -- let's do more of those!The second line here being "Explicit is better than implicit". The problem with global variables is that it is not explicitly clear where they came from, nor is it clear which global terms you're using as Python has a number of built-in statements, functions, and objects that are global by necessity, like
__file__
which always returns the path to the current file in use. So you can see why collecting all the global variables from one file and dumping them into another file might cause problems, even if you skip all the__
objects as you do in your code above. However, all is not lost and you can get around this issue, and any other potential issues, with the last line of the Zen 'Namespaces are great'.In other words, you could make a class (called
globals
probably) and put everything on that object and then pass that object between your modules. That would effectively put all the globals in one file into another, just in a new namespace such that it would be immediately clear to both the reader and the computer the difference betweenglobals.__file__
and__file__
.This is the best-practice way of doing what you're trying without re-writing the whole thing to avoid using globals at all from a pure software development PoV. I'd be interested to hear what SpaceClaim scripting people say!
0 -
Thank you for the awesome response @James Derrick , I haven't read that "Zen of Python" resource before and I appreciate you sharing.
I like your notes and completely agree, globals everywhere makes quite the mess and I try to avoid globals almost completely in the tools I build.
However the second is from a Python/Programming development point of view which I definitely can help with! In general, the best practice in Python development is to avoid using globals where possible and make sure to explicitly pass objects a function needs directly to it in its signature.
My first pass at the module builds have nothing of the above demo incorporated, I instead pass objects from main to module. The issue I highlight is that somewhere in the passing process, the Spaceclaim object loses attributes and methods, making the passing technique a little less useful. It's like passing a numpy array from main to module and all of the sudden the size, transpose and other methods can't be used in your module.
With this in mind, I still feel that I'm doing something wrong but I'll try to build workarounds unless there's something Spaceclaim specific that I can do (@AKD-Scripting-Team). Maybe re-casting a type to a variable and importing the Spaceclaim API appropriately in the module.
1