New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Python contrib
conventions
#4062
Comments
I agree with all of this, and you seem to be best positioned to propose a specific technical architecture. |
@frank-trampe I'm well-positioned in some respects but a) it does seem like being able to pull contributions from their own repos would be nice and b) I only have a vague understanding of the build infrastructure. I guess there are actually three options:
Option 3 has some attractive aspects. Any thoughts @jtanx? If we can work out a mechanism I'm happy to help guide |
The problem is, as always, #3663. Curvatura works by registering a bunch of menu items. That's fine, and a lot of scripts can work that way, but to come up with contrib conventions that don't solve this problem is a half solution. For example, you failed to mention at all @glukfonts' project, SVGinOTlayersCompositor. Maybe you don't know about it? It works via Tkinter! Tkinter, in 2019! The first commit was Oct 1. And you know what? If we write in our conventions that Tkinter is what is to be used, I will even be OK with that. Even though we had a well working GTK integration, I will be quiet about it. But this cannot continue to be ignored if we are to have sane guidelines. I salute the work @glukfonts did but we will break it at any time. We need to make a promise that GTK will work from Python, or that Tkinter will, and that that will not be broken, for me to bother writing scripts. |
My proposal, and therefore this issue, is about the bar for including contributed scripts in FontForge releases. The question of what should be possible to do with a script is an important one, but also a separate one. |
does a script that includes Tkinter pass that bar |
@ctrlcctrlv, the most basic answer to that question is: Not automatically by default. Some thought would have to go into it before it could. tkinter does have the advantage of not being X-specific. Beyond that I know very little about it on a practical level. (I played around with tcl/tk some ages ago in its heyday.) One requirement on any such script living in |
@ctrlcctrlv, it says that it is for Python 2.x. Does it work with Python 3? |
@skef Well we ought to have those thoughts because whether or not Tkinter is allowed is going to have a tremendous influence on what scripts get in, and if we let in one script with Tkinter that's an enduring promise that such will be allowed longterm. @frank-trampe It does not but I could just as easily write/find an example that uses Python 3. |
It would be fairly typical if the easy consensus cases wind up in a @ctrlcctrlv To the extent tkinter-like UI extensions are important you might want to focus on pushing for the plugin-type support discussed elsewhere. That way any worries about fragility are beyond the project members' scope. |
I'm not really making a big ask here. Either we promise not to break Tkinter, or we fix GTK. Either one closes #3663 as far as I'm concerned. We should only accept scripts for |
I second the motion to draw @jtanx into this discussion for perspective on GTK and the build system. |
Since someone is already using Tkinter, and since the Python developers are still bundling it by default, we should just promise not to break it. I can write #4066 with Tkinter as a demo. |
By the way @frank-trampe, here's a dead simple demo that works in Python 3 if you're curious: # Python 3 only
from tkinter import messagebox, Tk
window = Tk()
# On my system, lack of the following line causes a superfluous window to appear
window.wm_withdraw()
messagebox.showinfo("I matter", "Tkinter matters")
# Very important, otherwise window will never close
window.destroy() I really don't understand why @skef doesn't think that once we open the repository to outside Python scripts people aren't going to (rightfully) want to do stuff like this...we need to know if we're going to allow it, or if we're going to merge the GTK fix and force people to use GTK. |
@ctrlcctrlv I think two different issues may be getting confused here. There was discussion at one point of a script repository. If the FontForge project created a such a repository and then decided what could and could not go into it based on, for example, certain dependencies, that would raise the issues you've been discussing. That's not what the If the linked-to SVG font support script had no dependencies at all I doubt I would personally support adding it to The idea that the project would include a small number of key scripts in |
On the other issue: I'm happy to argue again for what I argued before: The ideal repository for (Python) FontForge extensions would be PyPI. The obstacle in the way of that solution is a discovery mechanism/convention. That's a solved problem for Python. We should probably use the namespace solution. If folks were to say to me "we think this is the top priority" I would probably do it. With a discovery mechanism we can add hooks that will be called on packages when FontForge starts up, so that they can (e.g.) register menu items. It would also be nice to have a place in 'Prefs' where you can turn a given discovered plugin off. None of this is very difficult to code up. There's one problem, however, that I would need @jtanx's help with. We need to be able to install real python-y files in addition to our C-API modules. (I'm not going to bother trying to code up a namespace package in C just because we don't have a way to install a python file. We write far too much Python in C as it is.) |
I'm not sure PyPI is ideal. On Windows for example the Python FontForge uses is the one we bundle, right? So are we going to start bundling |
That's already a problem for any "third party" script with python dependencies -- the storage and retrieval mechanism doesn't change that. Windows is likely a problem in that way unless and until we bind against the "native" one. (I believe switching to CMake was supposed to bring that closer to possible, but I don't know what further issues we face in compiling with Visual Studio.) (In case anyone has envisioned a repository that bundles all the dependencies, that would end up being a much bigger hornets nest in the end.) |
My idea which will work fine on Windows and for users not tech savvy enough to touch command lines:
This is similar to how the WeeChat project does things. |
Most obvious dependency for people looking to do more advanced spline stuff: |
I'll be stronger: Dependencies have their own dependencies. Code changes all the time in ways requiring updates. There are potential security problems. On systems where we're using the system python the dependencies we install will clash with the dependencies installed by the user It's a non-starter, not going to happen. |
Aren't we coming up with conventions in this thread? I think that a system that has no plans for being user-friendly or accessible to Windows users (or other platforms where we bundle the interpreter) is a "non-starter". I don't think it's a big deal to add a well-defined subdirectory to the Python module search path on select platforms. Just tell developers if they can put any Python module they want into a folder named e.g. |
Apologies, I haven't been following this very closely, and I still don't have too much time on my hands right now. Here's my 2c
It's also (if history is anything to go by), the place where code goes to die, because no one looks after it; the same too for pycontrib.
Out of the three options presented, I like this one the best.
I don't think so, I think that's conflating this issue. As to the whole Tk vs. GTK (vs Qt?) argument, I don't see that as being a problem; correct me if I'm wrong but given the existing limitations on how the GUI can be influenced through scripting, it's unlikely that whatever will be done in the future will cause any pre-existing functionality that uses some other toolkit to break. If it's looking like it will, well there's nothing preventing re-evaluating at that stage.
At a guess I'd think this would be a breaking change. I've thought about this before; basically we'd need to install a package like:
But I don't know how we'd do that and retain backwards compatibility.
We bundle a whole Python distribution, same as the mac bundle. It already has pip installed, iirc, although it's not that usable because we ship the msys2/mingw-w64 Python, which means there aren't binary wheels for things like numpy/pandas. Finally some further thoughts:
|
I think there would be. I already mentioned the SVGinOTlayersCompositor thing...as the manager of the @fontforge Twitter account I see a lot of what people in the community are doing and there are a lot of scripts floating out there, people are disappointed there's no way to contribute them. We'd probably have around 10 scripts by mid-year 2020, I'll be contributing some of those of course.
Well so long as we commit to not breaking Tkinter, which works right now, in the formal write up of the conventions, I'd be happy to support them. @skef also wrote:
If we had this combined with a |
How much of a problem for end-user builds is that likely to cause? Would we need a step like the old build tools download or can CMake just deal with that itself? (Otherwise this is my preference as well.)
Well, wait, @jtanx there are two "levels" to this. For now I'm just talking about shipping a python file under the fontforge namespace. (Or, if absolutely necessary, a different namespace. We just want to be sure that if fontforge is installed with python the discovery plumbing is there too.) I thought it was possible to ship If we're talking about the second level we'd start by changing our classes to "fontforge_int" (or whatever) and then have the python files import and inherit from the renamed C-API modules. That might break some really subtle stuff, but with a little care almost everything should be fine. (Famous last words.) (I'd be curious to play around with that a bit if and when we get a chance. Just make "empty" python files that inherit, change the names around, and see if things work and if not what breaks. Some of the internal plumbing might need to change a bit but I'm guessing it would be doable.) |
I initiated this discussion because I think the already discussed Curvatura tool is close to meeting a bar for shipping with FontForge and therefore it would be good to have a model for that. But I agree the generality bar for Subjectively I think the best indication is whether the tool seems like something that we would contemplate building into FontForge itself. Anyway, if our "custom" python implementations have
Not a huge project. |
Why not just install to a new directory like |
Install which files? |
The contents of fontforge/contrib |
Oh, where the files end up isn't the problem, we'd presumably put them where |
Cool. I'm glad we're allowing Tkinter. Do you want me to start writing contribution guidelines, or do you have that covered? If I finish #4066 would that meet the bar for inclusion you think? |
OK, I'll think about the mechanics of the new repository and we can go from there. I would prefer having separate directories for each tool, so that each can have a |
And I guess it won't be that hard to do the equivalent of
from the C-API so I I suppose I can just write that stuff in C. |
(Hmm. Let me read up on this properly before doing anything -- I'm going off a pretty brief skim. The important thing is that it's workable.) |
Oh, this is super easy. @jtanx Shipping actual python code remains among my strong desires, but we don't need that for this. I'll make a prototype (probably without prefs-disabling to start with) to play around with. |
You could do the same to bundle non-core Python dependencies for packages that don't use the system's Python. For each installed script:
|
The proposal is a system that allows FontForge to be extended through normal python packages. How is the independence from the project itself not a feature rather than a bug? I understand the "excitement" point but I don't see how it outweighs all the downsides. |
It certainly is a bug. People want their code in the main release. People want end users to be able to use their scripts without a lot of hassle on Windows and OS X, where a suitable system Python/Pip is unlikely to exist. I'm against such a system if it's our only answer to plugins. Implement it, fine, but I strongly believe we need to promise to distribute scripts if we're going to get developers interested in contributing them. Only enable a few of them by default. Make them pip packages and at the time of building for Windows have Pip install the requirements into |
@jtanx already clarified:
So there's already a |
Why should we expect users to bust out the command line to install the dependencies for a script we distribute? If we're bundling a whole Python distribution, why can't we install Python dependencies we know we need into the Windows/Mac bundles? |
I've said my piece. |
So scripts accepted into |
Hold up, well no, I likely won't be doing that. Just like system Python, I'm not about to install a bunch of crap out of the box as part of the default bundle. At the least I'd think long and hard about doing that, as it's not without implications of its own (and this has already been pointed out in earlier discussions). |
Here's what I don't understand— Why do we want to distribute Python scripts at all if we're not willing to pack their dependencies into the executables for Windows/OS X? Do we even want to make a |
Because I'm not going to make an announcement on Twitter like "we're inviting contributions but if you have any dependencies end users need to run arcane commands with long paths like Let someone else explain the rationale for this to people who would contribute scripts... |
Agh. There are indeed two separate needs here. There are some things that we would almost certainly want everybody to have that would make sense to bundle. But then there are also tangential things that would not make sense and would count as clutter to most users. As @ctrlcctrlv points out, casual users on Windows and Macintosh would really not be able to use the optional ones if doing so required installing dependencies, so I see the big value add in finding a good way to bundle the ones of more universal appeal. If tk seems a little too far off the beaten path to bundle, perhaps we could just shoehorn GTK instead, since that's such a light layer on top of GDK? Then we could bundle a core group of tools that use stock Python and GTK without much trouble. |
@ctrlcctrlv, my long ago question (by message count) was whether the SVG thing worked with Python 3, not whether tkinter worked. |
Calibre is another example of a software that supports Python plugins. They are installed via ZIP files loadable via the GUI. Many plugins are part of the default distribution as well, though not all enabled by default. There's nothing wrong with this and it makes the plugins actually accessible to a wide audience. |
@frank-trampe I just tried my example Tkinter script on Windows and it doesn't work. So the Python interpreter we're bundling doesn't include Tkinter. Jeremy wrote "We bundle a whole Python distribution [on Windows]" but I looked through So @skef said Tkinter scripts could be accepted into So…what do they want? I oppose any conventions that don't have an answer to the question of dependencies that works for casual users. Half-assing this isn't an option. |
I'm not going to speak for @jtanx. For myself:
|
@skef, did we ever merge that into mainline? If not, is there anything that would keep us from doing so? |
There have been some gdkdraw merges that might call for further testing and maybe some tweaks, but broadly speaking it's probably close to being mergable (unless I'm forgetting some larger PR in the mean time). If anyone wants me to restate/summarize my case for why that approach makes the most sense given the current state of the UI, I can. What I'll say here is that without further development, it can support the use-cases of 1) modal dialogs and 2) persistent windows not tightly tied to FontForge state. It would of course require compiling with GDK rather than X11. (Or, rather, users that did not compile with GDK could not run extensions programmed to use it.) That takes care of a lot of potential needs, but some guidance pushing contributors in those directions would be warranted. To have more general interactions FontForge needs a better model for them, with signals and events. I outlined in #3489 how the point info dialog isn't properly bound to a specific state, and the problems someone would face trying to maintain, for example, a window related to a specific CharView are similar. So (in my view) people should be warned away from trying. Still, the most basic throw-up-a-custom-modal-dialog interaction, similar to the "ask" methods of the python API, should work fine. The "bridge" is mostly a very small bit of modality-preserving code on top of @jtanx's massive amount of GDK work. |
The lack of tk support is because the tk dll is lazily loaded, so it's not picked up in the script that bundles all the DLLs required. As for pip, well I thought it did, but apparently pip is packaged separately on msys2. But it's not exactly hard to install pip yourself. |
One of my personal scripts now uses Tkinter: https://github.com/ctrlcctrlv/QuickAnchors/blob/main/QuickAnchors.py So I hope any future change won't break this, as I plan to use it a lot for quickly adding anchors. It writes a TSV file which I convert into FEA syntax: #!/usr/bin/env python3
import csv
import sys
import fontforge
with open("top_marks") as f:
top_marks = f.read().strip().split()
print("@top_marks = [{}];".format(' '.join(top_marks)))
gdefsimple = list()
f = fontforge.open("FRBAmericanCursive.sfd")
for g in f.glyphs():
if g.glyphname not in top_marks:
gdefsimple.append(g.glyphname)
print("@GDEFSimple = [{}];".format(" ".join(gdefsimple)))
print("""
table GDEF {
GlyphClassDef @GDEFSimple,,@top_marks,;
} GDEF;
""")
print("feature mark {")
print(" markClass @top_marks <anchor 0 0> @top;")
with open(sys.argv[1]) as csvf:
r = csv.reader(csvf, delimiter="\t")
for row in r:
(glyph, x, y) = row
print(" position base {} <anchor {} {}> mark @top;".format(glyph, x, y))
print("} mark;") |
In the past year most of the contents of FontForge's
contrib
directory were either removed from the repo or pulled out of the release build process. That was not out of skepticism about external contributions in general (I don't think), it had more to do with what had wound up there.contrib
had become a place to put "fragile" projects that mixed C and python interfaces, and the move to GDK had altered the cost/benefit ratio against them.I've made noises in the past about creating a robust "plugin" system that would allow "outside" contributors to deliver their own functionality through python modules (installed with
pip
, for example). That's still a worthy goal but a) it hasn't happened (yet?) and b) such a system still relies on users being able to find what they need. So it would be nice to have something concrete in the mean time.Anyway, I'm opening this issue to suggest and start a discussion about some conventions for accepting contributions to be shipped with FontForge. Here are my thoughts:
contrib
should be based on the combination of:a. General applicability of the functionality
b. Code quality
c. Engagement of the contributor at the time of contribution. (This is a weak indicator of likelihood of future engagement, but it's something.)
Code quality is, of course, something that can be improved through engagement.
of menu space, but each contribution has its own area.
These questions are newly relevant because of @linusromer's offer in #3216. After seeking input from other FontForge users that tool has evolved into https://github.com/linusromer/curvatura, which I personally think is very close to meeting the bar for release in FontForge's
contrib
directory. It definitely adds functionality that has already been requested, and does so in a way that isn't compromised by being in script form. (That is, if we add hotkeys for it. @linusromer has some suggestions about those here.)Therefore I suggest we discuss this a bit, and if we come to an agreement we either invite @linusromer to submit a PR, or construct some infrastructure that allows our build process to pull contributions from their own repositories. (If we do the latter we might want to request some level of access to the outside repo for some or all team members.)
The text was updated successfully, but these errors were encountered: