-
Notifications
You must be signed in to change notification settings - Fork 1.1k
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
Expose Ruff's public API as a Python library #659
Comments
This would mean that we could do something like the following, right?
Thanks! |
Yup, that's right! |
@messense - I wasn't certain on this last time -- if we bundle a Python API with Ruff, will we need to build separate wheels for every Python version? |
If you can use |
Awesome thank you. I think we should be able to do that, so maybe this will be really straightforward. |
Hello there, do you happen to have a rough timeline for when (if?) this is going to happen? I'm looking to integrate ruff into a tool I'm developing, which would require an API of some sort. It would be very helpful to know if this is something I can wait on, or look for another solution / workaround! |
@provinzkraut - It's definitely going to happen! I could probably ship it within the next week or so. I'd just been punting on it until I had more people asking for it. Could I hear a bit more about your use-case, if you don't mind sharing? |
@charliermarsh That's good to hear!
Sure. I'm working on a markdown extension to automatically generate pymdown tabs for different Python versions from a source version, i.e. generate 3.7, 3.8, 3.10 tabs from a 3.7 source (repo). Currently I'm using |
@provinzkraut - Ok, cool. Let me see what I can do. I don't know if you're comfortable reading Rust, but would the current Rust public API suit your use-case, were it callable from Python with Python objects etc.? |
In short: it takes a file path (to find the I'm guessing that for your use-case, what you actually want is a function that takes source code (plus settings, to enable a list of checks) and returns fixed source code? |
I looked at this yesterday because I though that maybe it could be as simple as adding a tiny wrapper around the rust lib myself, but it seems to be a bit more involved. The current API doesn't really lend itself that well to my usecase.
That would be ideal, yes. Dealing with a list of checks and extracting what I need from it also wouldn't be that big of an issue, but passing in configuration directly and omitting the config file is crucial, both for the needed configurability (I need to run the fixers with varying configuration for every invocation) and performance (I'm running the fixers many times on small snippets, which means the overhead of looking for and parsing a |
I'm working on this now. |
I had a need to execute Ruff as an Alembic post write hook. I came up with a very hamfisted approach that I found from the distributed
[post_write_hooks]
# post_write_hooks defines scripts or Python functions that are run
# on newly generated revision scripts. See the documentation for further
# detail and examples
# format using "black" - use the console_scripts runner, against the "black" entrypoint
hooks = ruff, black
ruff.type = ruff
black.type = console_scripts
black.entrypoint = black and then Alembic's import os
import sysconfig
from alembic.script import write_hooks
@write_hooks.register("ruff")
def run_ruff(filename, options):
ruff = os.path.join(sysconfig.get_path("scripts"), "ruff")
os.spawnv(os.P_WAIT, ruff, [ruff, filename, "--fix", "--exit-zero"]) |
👍 Yup that should be safe to do! (The downside being that you have to go through the CLI rather than calling a function directly. Hoping to enable that soon but not working on it right now.) |
Adding a data point: in mkdocstrings-python we format function signatures with Black if it is installed. We would like to support Ruff to, but spawning a subprocess for each signature is very costly, so we would greatly appreciate a Python binding that doesn't use subprocesses 🙂 A wrapper that hides the subprocess calls sounds nice, but won't be enough for our use-case. |
@pawamoy that sounds neat. We plan to integrate our LSP into ruff (implemented in Rust). I know, it's not as convenient as a Python API but it would allow you to format files without spawning a process for every signature (although it might still be very costly because it requires multiple LSP calls to format a single code snipped) |
By calls do you mean network calls? Or could we somehow spawn the LSP server locally (like a daemon)? |
You would spawn the LSP like a daemon and communicate over stdin/stdout. |
Ah, interesting. Then yeah, that's already much better than subprocesses 🙂 Thanks for the info! |
I put together an experimental package that uses PyO3 to wrap the Ruff formatter in a Python API that doesn't require any subprocesses. I'd still consider it alpha at best (there's only one callable function), but maybe it could be helpful to others as well? |
Amazing, thanks for sharing! I'll check it out :) |
@charliermarsh just checking in - is there any way to configure the |
@Zac-HD, yes, there is! We recently extended the |
Adding another data point: |
Another data point: it would make it easier to replace programmatic calls to black, like in mdsformat-black: https://github.com/hukkin/mdformat-black/blob/master/mdformat_black/__init__.py def format_python(unformatted: str, _info_str: str) -> str:
return black.format_str(unformatted, mode=black.Mode()) |
I’d want to use an API like |
Not the most elegant solution and I haven't tried it myself, but it should soon be possible to call the ruff WASM API from Python: Considering that we have a WASM API now, I'm open to reconsidering a PyO3 API. Let me discuss this internally.
|
I would be open to expose a Ruff Pyo3 API:
I'm happy to support if anyone's interested in contributing the API to ruff. |
Hey, just to add another data-point: we at Vizro would also love to be able to invoke |
Same here -- would love to replace |
@maxschulz-COL @n8henrie @adamchainz I would like to remind folks that https://github.com/amyreese/ruff-api has a working, simple API wrapping both the formatter and import sorter from Ruff, just a |
That looks great, but it is also documented as "highly experimental", so people maybe reluctant to add that to their tool chains. Why don't you contribute that to the ruff project? |
Agreed -- it would be great to have this under ruff's umbrella! |
See: #593
The text was updated successfully, but these errors were encountered: