Adding DYNAMIC arguments to WindowCommand class - python

THE PROBLEM
In short, below works but only when hardcoded like this.
class GetWindowCommand(sublime_plugin.WindowCommand):
#NEED VARIABLE INSTEAD OF THE HARDCODED "qv" string
sublime.active_window().run_command("get_window",{"qualifier": "qv"})
def __init__(self,window):
self.window=window
def run(self,qualifier):
self.projectFolders(qualifier)
def projectFolders(self,qualifier):
print(qualifier)
My goal is that when plugin is loaded, it reads the project folders and looks for specific files depending on the folder. As such, I need to access an external variable AS WELL AS the the WindowCommandClass
When doing print(WindowCommandClass) I notice it populates all the methods with the self,window variables and everything works.
In theory I thought I could introduce variables as shown below
qualifier="qv"
print(WindowCommandClass.projectFolders(qualifier))
However, introducing arguments to any method on that class seems to destroy the self and window arguments from the WindowCommandClass. I've only been using python & sublime text api for a couple days, so I have no idea if I'm missing something small or attempting the impossible. Any ideas?

Your question does not make it clear what the problem is. But have a look at this example and the notes I've made in it, perhaps it will help.
class GetWindowCommand(sublime_plugin.WindowCommand):
# The following call should not be anywhere in your plugin at all
# unless for some reason you want to restart your plugin:
# sublime.active_window().run_command("get_window", {"qualifier": "qv"})
def run(self, qualifier=None):
""" Called by Sublime Text when the plugin is run. """
# self.window is set by Sublime - do NOT set it in a __init__() method.
# The 'qualifier' variable will hold whatever the 'qualifier' arg
# was when the plugin was launched, e.g. 'foo' in my example below,
# or None if the plugin was started without the 'qualifier' arg set.
project_data = self.window.project_data()
if not project_data:
return
project_folders = project_data.get("folders", [])
if not project_folders:
print("No project folders have been set.")
return
for folder in project_folders:
print(folder)
You could launch your plugin by assigning a key binding in your user keys file:
{ "keys": ["ctrl+f0"], "command": "get_window", "args": {"qualifier": "foo" } },

In case anyone is looking to pass values to a class in Sublime Text 3 plugin
Given a class that starts out
class GetWindow(sublime_plugin.WindowCommand)
def __init__(self,window):
self.window=window
def results(self)
return("just testing")
I was calling INCORRECTLY as
print(GetWindow().results())
What I had to do was supply the function with the class like this.
print(GetWindow(sublime_plugin.WindowCommand).results())
Now to get the variable as mentioned in original post I can do this
qualifier='qv'
results=SublimeID(sublime.window,qualifier).results()
Also modify class & methods to include the variable
def __init__(self,window,qualifier):
self.qualifier=qualifier
def results(self)
qualifer=self.qualifier
# You can now work with this external variable #

Related

Is there a way to make Python nested class instances within a class definition not break when I have to change a definitions location?

I'm using Python 3.10+.
I reviewed stackoverflow and couldn't find the exact problem discussed. If I missed it, can you send me the link?
PROBLEM
I have the following folder structure:
folderA
--scriptA.py
In scriptA, I define class X
class X:
def __init__():
self.prop1 = Y()
self.prop2 = somevalue
self.prop3 = somevalue
class Y:
def __init__():
self.creationdate = dt.datetime.now()
When I print vars(instanceX), it shows the structure:
instanceX = X()
print(vars(instanceX)
{
...
'prop1': <FolderA.ScriptA.Y object at 0x000asdff20323f0>,
...
}
I save this instance to a file.
Later, I rearranged my code so now the class definition of Y has moved to a FolderB.ScriptB.py.
Now when I open up the file containing the instance, the system returns an error essentially saying no module found.
I realized that it is because the instance of Y is tied to a specific location.
So what I did to fix it was recreate the old location of the definition so I can read the file, replace the value of the instance of Y property with the new definition, so now it is tied to the definition in the new location.
However, if down the road I have to rearrange my code again, it's going to break again.
I sense there is some best practice approach that I am breaking here.
How would I rewrite the code so that I don't have to worry about where I move my scripts or definitions around in the future so long as the definition exists somewhere in the codebase? Or is that even possible? Would I just have to avoid changing the location of class definitions in the future?

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)?

How to recursively print my directory structure with indentations? (no imported modules)

