Skip to content

Apply ruff formatting and safe lint fixes - #1061

Open
kroenlein wants to merge 5 commits into
mainfrom
maintain/ruff-formatting
Open

Apply ruff formatting and safe lint fixes#1061
kroenlein wants to merge 5 commits into
mainfrom
maintain/ruff-formatting

Conversation

@kroenlein

@kroenlein kroenlein commented Aug 7, 2026

Copy link
Copy Markdown
Collaborator

The only purpose of the PR is running all package lines through ruff so that future formatting issues do not distract from code changes.

PR Type:

  • Breaking change (fix or feature that would cause existing functionality to change)
  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Maintenance (non-breaking change to assist developers)

Adherence to team decisions

  • I have added tests for 100% coverage
  • I have written Numpy-style docstrings for every method and class.
  • I have communicated the downstream consequences of the PR to others.
  • I have bumped the version in __version__.py

kroenlein and others added 2 commits August 6, 2026 09:09
…igial-test-fields

[v5.0] Remove vestigial experimental fields from test fixture
Ran `ruff format` and `ruff check --fix` (safe fixes only, line-length 99)
over all Python files in src/ and tests/.

Resolved conflicts with the project's flake8 configuration:
- Disabled RUF100 during the fix so noqa comments flake8 relies on
  (D-codes, E501, W505) are preserved.
- Hand-wrapped 8 f-strings that exceeded 99 chars after .format() -> f-string
  conversion.
- Added E203 to the flake8 ignore list (standard ruff/black slice-spacing
  exception).

