Skip to content
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

Change Black linelength defaults? #10

Open
coolum001 opened this issue Aug 3, 2019 · 14 comments
Open

Change Black linelength defaults? #10

coolum001 opened this issue Aug 3, 2019 · 14 comments

Comments

@coolum001
Copy link

Hi

First of all, thank you for this extension.

I plan to use nb_black and Jupyter Notebooks to generate blog posts, where code blocks are indented. This means I would like to set the line length to 65 (ie not the default).

I would also like to preserve single quote strings (a black option).

Can you indicate where in your code it might be possible to change the default parameters for black?

Second:
I am running Jupyter lab Version 0.35.3, in an environment as below

python version : 3.7.1 (default, Dec 10 2018, 22:54:23) [MSC v.1915 64 bit (AMD64)]
python environment : ac5-py37
pandas version : 0.23.4
current wkg dir: C:\Users\donrc\Documents\JupyterNotebooks\OSMNXNotebookProject\develop
Notebook name: Communities.ipynb
Notebook run at: 2019-08-03 18:45:44.954269 local time
Notebook run at: 2019-08-03 08:45:44.954269 UTC
Notebook run on: Windows-10-10.0.18362-SP0

<IPython.core.display.Javascript object>

You will notice that Jupyterlab displays after each cell execution (I assume this is unintended behaviour)


<IPython.core.display.Javascript object>

I am running nb_black as below

(ac5-py37) C:\Users\donrc>conda list nb_black
# packages in environment at D:\Anaconda3\envs\ac5-py37:
#
# Name                    Version                   Build  Channel
nb_black                  1.0.6                      py_0    conda-forge

Now I can't reproduce this behaviour in smaller Notebooks, so you may see fit to ignore this until I can :)

Third, invoking %load_ext lab_black seems to stick with the notebook. Even if you reload the notebook and delete the %load_ext cell, the black formatting is still applied to new cells. You may wish to mention that you turn it off by a %unload_ext lab_black call.

Happy to supply more info if needed

Don Cameron

@coolum001
Copy link
Author

Hi
Don Cameron here.

I think that the <IPython.core.display.Javascript object> display after each cell was because I had loaded nb_black into a JupyterLab, environment, and not lab_black. Unloading the correct extension fixed the problem.

Sorry to waste your time on this,
Don

@vmarceau
Copy link

vmarceau commented Aug 8, 2019

Hey Don,

Just curious if you have found a way to change the default parameters for black when using nb_black (especially max line length and single quotes)? I would also be interested in doing that.

Thanks!

@michaelaye
Copy link

configuring black itself doesn't work? https://black.readthedocs.io/en/stable/pyproject_toml.html

@coolum001
Copy link
Author

Hi
I didn't want to reconfigure black as a whole, because I use it in VSCODE, and I want it as it is.

My use-case is creating blog entries from JupyterLab notebooks, where because my blog-engine (Pelican, built-texts theme, ipynb.markup plugin) has quite a narrow column width. So I just want the code in some Notebooks (but not all) formatted as narrow. For an example, see https://coolum001.github.io/jupyterblog.html

I have hacked up a solution:

in lab_black.py, there is a function defined _format_code(code)

My version of this now reads

    def _format_code(code):
#        return format_str(src_contents=code, mode=FileMode())
        my_mode = FileMode()
        my_mode.line_length = 65
        my_mode.string_normalization = False
        return format_str(src_contents=code, mode=my_mode)

When I stop being lazy, I might work out how to read parameters from the %load_ext command :) , but this works for me.

Thanks again for the package
Don Cameron

@coolum001
Copy link
Author

Just to be completely accurate, the blog post referenced above was formatted with a lab_black.py locally in the same directory as the Notebook, with _format_code() defined as:

    def _format_code(code):
#        return format_str(src_contents=code, mode=FileMode())
        my_mode = FileMode()
        my_mode.line_length = 60
        my_mode.string_normalization = False
        return format_str(src_contents=code, mode=my_mode)

@michaelaye
Copy link

Note that the black configuration file works locally as well, so you can have completely different settings per folder by having that config file in there.

@coolum001
Copy link
Author

Michael

Didn't know that (obviously). I will give it a try, as being cleaner than having private versions of lab_black
Thanks
Don

@coolum001
Copy link
Author

Hi
I have a directory with a pyproject.toml file that looks like:

[tool.black]
skip-string-normalization = true
line-length = 60

and a batch (command line) invocation of black works as expected, giving me the message:

Using configuration from C:\Users\donrc\Documents\JupyterNotebooks\SymAlgebraExamplesNotebookProject\develop\pyproject.toml.

