2020-12-03 16:54:36 +01:00
# See https://semgrep.dev/docs/writing-rules/rule-syntax/ for documentation on YAML rule syntax
2020-03-19 00:32:26 +01:00
rules :
2020-07-01 21:19:49 +02:00
####################### PYTHON RULES #######################
2020-03-19 00:32:26 +01:00
- id : deprecated-render-usage
pattern : django.shortcuts.render_to_response(...)
2020-04-27 13:46:53 +02:00
message : "Use render() (from django.shortcuts) instead of render_to_response()"
2020-03-19 00:32:26 +01:00
languages : [ python]
severity : ERROR
2020-04-27 13:46:53 +02:00
2020-04-29 13:50:36 +02:00
- id : dont-use-stream-objects-filter
pattern : Stream.objects.filter(...)
message : "Please use access_stream_by_*() to fetch Stream objects"
languages : [ python]
severity : ERROR
paths :
2020-06-05 10:10:37 +02:00
include :
- zerver/views/
2020-05-01 08:56:20 +02:00
2023-09-29 17:03:18 +02:00
- id : time-machine-travel-specify-tick
patterns :
- pattern : time_machine.travel(...)
- pattern-not : time_machine.travel(..., tick=..., ...)
message : |
Specify tick kwarg value for time_machine.travel(). Most cases will want to use False.
languages : [ python]
severity : ERROR
2023-08-30 21:19:37 +02:00
- id : limit-message-filter
patterns :
- pattern : Message.objects.filter(...)
- pattern-not : Message.objects.filter(..., realm=..., ...)
- pattern-not : Message.objects.filter(..., realm_id=..., ...)
- pattern-not : Message.objects.filter(..., realm_id__in=..., ...)
- pattern-not : Message.objects.filter(..., id=..., ...)
- pattern-not : Message.objects.filter(..., id__in=..., ...)
- pattern-not : Message.objects.filter(..., id__lt=..., ...)
- pattern-not : Message.objects.filter(..., id__gt=..., ...)
message : "Set either a realm limit or an id limit on Message queries"
languages : [ python]
severity : ERROR
paths :
exclude :
- "**/migrations/"
2024-03-22 15:01:55 +01:00
- id : dont-use-empty-select_related
pattern-either :
2024-03-22 21:22:00 +01:00
- pattern : $X.select_related()
- pattern : $X.prefetch_related()
2024-03-22 15:01:55 +01:00
message : |
Do not use a bare '.select_related()' or '.prefetch_related()', which can join many more tables than expected. Specify the relations to follow explicitly.
languages : [ python]
severity : ERROR
2020-05-01 08:56:20 +02:00
- id : dont-import-models-in-migrations
patterns :
2024-08-28 03:44:40 +02:00
- pattern-not : from zerver.lib.partial import partial
2024-07-17 18:14:17 +02:00
- pattern-not : from zerver.lib.mime_types import $X
2020-05-01 08:56:20 +02:00
- pattern-not : from zerver.lib.redis_utils import get_redis_client
2023-05-18 17:21:21 +02:00
- pattern-not : from zerver.lib.utils import generate_api_key
2023-12-15 02:51:31 +01:00
- pattern-not : from zerver.models.linkifiers import filter_pattern_validator
- pattern-not : from zerver.models.linkifiers import url_template_validator
2023-12-15 03:57:04 +01:00
- pattern-not : from zerver.models.streams import generate_email_token_for_stream
2023-12-15 02:14:24 +01:00
- pattern-not : from zerver.models.realms import generate_realm_uuid_owner_secret
2020-05-01 08:56:20 +02:00
- pattern-either :
- pattern : from zerver import $X
- pattern : from analytics import $X
- pattern : from confirmation import $X
2021-06-17 15:02:52 +02:00
message : "Don't import models or other code in migrations; see https://zulip.readthedocs.io/en/latest/subsystems/schema-migrations.html"
2020-05-01 08:56:20 +02:00
languages : [ python]
severity : ERROR
paths :
2020-06-05 10:10:37 +02:00
include :
- "**/migrations"
exclude :
migrations: Squash zerver migrations.
This has the impact of making rebuilding the database in a Zulip
development environment, or initializing a new production database,
dramatically faster.
This was generated by merging the output of `manage.py makemigrations`
with an empty migration.
Tested using `tools/rebuild-test-database` before and after this
change, and comparing the output of `pg_dump -d zulip_test` using
Git's diff comparison algorithm. Differences in that SQL dump include:
- The actual generated table contents, due to timestamps and the like;
this is expected and unrelated to schema.
- Orders of fields within tables, which is not significant in SQL.
- IDs assigned to tables in the ContentType table, which is expected
and not a problem with how that Django table is designed.
- Names of generated indexes and constraints; modern Django seems to
abbreviate long names differently for these, and it's not obviously
possible to configure those used by the `db_index` property. If
necessarily, likely this can be converged via a migration filled
with `IF EXISTS` rename operations like the one done in
zerver/migrations/0246_message_date_sent_finalize_part2.py.
- Names of the ~3 sequences related to renamed tables:
usertopic/mutedtopic, botconfigdata/botuserconfigdata,
realmdomain/realmalias. Probably there's no action required here,
but we could do rename operations if desired.
2024-08-17 03:19:36 +02:00
- zerver/migrations/0001_squashed_0569.py
2020-06-05 10:10:37 +02:00
- zerver/migrations/0032_verify_all_medium_avatar_images.py
- zerver/migrations/0104_fix_unreads.py
- zerver/migrations/0206_stream_rendered_description.py
- zerver/migrations/0209_user_profile_no_empty_password.py
- zerver/migrations/0260_missed_message_addresses_from_redis_to_db.py
2022-04-01 02:25:27 +02:00
- zerver/migrations/0387_reupload_realmemoji_again.py
2023-12-06 06:09:58 +01:00
- zerver/migrations/0443_userpresence_new_table_schema.py
2023-12-01 08:20:48 +01:00
- zerver/migrations/0493_rename_userhotspot_to_onboardingstep.py
2020-06-05 10:10:37 +02:00
- pgroonga/migrations/0002_html_escape_subject.py
2020-05-02 08:44:14 +02:00
2024-04-29 16:57:13 +02:00
- id : use-addindexconcurrently
2024-04-29 21:56:45 +02:00
pattern : django.db.migrations.AddIndex(...)
2024-04-29 16:57:13 +02:00
message : "Import and use AddIndexConcurrently from django.contrib.postgres.operations rather than AddIndex"
languages : [ python]
severity : ERROR
paths :
include :
- "**/migrations"
exclude :
- analytics/migrations/0008_add_count_indexes.py
- zerver/migrations/0001_initial.py
migrations: Squash zerver migrations.
This has the impact of making rebuilding the database in a Zulip
development environment, or initializing a new production database,
dramatically faster.
This was generated by merging the output of `manage.py makemigrations`
with an empty migration.
Tested using `tools/rebuild-test-database` before and after this
change, and comparing the output of `pg_dump -d zulip_test` using
Git's diff comparison algorithm. Differences in that SQL dump include:
- The actual generated table contents, due to timestamps and the like;
this is expected and unrelated to schema.
- Orders of fields within tables, which is not significant in SQL.
- IDs assigned to tables in the ContentType table, which is expected
and not a problem with how that Django table is designed.
- Names of generated indexes and constraints; modern Django seems to
abbreviate long names differently for these, and it's not obviously
possible to configure those used by the `db_index` property. If
necessarily, likely this can be converged via a migration filled
with `IF EXISTS` rename operations like the one done in
zerver/migrations/0246_message_date_sent_finalize_part2.py.
- Names of the ~3 sequences related to renamed tables:
usertopic/mutedtopic, botconfigdata/botuserconfigdata,
realmdomain/realmalias. Probably there's no action required here,
but we could do rename operations if desired.
2024-08-17 03:19:36 +02:00
- zerver/migrations/0001_squashed_0569.py
2024-04-29 16:57:13 +02:00
- zerver/migrations/0082_index_starred_user_messages.py
- zerver/migrations/0083_index_mentioned_user_messages.py
- zerver/migrations/0095_index_unread_user_messages.py
- zerver/migrations/0098_index_has_alert_word_user_messages.py
- zerver/migrations/0099_index_wildcard_mentioned_user_messages.py
- zerver/migrations/0112_index_muted_topics.py
- zerver/migrations/0177_user_message_add_and_index_is_private_flag.py
- zerver/migrations/0180_usermessage_add_active_mobile_push_notification.py
- zerver/migrations/0268_add_userpresence_realm_timestamp_index.py
- zerver/migrations/0343_alter_useractivityinterval_index_together.py
- zerver/migrations/0351_user_topic_visibility_indexes.py
- zerver/migrations/0443_userpresence_new_table_schema.py
- zerver/migrations/0446_realmauditlog_zerver_realmauditlog_user_subscriptions_idx.py
- zerver/migrations/0449_scheduledmessage_zerver_unsent_scheduled_messages_indexes.py
- zilencer/migrations/0016_remote_counts.py
- zilencer/migrations/0017_installationcount_indexes.py
- zilencer/migrations/0029_update_remoterealm_indexes.py
- zilencer/migrations/0058_remoteinstallationcount_add_mobile_pushes_forwarded_index.py
- zilencer/migrations/0059_remoterealmauditlog_add_synced_billing_event_type_index.py
- id : use-removeindexconcurrently
2024-04-29 21:56:45 +02:00
pattern : django.db.migrations.RemoveIndex(...)
2024-04-29 16:57:13 +02:00
message : "Import and use RemoveIndexConcurrently from django.contrib.postgres.operations rather than RemoveIndex"
languages : [ python]
severity : ERROR
paths :
include :
- "**/migrations"
exclude :
- zerver/migrations/0473_remove_message_non_realm_id_indexes.py
- zerver/migrations/0486_clear_old_data_for_unused_usermessage_flags.py
- zilencer/migrations/0038_unique_server_remote_id.py
2023-03-21 07:10:20 +01:00
- id : html-format
languages : [ python]
pattern-either :
- pattern : markupsafe.Markup(... .format(...))
- pattern : markupsafe.Markup(f"...")
- pattern : markupsafe.Markup(... + ...)
severity : ERROR
message : "Do not write an HTML injection vulnerability please"
2020-05-04 01:56:44 +02:00
- id : sql-format
languages : [ python]
pattern-either :
- pattern : ... .execute("...".format(...))
2020-06-15 23:39:16 +02:00
- pattern : ... .execute(f"...")
2023-03-21 07:10:20 +01:00
- pattern : ... .execute(... + ...)
2020-05-04 01:56:44 +02:00
- pattern : psycopg2.sql.SQL(... .format(...))
2020-06-15 23:39:16 +02:00
- pattern : psycopg2.sql.SQL(f"...")
2023-03-21 07:10:20 +01:00
- pattern : psycopg2.sql.SQL(... + ...)
2020-06-14 03:48:07 +02:00
- pattern : django.db.migrations.RunSQL(..., "..." .format(...), ...)
2020-06-15 23:39:16 +02:00
- pattern : django.db.migrations.RunSQL(..., f"...", ...)
2023-03-21 07:10:20 +01:00
- pattern : django.db.migrations.RunSQL(..., ... + ..., ...)
2020-06-14 04:05:38 +02:00
- pattern : django.db.migrations.RunSQL(..., [..., "..." .format(...), ...], ...)
2020-06-15 23:39:16 +02:00
- pattern : django.db.migrations.RunSQL(..., [..., f"...", ...], ...)
2023-03-21 07:10:20 +01:00
- pattern : django.db.migrations.RunSQL(..., [..., ... + ..., ...], ...)
2020-05-04 01:56:44 +02:00
severity : ERROR
message : "Do not write a SQL injection vulnerability please"
2024-05-29 21:41:40 +02:00
paths :
exclude :
- zerver/migrations/0531_convert_most_ids_to_bigints.py
2020-06-13 05:24:42 +02:00
2020-10-17 02:53:53 +02:00
- id : translated-format-lazy
languages : [ python]
2021-04-16 00:57:30 +02:00
pattern : django.utils.translation.gettext_lazy(...).format(...)
2020-10-17 02:53:53 +02:00
severity : ERROR
message : "Immediately formatting a lazily translated string destroys its laziness"
2023-07-17 22:40:33 +02:00
- id : translated-positional-field
languages : [ python]
patterns :
- pattern-either :
- pattern : django.utils.translation.gettext("$MESSAGE")
- pattern : django.utils.translation.pgettext($CONTEXT, "$MESSAGE")
- pattern : django.utils.translation.gettext_lazy("$MESSAGE")
- pattern : django.utils.translation.pgettext_lazy($CONTEXT, "$MESSAGE")
- metavariable-regex :
metavariable : $MESSAGE
regex : (^|.*[^{])(\{\{)*\{[:!}].*
severity : ERROR
message : "Prefer {named} fields over positional {} in translated strings"
2020-06-14 07:01:21 +02:00
- id : percent-formatting
languages : [ python]
pattern-either :
- pattern : '"..." % ...'
2021-04-16 00:57:30 +02:00
- pattern : django.utils.translation.gettext(...) % ...
2023-07-17 22:40:33 +02:00
- pattern : django.utils.translation.pgettext(...) % ...
2021-04-16 00:57:30 +02:00
- pattern : django.utils.translation.gettext_lazy(...) % ...
2023-07-17 22:40:33 +02:00
- pattern : django.utils.translation.pgettext_lazy(...) % ...
2020-06-14 07:01:21 +02:00
severity : ERROR
message : "Prefer f-strings or .format for string formatting"
2020-06-26 02:35:16 +02:00
2021-02-14 00:03:40 +01:00
- id : change-user-is-active
languages : [ python]
patterns :
- pattern-either :
- pattern : |
$X.is_active = ...
- pattern : |
setattr($X, 'is_active', ...)
- pattern-not-inside : |
def change_user_is_active(...) :
...
message : "Use change_user_is_active to mutate user_profile.is_active"
severity : ERROR
2021-10-06 17:13:57 +02:00
paths :
exclude :
- zerver/migrations/0373_fix_deleteduser_dummies.py
2021-12-02 20:31:42 +01:00
- id : confirmation-object-get
languages : [ python]
patterns :
- pattern-either :
- pattern : Confirmation.objects.get(...)
- pattern : Confirmation.objects.filter(..., confirmation_key=..., ...)
- pattern-not-inside : |
def get_object_from_key(...) :
...
paths :
exclude :
- zerver/tests/
message : "Do not fetch a Confirmation object directly, use get_object_from_key instead"
severity : ERROR
2023-06-08 01:04:25 +02:00
- id : dont-make-batched-migration-atomic
patterns :
- pattern : |
class Migration(migrations.Migration) :
...
- pattern-inside : |
...
BATCH_SIZE = ...
...
- pattern-not : |
class Migration(migrations.Migration) :
atomic = False
paths :
include :
- "**/migrations"
message : 'A batched migration should not be atomic. Add "atomic = False" to the Migration class'
languages : [ python]
severity : ERROR
api: Add new typed_endpoint decorators.
The goal of typed_endpoint is to replicate most features supported by
has_request_variables, and to improve on top of it. There are some
unresolved issues that we don't plan to work on currently. For example,
typed_endpoint does not support ignored_parameters_supported for 400
responses, and it does not run validators on path-only arguments.
Unlike has_request_variables, typed_endpoint supports error handling by
processing validation errors from Pydantic.
Most features supported by has_request_variables are supported by
typed_endpoint in various ways.
To define a function, use a syntax like this with Annotated if there is
any metadata you want to associate with a parameter, do note that
parameters that are not keyword-only are ignored from the request:
```
@typed_endpoint
def view(
request: HttpRequest,
user_profile: UserProfile,
*,
foo: Annotated[int, ApiParamConfig(path_only=True)],
bar: Json[int],
other: Annotated[
Json[int],
ApiParamConfig(
whence="lorem",
documentation_status=NTENTIONALLY_UNDOCUMENTED
)
] = 10,
) -> HttpResponse:
....
```
There are also some shorthands for the commonly used annotated types,
which are encouraged when applicable for better readability and less
typing:
```
WebhookPayload = Annotated[Json[T], ApiParamConfig(argument_type_is_body=True)]
PathOnly = Annotated[T, ApiParamConfig(path_only=True)]
```
Then the view function above can be rewritten as:
```
@typed_endpoint
def view(
request: HttpRequest,
user_profile: UserProfile,
*,
foo: PathOnly[int],
bar: Json[int],
other: Annotated[
Json[int],
ApiParamConfig(
whence="lorem",
documentation_status=INTENTIONALLY_UNDOCUMENTED
)
] = 10,
) -> HttpResponse:
....
```
There are some intentional restrictions:
- A single parameter cannot have more than one ApiParamConfig
- Path-only parameters cannot have default values
- argument_type_is_body is incompatible with whence
- Arguments of name "request", "user_profile", "args", and "kwargs" and
etc. are ignored by typed_endpoint.
- positional-only arguments are not supported by typed_endpoint. Only
keyword-only parameters are expected to be parsed from the request.
- Pydantic's strict mode is always enabled, because we don't want to
coerce input parsed from JSON into other types unnecessarily.
- Using strict mode all the time also means that we should always use
Json[int] instead of int, because it is only possible for the request
to have data of type str, and a type annotation of int will always
reject such data.
typed_endpoint's handling of ignored_parameters_unsupported is mostly
identical to that of has_request_variables.
2023-07-28 08:34:04 +02:00
- id : typed_endpoint_without_keyword_only_param
patterns :
- pattern : |
@typed_endpoint
def $F(...)-> ... :
...
- pattern-not-inside : |
@typed_endpoint
def $F(..., *, ...)-> ... :
...
2024-08-15 10:45:39 +02:00
- pattern-not-inside : |
@typed_endpoint
def $F(..., *args, ...)-> ... :
...
api: Add new typed_endpoint decorators.
The goal of typed_endpoint is to replicate most features supported by
has_request_variables, and to improve on top of it. There are some
unresolved issues that we don't plan to work on currently. For example,
typed_endpoint does not support ignored_parameters_supported for 400
responses, and it does not run validators on path-only arguments.
Unlike has_request_variables, typed_endpoint supports error handling by
processing validation errors from Pydantic.
Most features supported by has_request_variables are supported by
typed_endpoint in various ways.
To define a function, use a syntax like this with Annotated if there is
any metadata you want to associate with a parameter, do note that
parameters that are not keyword-only are ignored from the request:
```
@typed_endpoint
def view(
request: HttpRequest,
user_profile: UserProfile,
*,
foo: Annotated[int, ApiParamConfig(path_only=True)],
bar: Json[int],
other: Annotated[
Json[int],
ApiParamConfig(
whence="lorem",
documentation_status=NTENTIONALLY_UNDOCUMENTED
)
] = 10,
) -> HttpResponse:
....
```
There are also some shorthands for the commonly used annotated types,
which are encouraged when applicable for better readability and less
typing:
```
WebhookPayload = Annotated[Json[T], ApiParamConfig(argument_type_is_body=True)]
PathOnly = Annotated[T, ApiParamConfig(path_only=True)]
```
Then the view function above can be rewritten as:
```
@typed_endpoint
def view(
request: HttpRequest,
user_profile: UserProfile,
*,
foo: PathOnly[int],
bar: Json[int],
other: Annotated[
Json[int],
ApiParamConfig(
whence="lorem",
documentation_status=INTENTIONALLY_UNDOCUMENTED
)
] = 10,
) -> HttpResponse:
....
```
There are some intentional restrictions:
- A single parameter cannot have more than one ApiParamConfig
- Path-only parameters cannot have default values
- argument_type_is_body is incompatible with whence
- Arguments of name "request", "user_profile", "args", and "kwargs" and
etc. are ignored by typed_endpoint.
- positional-only arguments are not supported by typed_endpoint. Only
keyword-only parameters are expected to be parsed from the request.
- Pydantic's strict mode is always enabled, because we don't want to
coerce input parsed from JSON into other types unnecessarily.
- Using strict mode all the time also means that we should always use
Json[int] instead of int, because it is only possible for the request
to have data of type str, and a type annotation of int will always
reject such data.
typed_endpoint's handling of ignored_parameters_unsupported is mostly
identical to that of has_request_variables.
2023-07-28 08:34:04 +02:00
message : |
@typed_endpoint should not be used without keyword-only parameters.
Make parameters to be parsed from the request as keyword-only,
or use @typed_endpoint_without_parameters instead.
languages : [ python]
severity : ERROR
api: Avoid programming errors due to nested Annotated types.
We want to reject ambiguous type annotations that set ApiParamConfig
inside a Union. If a parameter is Optional and has a default of None, we
prefer Annotated[Optional[T], ...] over Optional[Annotated[T, ...]].
This implements a check that detects Optional[Annotated[T, ...]] and
raise an assertion error if ApiParamConfig is in the annotation. It also
checks if the type annotation contains any ApiParamConfig objects that
are ignored, which can happen if the Annotated type is nested inside
another type like List, Union, etc.
Note that because
param: Annotated[Optional[T], ...] = None
and
param: Optional[Annotated[Optional[T], ...]] = None
are equivalent in runtime prior to Python 3.11, there is no way for us
to distinguish the two. So we cannot detect that in runtime.
See also: https://github.com/python/cpython/issues/90353
2023-08-17 00:35:10 +02:00
- id : dont-nest-annotated-types-with-param-config
patterns :
- pattern-not : |
def $F(..., invalid_param : typing.Optional[<... zerver.lib.typed_endpoint.ApiParamConfig(...) ...>], ...) -> ... :
...
- pattern-not : |
2024-07-12 02:30:25 +02:00
def $F(..., $A : typing.Annotated[<... zerver.lib.typed_endpoint.ApiParamConfig(...) ...>], ...) -> ... :
api: Avoid programming errors due to nested Annotated types.
We want to reject ambiguous type annotations that set ApiParamConfig
inside a Union. If a parameter is Optional and has a default of None, we
prefer Annotated[Optional[T], ...] over Optional[Annotated[T, ...]].
This implements a check that detects Optional[Annotated[T, ...]] and
raise an assertion error if ApiParamConfig is in the annotation. It also
checks if the type annotation contains any ApiParamConfig objects that
are ignored, which can happen if the Annotated type is nested inside
another type like List, Union, etc.
Note that because
param: Annotated[Optional[T], ...] = None
and
param: Optional[Annotated[Optional[T], ...]] = None
are equivalent in runtime prior to Python 3.11, there is no way for us
to distinguish the two. So we cannot detect that in runtime.
See also: https://github.com/python/cpython/issues/90353
2023-08-17 00:35:10 +02:00
...
- pattern-not : |
2024-07-12 02:30:25 +02:00
def $F(..., $A : typing.Annotated[<... zerver.lib.typed_endpoint.ApiParamConfig(...) ...>] = ..., ...) -> ... :
api: Avoid programming errors due to nested Annotated types.
We want to reject ambiguous type annotations that set ApiParamConfig
inside a Union. If a parameter is Optional and has a default of None, we
prefer Annotated[Optional[T], ...] over Optional[Annotated[T, ...]].
This implements a check that detects Optional[Annotated[T, ...]] and
raise an assertion error if ApiParamConfig is in the annotation. It also
checks if the type annotation contains any ApiParamConfig objects that
are ignored, which can happen if the Annotated type is nested inside
another type like List, Union, etc.
Note that because
param: Annotated[Optional[T], ...] = None
and
param: Optional[Annotated[Optional[T], ...]] = None
are equivalent in runtime prior to Python 3.11, there is no way for us
to distinguish the two. So we cannot detect that in runtime.
See also: https://github.com/python/cpython/issues/90353
2023-08-17 00:35:10 +02:00
...
- pattern-either :
- pattern : |
def $F(..., $A : $B[<... zerver.lib.typed_endpoint.ApiParamConfig(...) ...>], ...) -> ... :
...
- pattern : |
def $F(..., $A : $B[<... zerver.lib.typed_endpoint.ApiParamConfig(...) ...>] = ..., ...) -> ... :
...
message : |
Annotated types containing zerver.lib.typed_endpoint.ApiParamConfig should not be nested inside Optional. Use Annotated[Optional[...], zerver.lib.typed_endpoint.ApiParamConfig(...)] instead.
languages : [ python]
severity : ERROR
2023-09-07 18:22:41 +02:00
- id : exists-instead-of-count
patterns :
- pattern-either :
- pattern : ... .count() == 0
- pattern : |
if not ... .count() :
...
message : 'Use "not .exists()" instead; it is more efficient'
languages : [ python]
severity : ERROR
- id : exists-instead-of-count-not-zero
patterns :
- pattern-either :
- pattern : ... .count() != 0
- pattern : ... .count() > 0
- pattern : ... .count() >= 1
- pattern : |
if ... .count() :
...
message : 'Use ".exists()" instead; it is more efficient'
languages : [ python]
severity : ERROR
2023-09-11 20:22:32 +02:00
- id : functools-partial
pattern : functools.partial
2024-04-29 23:20:36 +02:00
message : "Replace functools.partial with zerver.lib.partial.partial for type safety"
2023-09-11 20:22:32 +02:00
languages : [ python]
severity : ERROR
2023-11-28 19:33:10 +01:00
- id : timedelta-positional-argument
patterns :
2024-04-29 21:56:45 +02:00
- pattern : datetime.timedelta(...)
- pattern-not : datetime.timedelta(0)
- pattern-not : datetime.timedelta(..., days=..., ...)
- pattern-not : datetime.timedelta(..., seconds=..., ...)
- pattern-not : datetime.timedelta(..., microseconds=..., ...)
- pattern-not : datetime.timedelta(..., milliseconds=..., ...)
- pattern-not : datetime.timedelta(..., minutes=..., ...)
- pattern-not : datetime.timedelta(..., hours=..., ...)
- pattern-not : datetime.timedelta(..., weeks=..., ...)
2023-11-28 19:33:10 +01:00
message : |
Specify timedelta with named arguments.
languages : [ python]
severity : ERROR
2023-11-28 19:16:58 +01:00
- id : time-machine
languages : [ python]
patterns :
2024-04-29 21:56:45 +02:00
- pattern : unittest.mock.patch("$FUNCTION", return_value=$TIME)
2023-11-28 19:16:58 +01:00
- metavariable-regex :
metavariable : $FUNCTION
regex : .*timezone_now
fix : time_machine.travel($TIME, tick=False)
severity : ERROR
message : "Use the time_machine package, rather than mocking timezone_now"
2023-12-05 21:25:00 +01:00
- id : urlparse
languages : [ python]
pattern-either :
- pattern : urllib.parse.urlparse
- pattern : urllib.parse.urlunparse
- pattern : urllib.parse.ParseResult
severity : ERROR
message : "Use urlsplit rather than urlparse"