question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Question: how do I write & run a new profile? Confusion points in quick start guide

See original GitHub issue

I am experimenting with writing a new custom profile, so I will record parts of the experience here, in hopes to help other people to get through the same thing, and ultimately in hopes that the docs can be improved a bit for other beginners.

[This issue is a work in progress and will be edited a few times as I work on this. Feel free to comment if you like, before it is done, however.]

Phase one: making fontbakery command recognize new profile

My beginner problems and solution (Click to expand)

I got stuck at trying to run what I have made so far (basically just the “hello world” example at this stage).

So far, I have tried to follow the instructions at https://font-bakery.readthedocs.io/en/stable/developer/writing-profiles.html.

I have copied from this and modified slightly to have different naming. My current progress is here: https://github.com/typotheque/fontbakery/blob/4d6c10adb591331c1cde457326beb5f8920434e6/Lib/fontbakery/profiles/typotheque.py

Then, I tried to run the following:

fontbakery check-profile typotheque /path/to/fonts

I also tried making a specific check-typotheque command, with this code.

▶ fontbakery check-typotheque /Users/stephennixon/type-repos/tptq/fontbakery-testing/tremoloVF     
usage: fontbakery [-h] [--list-subcommands] [--version]
                  [{build-contributors,check-adobefonts,check-fontval,check-googlefonts,check-opentype,check-profile,check-ufo-sources,check-universal,generate-glyphdata}]
fontbakery: error: argument subcommand: invalid choice: 'check-typotheque' (choose from 'build-contributors', 'check-adobefonts', 'check-fontval', 'check-googlefonts', 'check-opentype', 'check-profile', 'check-ufo-sources', 'check-universal', 'generate-glyphdata')

I then made a fontbakery-venv as recommended in the docs, and installed the modified fontbakery files with pip install -e . This didn’t seem to work quite as I needed it to at first, but I used which fontbakery to find that I wasn’t calling the right thing. I had to basically restart my venv and reinstall to make it work. This isn’t the exact order I did things in, but it’s close:

(fontbakery-venv) 
▶ which fontbakery
/Library/Frameworks/Python.framework/Versions/3.7/bin/fontbakery

(fontbakery-venv) 
type-repos/tptq/fontbakery-tptq  tptq ✗                                                                                   24m ⚑  
▶ deactivate 

type-repos/tptq/fontbakery-tptq  tptq ✗                                                                                   24m ⚑  
▶ source fontbakery-venv/bin/activate

(fontbakery-venv) 
type-repos/tptq/fontbakery-tptq  tptq ✗                                                                                   23m ⚑  
▶ pip install -e .  

(fontbakery-venv) 
type-repos/tptq/fontbakery-tptq  tptq ✗                                                                                   24m ⚑  
▶ which fontbakery                   
/Users/stephennixon/type-repos/tptq/fontbakery-tptq/fontbakery-venv/bin/fontbakery

I think I also had to add the following to the profile to make it work:

from fontbakery.checkrunner import Section
profile = profile_factory(default_section=Section("Typotheque"))

I also found that to run a specific new profile with the check-profile command, you must pass its file path, like so:

