Standarized file importing, and keeping Leo updated

67 views
Skip to first unread message

Fidel N

unread,
Jul 6, 2014, 5:04:12 AM7/6/14
to leo-e...@googlegroups.com
Hi all:
Im having trouble to keep Leo updated because of this, and wanted to ask if someone can think of a way around.

I like Leo to import any file I drop to it as h = "@url File_or_last_folder_name" // b = "path_to_the_item"

Then my scripts will identify the kind of file it is, and offer me options on what to do with it. An imminent approach for this is to be able to import csv mind maps, and more. (The user drops the csv, my Leo dynamic menu will ask if he wants to import as mind map, and the user will have imported a file with 3 clicks, avoiding having to navigate in a file browser launched from Leo to find the file). 
I am finally making a self-contained well arranged set of classes (a plugin), and at last, it IS pythonic and will be shareable (at last).

Anyway, for the standardized file importing, I needed to edit the way Leo imports files, and make Leo import any file dropped to it as "@url"

For this, I replaced the following in LeoPyRef.leo:  (qtGui.py-->Frame and component classes...-->class LeoQTreeWidget (QTreeWidget)-->Event handlers (LeoQTreeWidget)-->dropEvent & helpers-->urlDrop & helpers)

self.doFileUrl

with:

self.doHttpUrl

Is there a way I could still import files that way, without having to touch LeoPyRef?
Having that file uncompatible with the main Leo repo keeps me away from making pull requests and such, since whenever I want to suggest something, that line gets in the way. And I cant update Leo quickly because then I have to edit that line again, etc.

Thanks!

Edward K. Ream

unread,
Jul 6, 2014, 8:04:19 AM7/6/14
to leo-editor
On Sun, Jul 6, 2014 at 4:04 AM, Fidel N <fidel...@gmail.com> wrote:
> Hi all:
> Im having trouble to keep Leo updated because of this, and wanted to ask if
> someone can think of a way around.
[big snip]
> Is there a way I could still import files that way, without having to touch
> LeoPyRef?

I think you are going to really like this answer: use a local copy of
LeoPyRef.leo, by convention called leoPy.leo:

http://leoeditor.com/FAQ.html#how-should-i-use-leo-with-bzr-git-hg-svn-cvs

The third bullet point is:

The repository contains reference .leo files. These reference files
should contain nothing but @file nodes. Reference files should change
only when new external files get added to the project. Leo’s git
repository and Leo distributions contain the following reference
files: LeoPyRef.leo, LeoPluginsRef.leo and leoGuiPluginsRef.leo.
Developers should use local copies of reference files for their own
work. For example, instead of using LeoPyRef.leo directly, I use a
copy called LeoPy.leo.

HTH.

Edward

Terry Brown

unread,
Jul 6, 2014, 3:31:47 PM7/6/14
to leo-e...@googlegroups.com
On Sun, 6 Jul 2014 02:04:11 -0700 (PDT)
Fidel N <fidel...@gmail.com> wrote:

> Is there a way I could still import files that way, without having to
> touch LeoPyRef?
> Having that file uncompatible with the main Leo repo keeps me away
> from making pull requests and such, since whenever I want to suggest
> something, that line gets in the way. And I cant update Leo quickly
> because then I have to edit that line again, etc.

In similar cases I've used a @script node in my local (personal,
i.e. not part of Leo) .leo files to alter Leo's behavior via monkey
patching.

Hmm, this example turned out less interesting than I thought:

class LeoInternalClass:
def seven(self, x):
print(7,x)

lic1 = LeoInternalClass()
lic2 = LeoInternalClass()

print("pre-patch")
lic1.seven('1')
lic2.seven('2')

def new_seven(self,x):
print("seven",x)

LeoInternalClass.seven = new_seven

print("\nPatch class and lic2 instance")
lic2.seven = lambda x, self=lic2: new_seven(self, x)

lic3 = LeoInternalClass()

lic1.seven('1')
lic2.seven('2')
lic3.seven('3')

def newer_seven(self,x):
print("3+4",x)

LeoInternalClass.seven = newer_seven

lic4 = LeoInternalClass()

print("\nPatch class again")
lic1.seven('1')
lic2.seven('2')
lic3.seven('3')
lic4.seven('4')

Basically, patch the class, all current and future instances affected
*unless* the instance has been patched. Patch the instance, and
patches to the class are irrelevant.

Cheers -Terry

Fidel N

unread,
Jul 6, 2014, 5:16:18 PM7/6/14
to leo-e...@googlegroups.com
Thank you both. Already tried both ways; And failed but already very close.

Edward, how is Leo supposed to know that my "leopyref.leo" file now will be leopy.leo? Where do I have to tell Leo to search for leopy instead of leopyref?


Terry, I like your solution very much, but my lack of python knowledge let me on the edge here.
It was already "fun" enough to reach the class and the function itself:

c.frame.tree.treeWidget.urlDrop

But when I replace that function with my (actually working in Leo) one, it throws this error:
I know I reached the one I wanted because in other windows, where I didnt replace it, it works as usual.

Thanks again!

Edward K. Ream