So I have created a directory structure from scratch. I am pretty new to python. This is my code
class File:
def __init__(self, name, contents = [], owner = "No owner currently defined"):
self.name = name
self.contents = contents
self.owner = owner
def CreateOwner(self, new_owner):
self.owner = new_owner
class Directory(File):
def __repr__(self):
return f"Directory({self.name}, {self.contents})"
class PlainFile(File):
def __init__(self, name, owner = "No owner currently defined"):
self.name = name
self.owner = owner
I have made this directory structure
root = Directory("root",
[PlainFile("boot.exe"),
Directory("home", [
Directory("Julius",
[PlainFile("dog.jpg"),
PlainFile("homework.txt")]),
Directory("Cameron", [PlainFile("Elephant.jpg")])])])
And I want to make a function that will recursively print the names of each directory with their subdirectories and files directly underneath them but indented to the right to show that they come from the certain directory. And so each time a new directory is opened from within a directory a new indent is made. I really don't know how to. I have tried for loops and while loops but can't get it to work, I don't even know how to make indentations for opening new directories. Please help :(
Welcome to the world of python and stackoverflow! Good news is that the solution to your problem is very straight-forward. First off, some quick but important comments on your working code:
contents: should probably only be an attribute of the Directory subclass. Also, mutable default arguments is bad practice.
CreateOwner: In python, the convention is to write snake_case instead of CamelCase for everything that isn't class names.
owner: The normal way of implementing a default unset field, even string ones, is usually None.
Here's one way to solve your problem: Have a recursive function with 2 parameters: directory and indentation level. After printing the current Directory, check what you are going to do with each contents element with isinstance(). A Directory requires a recursive call with incremented indent, while a PlainFile is simply printed out. Correctly solved, you will get something like this:
Turning the function into a Directory method is something I'll leave as an exercise to the reader.
Hint:
One way of doing this is to have 2 seperate methods with the one being used from the outside being a shortcut using the current instance to the main method with the main logic which isn't instance-bound. Bonus points if making the latter a classmethod.
Try now and see if it goes better. Comment here if you get stuck again. I have coded a solution which works, but trying yourself first is always better for understanding.
Hopefully you are comfortable with recursion. Just some sample code, so that you can build up. For eg I have not used your repr overload, you can do that easily.
(On a diff note, In your code , you are inheriting from File for directory/Plain file class , but are not calling parent constructor. Some clean up there, and you can simplify this code too)
def rec_print (file_obj:File,level):
try:
if file_obj.contents:
pass
except Exception as e:
return
for obj in file_obj.contents:
indents = "".join(["\t" for idx in range(level)])
print( f"{indents }{obj.name}")
rec_print(obj, level+1)

Refactor class method to property using Pycharm

I have the following class:
class Dogs(object):
def __init__(self):
self.names = []
self.breeds = set()
def number(self):
return len(self.names)
I want to change number to being a property. This means I also want to change all of it usages. Does PyCharm have this built into it's refactoring tools? It seems to be according to this issue.
At this point, I'm doing "find all usages" and then manually fixing each instance. If there isn't a specific refactoring tool for changing a method to a property, is there some way to use "find all usages" more effectively?
Yes, you can refactor a method to a property in PyCharm. Strangely, this does not correspond to any entry in the "Refactor" menu.
Just place the editor cursor on the name of the method and press Alt+⏎ shortcut to show the available Intentions.
Then, select "Convert method to property".
You can also trigger the global action search with Ctrl+Shift+A and select the intention from there.

Sublime Editor Plugin remember variable

I am writing a sublime editor 2 plugin, and would like it to remember a variable for the duration of the session. I do not want it to save the variable as a file (it is a password), but would like to be able to run a command repeatedly, and the variable to be accessible.
I want my plugin to work something like this...
import commands, subprocess
class MyCommand(sublime_plugin.TextCommand):
def run(self, edit, command = "ls"):
try:
thevariable
except NameError:
# should run the first time only
thevariable = "A VALUE"
else:
# should run subsequent times
print thevariable
One way to achieve this would be to make it a global variable. This will allow you to access that variable from any function. Here is a stack question to consider.
Another option would be to add it to the instance of the class. This is commonly done in the __init__() method of the class. This method is run as soon as the class object is instantiated. For more information on self and __init__() consult this stack discussion. Here is a basic example.
class MyCommand(sublime_plugin.TextCommand):
def __init__(self, view):
self.view = view # EDIT
self.thevariable = 'YOUR VALUE'
This will allow you to access this variable from a class object after it has been created. Something like this MyCommandObject.thevariable. These types of variables will last until the window in which the method was called from is closed.

Categories

Resources