▶ fontbakery check-profile Lib/fontbakery/profiles/typotheque.py path/to/fonts/*.ttf

At this stage, the profile looks like this.

Potential improvements for docs

These ideas reflect my personal experience/opinion, so please take these ideas with a grain of salt.

  • The “Writing Profiles” guide could start with more actionable, basic example with step-by-step instructions. For example:
    • It could also include information about pip installation
    • And then it could give just a hello world example, which someone could copy-paste
    • Maybe it could also link to a hello world in an example repo
    • If from fontbakery.checkrunner import Section \n profile = profile_factory(default_section=Section("Typotheque")) must be added, please include that in the hello world example
    • It should probably include instructions on how to make a new command
    • Then, it could give more information about the optional parts of a profile. Currently, the page starts with a few seemingly in-depth features that are hard to understand as a new reader.
  • If the contributor guide recommends a venv called fontbakery-venv, I think this should be included in the .gitignore, correct? (It currently isn’t.)
  • The first command of “Running Profiles” seems to maybe be incorrect. Doesn’t it need to give the relative filepath to the profile?

Phase two: “Profile fails expected checks test”

I have now gotten fontbakery to recognize the new profile. However, it is giving the error Profile fails expected checks test. Details inside this dropdown:

registering expected checks (Click to expand)

At this stage, the profile looks like this.

This was the error from it:

type-repos/tptq/fontbakery-tptq  tptq ✗                                                                                  31m ⚑  ⍉
▶ fontbakery check-profile Lib/fontbakery/profiles/typotheque.py /Users/stephennixon/type-repos/tptq/fontbakery-testing/tremoloVF
Traceback (most recent call last):
  File "/Users/stephennixon/type-repos/tptq/fontbakery-tptq/fontbakery-venv/bin/fontbakery", line 11, in <module>
    load_entry_point('fontbakery', 'console_scripts', 'fontbakery')()
  File "/Users/stephennixon/type-repos/tptq/fontbakery-tptq/Lib/fontbakery/cli.py", line 22, in main
    "fontbakery.commands." + subcommand_module, run_name='__main__')
  File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/runpy.py", line 208, in run_module
    return _run_code(code, {}, init_globals, run_name, mod_spec)
  File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/runpy.py", line 85, in _run_code
    exec(code, run_globals)
  File "/Users/stephennixon/type-repos/tptq/fontbakery-tptq/Lib/fontbakery/commands/check_profile.py", line 346, in <module>
    sys.exit(main())
  File "/Users/stephennixon/type-repos/tptq/fontbakery-tptq/Lib/fontbakery/commands/check_profile.py", line 229, in main
    profile = get_profile()
  File "/Users/stephennixon/type-repos/tptq/fontbakery-tptq/Lib/fontbakery/commands/check_profile.py", line 214, in get_profile
    imported = get_module(args.profile)
  File "/Users/stephennixon/type-repos/tptq/fontbakery-tptq/Lib/fontbakery/commands/check_profile.py", line 195, in get_module
    imported = get_module_from_file(name)
  File "/Users/stephennixon/type-repos/tptq/fontbakery-tptq/Lib/fontbakery/commands/check_profile.py", line 187, in get_module_from_file
    profile.loader.exec_module(module)
  File "<frozen importlib._bootstrap_external>", line 728, in exec_module
  File "<frozen importlib._bootstrap>", line 219, in _call_with_frames_removed
  File "Lib/fontbakery/profiles/typotheque.py", line 117, in <module>
    profile.test_expected_checks(expected_check_ids, exclusive=True)
  File "/Users/stephennixon/type-repos/tptq/fontbakery-tptq/Lib/fontbakery/checkrunner.py", line 1109, in test_expected_checks
    '\n'.join(message)))
fontbakery.checkrunner.SetupError: Profile fails expected checks test:
missing checks: com.typotheque/examples/hello, com.typotheque/examples/ttf_has_glyphs;
unexpected checks: com.google.fonts/check/family/panose_familytype, com.google.fonts/check/family_naming_recommendations, 

# ETC. 64 more check IDs omitted 

I am confused by this … I have the following in my code near the top of the profile:

expected_check_ids = (
    'com.typotheque/examples/hello',
    'com.typotheque/examples/ttf_has_glyphs',
)

and both of those are in the code, as shown in the Quick Start but named for this profile. However, the error is calling those checks as missing checks.

…my profile also has the final line of:

profile.test_expected_checks(expected_check_ids, exclusive=True)

Have I missed something here?

UDPATE

I have found that I can get the check running with the following code, where I exclude the profile_imports = ('fontbakery.profiles.universal',) temporarily. This works and even allows me to run the ghmarkdown option.

🍞 PASS: Simple "Hello World" example.

However, I still need to find how to import other checks.

UPDATE 2

I have solved this expected checks by taking some cues from the googlefonts profile. This included a couple of additions:

At the top:

from fontbakery.profiles.universal import UNIVERSAL_PROFILE_CHECKS

Near the top:

TYPOTHEQUE_CHECK_IDS = [
    'com.typotheque/check/hello',
]

EXPECTED_CHECK_IDS = \
    UNIVERSAL_PROFILE_CHECKS + \
    TYPOTHEQUE_CHECK_IDS

Last line:

profile.test_expected_checks(EXPECTED_CHECK_IDS, exclusive=True)

So, I think this is actually closer to a “Quick Start” / “Hello World” example, though obviously others would have to swap in their own foundry naming.

Suggestions for docs

  • Maybe update the “Hello World” with a complete example, similar to what I linked to just above?
  • Please explain why it is necessary to use both of the following (or if there is a better way?)
    • from fontbakery.profiles.universal import UNIVERSAL_PROFILE_CHECKS
    • profile_imports = ('fontbakery.profiles.universal',)

Issue Analytics

  • State:open
  • Created 3 years ago
  • Comments:8 (5 by maintainers)

github_iconTop GitHub Comments

2reactions
konturcommented, Jun 16, 2020

This includes a few different examples:

profile_imports = [
    [
        # Only a specific condition from the fontbakery module
        "fontbakery.profiles.shared_conditions", ["is_cff"]
    ],
    [
        # Only a specific condition from a local relative module (conditions.py)
        ".conditions", ["psautohint_stats"]
    ],
    [
        # A bunch of fontbakery profiles with all their checks
        "fontbakery.profiles",
        [
            "cff",
            "cmap",
            ...
            "post",
            "shared_conditions"
        ]
     ],
    [
        # One specific check from a profile in the fontbakery module
        "fontbakery.profiles.googlefonts", [
            "com_google_fonts_check_hinting_impact"
        ]
    ]
]

I’m not sure does it work so that omitting the second list includes all checks of a module, but at least if you want to cherry pick yourself some checks this works.

1reaction
graphicorecommented, Jun 16, 2020

There’s a lot going on here, I’ll try to answer some things.

First: there are separate options how to run a profile with Font Bakery. In general if you want to make a custom profile, I wouldn’t implement it in a clone/fork of Font Bakery. Just use the file path to the file that contains the profile OR make a module and install it into your virtual environment.

You should only work in a clone of Font Bakery if you either want to contribute or if you want to fork it and hence also maintain the fork. The “Source Code Contributor Guide” is meant for contributing.

The “Writing Profiles” guide could start with more actionable, basic example with step-by-step instructions. […]

We could make add a “Step by Step Beginners Guide to writing profiles”

It should probably include instructions on how to make a new command

This is IMO not a direction authors of custom profiles should go. Maybe just write a one line shell command next to your custom profile or even in your users ~/.bin

Then, it could give more information about the optional parts of a profile. Currently, the page starts with a few seemingly in-depth features that are hard to understand as a new reader.

Yes, it’s more like documentation, less like a guide, which is different, but a simpler guide could be present somewhere. Also, maybe you should have tried to read it again, I believe the stuff you did not understand is all in the very beginning of the document, with some exceptions, so maybe it’s just necessary to put it there. I’d call it rather documentation than a guide, because the way one reads documentation is not linear, it’s more like jumping on the page between passages and information.

I think one source of confusion was to use the “contributing” document along with the “writing profiles” document. So clearly, there’s a need to improve the conversion funnel for the user.

If from fontbakery.checkrunner import Section \n profile = profile_factory(default_section=Section(“Typotheque”)) must be added, please include that in the hello world example

This is documented in detail at the beginning of the documentation: From automatic discovery to full control

I second that from when I was writing a custom profile a while back. It’s not super clear but seems to be required, even if that is your “only” section.

No, it is not required.

I can copy and paste the example given in ‘writing profiles’ into a file, then run:

(venv3) commander@draugr:~/Projects/googlefonts> fontbakery  check-profile ./fontbakery-example-profile/my-custom-profile.py ~/Desktop/NotoSans-Regular.ttf

# Note, the profile is not in the fontbakery project directory:
(venv3) commander@draugr:~/Projects/googlefonts> which fontbakery
/home/commander/Projects/googlefonts/fontbakery/venv3/bin/fontbakery

The first command of “Running Profiles” seems to maybe be incorrect. Doesn’t it need to give the relative filepath to the profile?

Depends if your profile is installed as a module or not. I’m not exactly sure what you mean actually, but the one example uses a relative path and the other a module name, just look at the extension .py if you are not sure what is what, but there are also comments above (under “execute” in Quick start). However, you can also use an absolute path, FWIW.

(venv3) commander@draugr:~/Projects/googlefonts> fontbakery  check-profile /home/commander/Projects/googlefonts/fontbakery-example-profile/my-custom-profile.py ~/Desktop/NotoSans-Regular.ttf

About

[…] “Profile fails expected checks test”

  • Maybe update the “Hello World” with a complete example, similar to what I linked to just above?

I believe it’s mostly complete, but maybe we need a more verbose guide. But who’s going to read it? If it’s wrong or missing things we should correct that.

Please explain why it is necessary to use both of the following (or if there is a better way?) from fontbakery.profiles.universal import UNIVERSAL_PROFILE_CHECKS profile_imports = (‘fontbakery.profiles.universal’,)

There’s a lot of info about what profile_imports does and why it’s there, here’s a shorter one, but there’s a whole section.

profile_imports can be used to mix other profiles into this profile

if you follow the UNIVERSAL_PROFILE_CHECKS variable you’ll see it ends up in EXPECTED_CHECK_IDS and that ends up in profile.test_expected_checks(EXPECTED_CHECK_IDS, exclusive=True)

Now profile.test_expected_checks is documented this describes what it is good for. Please also search for this sentence:

Since we have the profile reference we can also use the expected_check_ids self check method.

This is optional, hence we can (not must) use it. It’s meant as self-check, similar to a check-sum. If you want to use it, you need a reference to a profile and that’s why you create it: profile = profile_factory(default_section=Section("Typotheque")).

Importing UNIVERSAL_PROFILE_CHECKS in a way defeats the self-check, because you don’t have control over the check id’s in that list, you could maintain the list yourself in your custom profile, to be sure you don’t miss it when a profile that is a dependency of your profile of you changes which checks it defines. But also, if you don’t get why to use profile.test_expected_checks or if you don’t need that kind of (self-)control, you should probably not use it in the first place.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Profile confusion - Oracle Help Center
Profile confusion is actually not an issue that is specific to Eloqua itself. It is based on the general limitations that come with...
Read more >
Confusion Matrix in R | A Complete Guide - DigitalOcean
A confusion matrix in R is a table that will categorize the predictions against the actual values. It includes two dimensions, among them...
Read more >
Tips & Templates for Writing Great Knowledge Base Articles
Here are some tips, tricks, and templates for how to write excellent knowledge base articles that help customers help themselves.
Read more >
How to use Slack: your quick start guide
Use mentions to get the attention of specific people in a conversation, whether you need to ask for feedback or follow up on...
Read more >
How to complete a Chase business credit card application
Use our guide to help you accurately complete a Chase business credit card application and avoid the potential pitfalls.
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found