However, %load_ext lab_black in a JupyterLab Notebook in the same directory, still converts single quotes to double. I suspect that the Black formatting is being done in a backend server or process, that can't see my directory to find my TOML file, because it has a different current working directory.

This happens even when I run the jupyter lab command that started that session, from inside that directory.

So I might have to go back to my handcrafted lab_black.py file after all :(
Thanks
Don Cameron

@michaelaye
Copy link

michaelaye commented Aug 9, 2019 via email

@dnanhkhoa
Copy link
Owner

Hi, sorry for late reply and thank Michael for solutions so far, I will try to figure out why it cannot detect local configuration file

@n8henrie
Copy link

I'd also love to see this extension respect pyproject.toml's black settings, but no luck so far.

I've gone the route above and manually edited the file in my site-packages which works.

Looking at the black code, I think the issue is that format_str doesn't call the functions related to finding and loading the config file; it relies on the passed-in FileMode, which has been set to defaults in the extension. Unfortunately I don't see an easy way to import just the config loading code from black (tried by importing click.testing.FileRunner or something to that effect but couldn't sort it out).

@n8henrie
Copy link

Here's one way: https://github.com/arokem/python-matlab-bridge/blob/master/pymatbridge/matlab_magic.py#L68 accept kwargs into load_ipython_extension and allow users desiring custom configuration to manually import the extension and run the function with their config.

The below is just a proof-of-concept patch, I don't use yapf so I don't know if it breaks anything there, and I only implemented configuration for line-length. The screenshot below shows how to load it with config, and shows that if loaded with %load_ext, it successfully loads but will use the black defaults.

diff --git a/lab_black.py b/lab_black.py
index 9dbf6f4..bec76e3 100644
--- a/lab_black.py
+++ b/lab_black.py
@@ -23,10 +23,11 @@ from IPython.display import Javascript, display
 __BF_SIGNATURE__ = "__BF_HIDDEN_VARIABLE_{}__"
 
 if sys.version_info >= (3, 6, 0):
-    from black import format_str, FileMode
+    import black
 
-    def _format_code(code):
-        return format_str(src_contents=code, mode=FileMode())
+    def _format_code(code, mode):
+
+        return black.format_str(src_contents=code, mode=mode)
 
 
 else:
@@ -170,9 +171,10 @@ def _recover_magic_commands(cell, hidden_variables):
 
 
 class BlackFormatter(object):
-    def __init__(self, ip, is_lab):
+    def __init__(self, ip, is_lab, mode):
         self.shell = ip
         self.is_lab = is_lab
+        self.mode = mode
 
     def __set_cell(self, unformatted_cell, cell, cell_id=None):
         if self.is_lab:
@@ -215,7 +217,7 @@ class BlackFormatter(object):
                 # Transform magic commands into special variables
                 cell = _transform_magic_commands(unformatted_cell, hidden_variables)
 
-                formatted_code = _format_code(cell)
+                formatted_code = _format_code(cell, self.mode)
 
                 # Recover magic commands
                 formatted_code = _recover_magic_commands(
@@ -230,10 +232,14 @@ class BlackFormatter(object):
 black_formatter = None
 
 
-def load_ipython_extension(ip):
+def load_ipython_extension(ip, line_length=79):
     global black_formatter
+    mode = black.FileMode(
+        target_versions={black.TargetVersion.PY38}, line_length=line_length,
+    )
+
     if black_formatter is None:
-        black_formatter = BlackFormatter(ip, is_lab=True)
+        black_formatter = BlackFormatter(ip, is_lab=True, mode=mode)
         ip.events.register("post_run_cell", black_formatter.format_cell)

screenshot 2020-06-25 at 12 13 29 PM

@msm1089
Copy link

msm1089 commented Aug 19, 2020

@n8henrie 's solution is best if you may ned to configure the line length. Shorter way, if you will only ever need to change the line length rarely or never:

replace

nb_black/lab_black.py

Lines 26 to 29 in d4bd99e

from black import format_str, FileMode
def _format_code(code):
return format_str(src_contents=code, mode=FileMode())

with

    from black import format_str, FileMode, TargetVersion

    def _format_code(code):
        mode = FileMode(target_versions={TargetVersion.PY38},
                              line_length=79)
        return format_str(src_contents=code, mode=mode)

setting line_length as desired.

@n8henrie
Copy link

Work seems to have slowed down, so I created a fork that addresses this issue and adds a few other features: https://github.com/n8henrie/jupyter-black

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants