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

New rule: dependency specification linting #9988

Open
QMalcolm opened this issue Feb 14, 2024 · 0 comments
Open

New rule: dependency specification linting #9988

QMalcolm opened this issue Feb 14, 2024 · 0 comments
Labels
rule Implementing or modifying a lint rule

Comments

@QMalcolm
Copy link

QMalcolm commented Feb 14, 2024

Context

Working in many python projects over the years, I've experienced on occasion bad things happening ᵀᴹ due to the accidental allowance of more than one major version of a package via dependency specification. Sometimes this is known and intentional, other times it is accidental and dangerous. A recent example of this that I experienced was that I upgraded dbt-semantic-interfaces to support both Pydantic 1 and Pydantic 2 (intentionally). A downstream package installed alongside dbt-semantic-interfaces had it's pydantic dependency specified as pydantic>=1.0,<=2.0. However, it was never intended to actually support Pydantic 2. It should have been pydantic>=1.0,<2.0, but because of the <= it started blowing up at runtime.

Desired Improvement

It'd be amazing to have a rule for linting python dependencies that ensures the allowance of multiple major versions of a dependency is always known and intentional. In my mind there are a few different types of dependency major version range specification that exist: unconstrained, constrained, and singular.

Singular Major Version

A singular major version specification means that only one major version for a given dependency is allowed by the specification. Thus, the linter should never raise an error for singular major version specifications of dependencies. Singular major version specifications look like the following

# only ever 1.5.7, thus only major version 1
package_a == 1.5.

# Allows for versions >= 1.0 and < 2, thus only major version 1
package_b ~= 1.0

# Allows for exactly what it says, thus only major version 1     
package_c >= 1.3.4, <2

Constrained Major Version

A constrained major version means that there is an upper bound specification, and the major version of the upper bound specification is different that the specified or implicit lower bound specification (if a lower bound isn’t specified it is implicitly 0.0).

This type of version specification is dangerous because major versions are generally where large breaking changes happen. Sometimes there is compatibility between major versions or compatibility might be possible through shimming, but this should be known and intentional. Thus, the linter should raise an error for this type of dependency version specification unless there is a comment to acknowledge it like # ignore:constrained_range or something similar. The following are examples of constrained major version specifications

# major versions allowed are [0, 1], an error should be raised
package_a < 2

# major versions allowed are [1, 2, 3], an error should be raised
package_b >= 1.0, <= 3

# major versions allowed are [1, 2], an error should be raised
package_c >= 1.0, < 3

Again all the above should have an error raised by the linter unless an acknowledgement is made that this is intentional like the following

# major versions allowed are [1, 2]
package_a >= 1.0, < 3  # ignore:constrained_range

Unconstrained Major Version

An unconstrained major version means that lower bound is specified or implicit, but no upper bound is provided. These are incredibly dangerous as large breaking changes are normal across major versions, this type of specification allows for any new major version to be automatically included as available. This type of version specification should always raise an error by the linter and not be ignorable. The following are examples unconstrained major version specifications

# allows for major versions [0, 1, 2, ..., infinitey]
package_a

# allows for major versions [2, 3, 4, ..., infinitey]
package_b >= 2

I'm happy to help contribute this, although I'm not super well versed in Rust. I'm currently working on a prototype in python.

@QMalcolm QMalcolm changed the title New rule: dependency linting New rule: dependency specification linting Feb 14, 2024
@MichaReiser MichaReiser added the rule Implementing or modifying a lint rule label Feb 14, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
rule Implementing or modifying a lint rule
Projects
None yet
Development

No branches or pull requests

2 participants