Fixed two autofixes that would have broken the test suite:
- Restored the load-bearing import order in tests/utils/fakes/__init__.py
  (marked # isort: skip_file) to avoid a circular import.
- Restored the pytest fixture import in tests/serialization/test_scorers.py
  (marked # noqa: F401).

flake8 is clean and all 1237 tests pass.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@kroenlein
kroenlein marked this pull request as ready for review August 7, 2026 02:36
@kroenlein
kroenlein requested a review from a team as a code owner August 7, 2026 02:36
Base automatically changed from release/5.0 to main August 7, 2026 15:19
Comment thread tests/_util/test_functions.py Fixed
Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
Comment thread src/citrine/gemtables/variables.py Outdated
Comment on lines +436 to +440
self.attribute_constraints = (
None
if attribute_constraints is None
else [(_make_link_by_uid(x[0]), x[1]) for x in attribute_constraints]
)

@anoto-moniz anoto-moniz Aug 19, 2026

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not a fan of this. I never like splitting ternary operators across multiple lines, but blowing it up like this means it's longer than the equivalent traditional if-statement.

I'd love if for ternaries that are too long, we could explode them into if statements. Or maybe just have ruff allow them to be two lines, like this one initially was?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I abstracted this into an explicit if clause, and then noticed we repeated that code 6 times, so I created a static method to consolidate.

Comment on lines +34 to +36
"{} is not a valid design subspace type. Must be in {}.".format(
data["type"], type_dict.keys()
)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wait, why didn't it convert this formatted string into an f-string? Did I misinterpret the previous conversions?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because we support 3.10, but nested double quotes isn't supported until 5.12. Manually addressed by swapping to single quotes.

@anoto-moniz anoto-moniz Aug 24, 2026

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just find it odd the formatter didn't realize that simple fix on its own. ¯_(ツ)_/¯

self.mean = mean
self.std = std
pass # pragma: no cover
# pragma: no cover

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be removed now.

def __init__(self, *, probabilities: dict):
self.probabilities = probabilities
pass # pragma: no cover
# pragma: no cover

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Drop.

self.quantities = quantities
self.labels = labels or {}
pass # pragma: no cover
# pragma: no cover

@anoto-moniz anoto-moniz Aug 19, 2026

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Drop.

This file has a bunch of #pragma: no cover statements on blank lines following the removal of unnecessary pass statements. They should all be dropped.

Comment on lines +24 to +29
pass # pragma: no cover
# pragma: no cover

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This one I get, because having a method with no body in Python feels weird. But a docstring makes it legal, so we can drop the pragma.

Comment thread src/citrine/resources/ingestion.py Outdated
Comment on lines +141 to +143
errors=[
IngestionErrorTrace.from_validation_error(x) for x in source.validation_errors
]

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've never been a fan of splitting for-comprehensions across lines. But at least the original form of this line makes it a bit clearer, since the for begins the second line, before closing the list. This new form obfuscates it in the middle of the line, surrounded by other stuff.

I'd prefer if we could get ruff to use the two-line version.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Couldn't find a direct fix, so I reverted and used # fmt: skip. The only "solution" was extending max line length, which would just trigger more problems.

Comment on lines +456 to +461
return IngestionStatus.build(
{
"status": IngestionStatusType.INGESTION_CREATED,
"errors": self.errors,
}
)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmmmmmmmmmm...not the most egregious, but feels needlessly verbose. Personally, I don't think we gain any clarity by having the braces on their own lines.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in pyproject.toml via skip-magic-trailing-comma.

Comment on lines +76 to +89
properties = Optional(
List(
Union(
[
LinkOrElse(GEMDPropertyTemplate),
SpecifiedMixedList(
[LinkOrElse(GEMDPropertyTemplate), Optional(Object(BaseBounds))]
),
]
)
),
"properties",
override=True,
)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oof. I hate this. However, it's more an expression of how messy the definition of the serde stuff is generally, laid bare by the complication of the type itself. So not sure there's anything to be done. Ugh.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I created an alias for LinkOrElse(GEMDPropertyTemplate) and swapped the Union to a |. I think it's more legible.

| LinkByUID
| Sequence[PropertyTemplate | LinkByUID | BaseBounds | None]
]
| None = None,

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I continue to think multi-line type definitions in the middle of a function definition are the work of the devil. But I'm not sure a super long line is much better...

Comment on lines +54 to +61
serialized = [(key_serialized, value_serialized),]
serialized = [
(key_serialized, value_serialized),
]

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be great if there was some rule that if ruff finds a collection on a single line with a trailing comma, it removed the comma instead of inserting newlines. That is, I'd want this to be turned into

serialized = [(key_serialized, value_serialized)]

Comment thread tests/gemd_query/test_gemd_query.py Outdated
Comment on lines +39 to +42
assert (
query.criteria[0].property_templates_filter
== query_copy.criteria[0].property_templates_filter
)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't know the best option for something like this, but I do know I dislike this method of splitting the assert.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I reworked this as looping over lambdas, since it there were honestly a lot of characters to track on that line.

Comment thread tests/resources/test_branch.py Outdated
Comment on lines +411 to +413
assert expected_data_updates["predictors"][0]["predictor_id"] == str(
actual_data_updates.predictors[0].uid
)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is even worse. If it must split them across lines, at least keep the left- and right-hand operands together.

Comment thread tests/resources/test_gemd_resource.py Outdated
Comment on lines +407 to +409
session.set_response(
obj.dump()
) # Delete calls get, must return object data internally

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't love wrapping due to a comment, even less so in a test. We should just move this comment to the line above.

Comment thread tests/resources/test_gemd_resource.py Outdated
Comment on lines +416 to +418
session.set_response(
obj.dump()
) # Delete calls get, must return object data internally

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here.

Comment thread tests/resources/test_table_config.py Outdated
Comment on lines +468 to +478
assert (
next(
(
var
for var in def1.variables
if name in var.headers and isinstance(var, IngredientLabelsSetByProcessAndName)
),
None,
)
is not None
)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is another example of linting making for terribly unreadable code. Is there some way to tell ruff to not format this line? Or do we just need to refactor it to be shorter?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Honestly, even the original version doesn't spark joy.

Comment thread tests/resources/test_templates.py Outdated
Comment on lines +63 to +65
BadRequest(
""
), # Attempted POST throws BadRequest because, for example, the template bounds are being narrowed.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should move the comment to make this more readable.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe if there's some way to automatically do that? Can we get ruff to move comments to the line above if the line is short enough without it?

Comment thread tests/test_citrine.py Outdated
Comment on lines +34 to +39
assert (
"1234"
== Citrine(
api_key="1234", scheme="http", host="citrine-testing.fake", port="8080"
).session.refresh_token
)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This line is particularly ugly.

Comment thread tests/test_session.py Outdated
Comment on lines +51 to +56
assert (
"1234"
== Session(
refresh_token="1234", scheme="ftp", host="citrine-testing.fake", port="8080"
).refresh_token
)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤮

Follow-up to the ruff-formatting pass, addressing Austin's review feedback
and applying the same fixes to unflagged instances of each concern type.

- Add [tool.ruff] config: skip-magic-trailing-comma (collapses single-line
  collections instead of exploding them) with isort.split-on-trailing-comma
  disabled for compatibility.
- Convert .format() calls on string literals to f-strings.
- Drop orphaned `# pragma: no cover` comments left after `pass` removal.
- Refactor split-operand/wrapped asserts to keep operands together (extract
  locals, loop over cases, lambda accessors) and move comments that forced
  line wraps above their expressions.
- gemtables/variables.py: extract the repeated ternary into a module-level
  `_build_attribute_constraints` helper and hoist the duplicated
  `_AttributeType`/`_ObjectType`/`_ConstraintType` aliases to module scope.
- Restore correct (separate) LinkOrElse instances in the template property
  definitions; shared Property descriptors break serialization-path assignment.
- validate_type: raise ValueError instead of bare Exception.
- Cover PvA __iter__ explicitly after switching next(iter(...)) reads to [].

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
if data_dict_copy["type"] != type_name:
raise Exception(
"Object type must be {}, but was instead {}.".format(type_name, data_dict["type"])
raise ValueError(

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I chose to change the type here because we really shouldn't have been throwing an Exception,

Comment on lines +445 to +448
assert any(
var
for var in def1.variables
if name in var.headers and isinstance(var, IngredientQuantityByProcessAndName)

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not formally the same but close enough and much more legible.

Comment on lines +52 to +55
cast = str(team_member)
assert user.screen_name in cast
assert all(a in cast for a in team_member.actions)
assert team.name in cast

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seemed like it was actually testing what we cared about plus dropped the operator-split.

Comment on lines +12 to +23
return {
"type": "ContinuousDimension",
"descriptor": {
"type": "Real",
"descriptor_key": "alpha",
"units": "",
"lower_bound": 5.0,
"upper_bound": 10.0,
},
"lower_bound": 6.0,
"upper_bound": 7.0,
}

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Showed up as a non-binding warning.

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

Successfully merging this pull request may close these issues.

3 participants