unread,
Jul 6, 2014, 9:10:58 PM7/6/14
to leo-editor
On Sun, Jul 6, 2014 at 4:16 PM, Fidel N <fidel...@gmail.com> wrote:
> Thank you both. Already tried both ways; And failed but already very close.
>
> Edward, how is Leo supposed to know that my "leopyref.leo" file now will be leopy.leo? Where do I have to tell Leo to search for leopy instead of
> leopyref?

I use batch files:

e.bat opens ekr.leo for my personal stuff,
s.bat opens Leo's sources: leoPy.leo, leoPlugins.leo, LeoDocs.leo (the
real file)
d.bat opens LeoDocs.leo
u.bat opens unitTest.leo (again, the real unitTest.leo)

And I have variants, e2, e3, s2, s3, u2, u3, d2, d3 that are to open
the files using Python 2 or 3.

I use exactly the same work flow on Linux using abbreviations rather
than .bat files.

Finally, I have a copy-files script that makes local copies of
leoPyRef.leo and leoPluginsRef.leo

Edward

P.S. Here are the scripts:

e.bat:

cls
gleo2 --no-cache "C:\Users\edreamleo\ekr.leo"

gleo2:

rem Opens Leo when double-clicked.
cls
python2 c:\leo.repo\trunk\launchLeo.py --gui=qttabs %*

s.bat:

cls
gleo2 leo\core\leoPy.leo leo\plugins\leoPlugins.leo leo\doc\LeoDocs.leo

HTH

EKR

Terry Brown

unread,
Jul 6, 2014, 11:21:39 PM7/6/14
to leo-e...@googlegroups.com
I'm guessing you left out my lambda: part. Maybe this is a better way
to do it:

import types
class LeoInternalClass:
def seven(self, x):
print(7,x)

lic1 = LeoInternalClass()
lic2 = LeoInternalClass()

print("pre-patch")
lic1.seven('1')
lic2.seven('2')

def new_seven(self,x):
print("seven",x)

# patch the class
LeoInternalClass.seven = new_seven

print("\nPatch class and lic2 instance")

# and patch the object (normally do only one)

# either lic2.seven = lambda x, self=lic2: new_seven(self, x)
# or, without futzing with arguments
lic2.seven = types.MethodType(new_seven, lic2)

lic3 = LeoInternalClass()

lic1.seven('1')
lic2.seven('2')
lic3.seven('3')

def newer_seven(self,x):
print("3+4",x)

LeoInternalClass.seven = newer_seven

lic4 = LeoInternalClass()

print("\nPatch class again")
lic1.seven('1')
lic2.seven('2')
lic3.seven('3')
lic4.seven('4')

types.MethodType() is much cleaner than that lambda thing.

Cheers -Terry

> Thanks again!
>

Fidel N

unread,
Jul 24, 2014, 5:31:34 AM7/24/14
to leo-e...@googlegroups.com
Thank you both again. Here is the code I ended up using, for future reference. I went for Terry's solution because its very clean, and I need to create nothing else but a @script node in each outline I want this working like that:

'''
How to replace a method in Leo (Make Leo behave differently without modifying leopyref.leo):

- Find the method. In my case, it was:
c.frame.tree.treeWidget.urlDrop
- Define your new function (urlDrop in the example code)
-  Run the example script whenever you want Leo to behave differently.
- [EXTRA] If you want this to happen everytime you run a Leo file, place the script under a node with a header "@script", and enable auto-running @script nodes in Leo config file.
'''


#Example script:

def urlDrop():
   
#Things you want Leo to do instead of what it does now
   
pass

#You need to import types, and also any modules your function needs. In my case, I had to import also QtCore:
import types
from PyQt4 import QtCore

#Replacement of your method:
c
.frame.tree.treeWidget.urlDrop = urlDrop
c
.frame.tree.treeWidget.urlDrop = types.MethodType(urlDrop, c.frame.tree.treeWidget.urlDrop)


Terry Brown

unread,
Jul 24, 2014, 9:32:04 AM7/24/14
to leo-e...@googlegroups.com
On Thu, 24 Jul 2014 02:31:34 -0700 (PDT)
Fidel N <fidel...@gmail.com> wrote:

> #Replacement of your method:
> c.frame.tree.treeWidget.urlDrop = urlDrop
> c.frame.tree.treeWidget.urlDrop = types.MethodType(urlDrop,
> c.frame.tree. treeWidget.urlDrop)

I think that should be just one assignment:

c.frame.tree.treeWidget.urlDrop = types.MethodType(
urlDrop, c.frame.tree.treeWidget)

Cheers -Terry

Fidel N

unread,
Jul 24, 2014, 9:35:48 AM7/24/14
to leo-e...@googlegroups.com
Hehe yes, thanks :)



--
You received this message because you are subscribed to the Google Groups "leo-editor" group.
To unsubscribe from this group and stop receiving emails from it, send an email to leo-editor+...@googlegroups.com.
To post to this group, send email to leo-e...@googlegroups.com.
Visit this group at http://groups.google.com/group/leo-editor.
For more options, visit https://groups.google.com/d/optout.

Reply all
Reply to author
Forward
0 new messages