zulip/zerver/lib
Zixuan James Li f4caf9dd79 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-09-08 08:20:17 -07:00
..
markdown widgets: Rename confusing attribute name in `tabbed_sections.py`. 2023-08-31 11:55:28 -07:00
upload ruff: Fix PIE808 Unnecessary `start` argument in `range`. 2023-09-01 14:57:01 -07:00
url_preview ruff: Fix UP032 Use f-string instead of `format` call. 2023-07-19 16:14:59 -07:00
webhooks ruff: Fix PERF401 Use a list comprehension to create a transformed list. 2023-08-07 17:23:55 -07:00
__init__.py
addressee.py users: Directly access id of foreign keys instead of full object. 2023-07-20 10:44:39 -07:00
alert_words.py alert_words: Refactor the code to flush alert_words cache. 2023-06-28 18:03:32 -07:00
async_utils.py
attachments.py upload: Rename delete_message_image to use word "attachment". 2023-03-02 16:36:19 -08:00
avatar.py settings: Make DEFAULT_LOGO_URI/DEFAULT_AVATAR_URI use staticfiles. 2023-02-14 17:17:06 -05:00
avatar_hash.py utils: Remove make_safe_digest wrapper. 2023-07-19 10:54:05 -07:00
bot_config.py ruff: Fix UP032 Use f-string instead of `format` call. 2023-08-02 15:58:55 -07:00
bot_lib.py black: Reformat with Black 23. 2023-02-02 10:40:13 -08:00
bot_storage.py python: Import F, Q, QuerySet from their canonical module. 2023-03-05 14:46:28 -08:00
bulk_create.py mypy: Upgrade mypy from 1.4.1 to 1.5.1. 2023-09-07 17:51:42 -07:00
cache.py ruff: Fix PERF401 Use a list comprehension to create a transformed list. 2023-08-07 17:23:55 -07:00
cache_helpers.py models: Fetch "recipient" object when along with "Huddle" object. 2023-08-10 17:35:43 -07:00
camo.py typing: Apply trivial none-checks with assertions as necessary. 2022-06-23 19:25:48 -07:00
ccache.py black: Reformat with Black 23. 2023-02-02 10:40:13 -08:00
compatibility.py ruff: Fix DTZ004 `datetime.datetime.utcfromtimestamp()`. 2023-01-04 16:25:07 -08:00
context_managers.py
create_user.py models: Add a unique index on UserProfile.api_key. 2023-05-19 11:11:04 -07:00
data_types.py ruff: Fix more of RUF010 Use conversion in f-string. 2023-06-06 14:58:11 -07:00
db.py python: Annotate type aliases with TypeAlias. 2023-08-07 10:02:49 -07:00
debug.py black: Reformat with Black 23. 2023-02-02 10:40:13 -08:00
default_streams.py streams: Pass stream_weekly_traffic field in stream objects. 2023-08-06 18:06:42 -07:00
dev_ldap_directory.py tests: Update tests to use example profile picture. 2022-10-31 14:36:54 -07:00
digest.py python: Annotate type aliases with TypeAlias. 2023-08-07 10:02:49 -07:00
display_recipient.py mypy: Improve type checks for user display recipients. 2023-08-10 18:13:43 -07:00
domains.py
drafts.py drafts: Access recipient_id when creating or editing Draft objects. 2023-08-10 17:35:43 -07:00
email_mirror.py mypy: Improve type checks for user display recipients. 2023-08-10 18:13:43 -07:00
email_mirror_helpers.py
email_notifications.py demo-orgs: Create dev environment demo organization without email. 2023-08-31 15:02:16 -07:00
email_validation.py black: Reformat with Black 23. 2023-02-02 10:40:13 -08:00
emoji.py python: Convert translated positional {} fields to {named} fields. 2023-07-18 15:19:07 -07:00
emoji_utils.py emoji: Match emoji sequences in markdown. 2023-08-23 16:18:15 -07:00
event_schema.py invite: Add new setting for "Who can create multiuse invite links". 2023-09-07 14:21:01 -07:00
events.py invites: Rename `can_invite_others_to_realm` local variables. 2023-09-07 14:21:01 -07:00
exceptions.py api: Add new typed_endpoint decorators. 2023-09-08 08:20:17 -07:00
export.py migration: Rename extra_data_json to extra_data in audit log models. 2023-08-16 17:18:14 -07:00
external_accounts.py ruff: Fix SIM118 Use `k not in d` instead of `k not in d.keys()`. 2023-07-24 10:39:28 -07:00
fix_unreads.py ruff: Fix PERF401 Use a list comprehension to create a transformed list. 2023-08-07 17:23:55 -07:00
generate_test_data.py ruff: Fix PERF401 Use a list comprehension to create a transformed list. 2023-08-07 17:23:55 -07:00
github.py ruff: Fix RSE102 Unnecessary parentheses on raised exception. 2023-02-04 16:34:55 -08:00
home.py narrow: Split out narrow_helpers. 2023-06-30 11:26:23 -07:00
hotspots.py ruff: Fix SIM118 Use `key in dict` instead of `key in dict.keys()`. 2023-01-04 16:25:07 -08:00
html_diff.py html_diff: Fix lxml import. 2023-03-05 14:46:28 -08:00
html_to_text.py widgets: Rename confusing attribute name in `tabbed_sections.py`. 2023-08-31 11:55:28 -07:00
i18n.py django: Use HttpRequest.headers. 2022-05-13 20:42:20 -07:00
import_realm.py invite: Add new setting for "Who can create multiuse invite links". 2023-09-07 14:21:01 -07:00
initial_password.py
integrations.py integrations: Extract integration event types returning function. 2023-08-30 15:54:13 -07:00
logging_util.py ruff: Fix PLR1714 Consider merging multiple comparisons. 2023-07-23 15:21:33 -07:00
management.py send_custom_email: Stop turning every user query into an id-based set. 2023-08-09 15:49:49 -07:00
mdiff.py node_tests: Move to web/tests. 2023-02-23 16:04:17 -08:00
mention.py mention: Determine @topic mention during message rendering. 2023-07-13 11:34:48 -07:00
message.py bulk_access_messages_expect_usermessage: Fix function name and comments. 2023-08-25 14:10:27 -04:00
migrate.py
mobile_auth_otp.py
muted_users.py muted users: Make file naming consistent. 2023-02-10 15:39:57 -08:00
name_restrictions.py name_restrictions: Update disposable_email_domains usage. 2023-07-19 16:14:59 -07:00
narrow.py Revert "narrow: Fix topic highlighting issue with apostrophes in search results." 2023-08-15 17:51:03 -07:00
narrow_helpers.py narrow: Split out narrow_helpers. 2023-06-30 11:26:23 -07:00
notes.py notes: Separate __notes_map per-subclass. 2022-10-10 08:42:13 -07:00
notification_data.py notifications: Rename 'pm' to 'dm' in 'RecipientInfoResult' dataclass. 2023-08-10 17:41:49 -07:00
onboarding.py message: Access realm from SendMessageRequest object directly. 2023-08-23 11:38:32 -07:00
outgoing_http.py
outgoing_webhook.py outgoing_webhook: Respect settings.OUTGOING_WEBHOOK_TIMEOUT_SECONDS. 2023-05-16 07:00:37 -07:00
per_request_cache.py per-request caches: Add per_request_cache library. 2023-08-11 11:09:34 -07:00
presence.py presence: Support null values in UserPresence. 2023-04-26 14:26:47 -07:00
profile.py
push_notifications.py mypy: Upgrade mypy from 1.4.1 to 1.5.1. 2023-09-07 17:51:42 -07:00
pysa.py
queue.py bots: Remove private stream subscriptions on changing bot owner. 2023-08-16 15:37:37 -07:00
rate_limiter.py ruff: Fix PERF102 Using only the keys/values of a dict. 2023-08-07 17:23:55 -07:00
realm_description.py
realm_icon.py settings: Make DEFAULT_LOGO_URI/DEFAULT_AVATAR_URI use staticfiles. 2023-02-14 17:17:06 -05:00
realm_logo.py settings: Make DEFAULT_LOGO_URI/DEFAULT_AVATAR_URI use staticfiles. 2023-02-14 17:17:06 -05:00
recipient_users.py models: Remove get_huddle_recipient and use get_or_create_huddle. 2023-08-10 17:35:43 -07:00
redis_utils.py
remote_server.py python: Convert translated positional {} fields to {named} fields. 2023-07-18 15:19:07 -07:00
request.py ruff: Fix FLY002 Consider f"…" instead of string join. 2023-08-07 17:12:41 -07:00
response.py webhooks: Use 200 status code for unknown events. 2023-07-11 13:51:37 -07:00
rest.py ruff: Fix RSE102 Unnecessary parentheses on raised exception. 2023-02-04 16:34:55 -08:00
retention.py retention: Do not archive attachments with scheduled messages. 2023-08-06 13:40:02 -07:00
safe_session_cached_db.py
scheduled_messages.py scheduled_messages: Add reasonable failure handling. 2023-05-09 13:48:28 -07:00
scim.py users: Set tos_version to -1 for users who have not logged-in yet. 2023-05-16 13:52:56 -07:00
scim_filter.py
send_email.py send_email: Provide the realm and string_id, for ease of "if" logic. 2023-08-30 11:54:28 -07:00
server_initialization.py invite: Add new setting for "Who can create multiuse invite links". 2023-09-07 14:21:01 -07:00
sessions.py typing: Add none-checks for miscellaneous cases. 2022-05-31 09:43:55 -07:00
singleton_bmemcached.py requirements: Upgrade Python requirements. 2023-04-03 22:39:21 -07:00
soft_deactivation.py notification_trigger: Rename `private_message` to `direct_message`. 2023-08-10 17:41:49 -07:00
sounds.py
sqlalchemy_utils.py
storage.py ruff: Fix PLE0101 Explicit return in `__init__`. 2023-02-23 11:47:08 -08:00
stream_color.py
stream_subscription.py topic_mentions: Fetch users to be notified of @topic mentions. 2023-07-13 11:34:48 -07:00
stream_topic.py message_send: Handle notifications for UNMUTED topic in a muted stream. 2023-03-06 19:15:45 -08:00
stream_traffic.py stream_traffic: Update get_streams_traffic to return None for zephyr realm. 2023-08-21 15:21:58 -07:00
streams.py streams: Extract some code out of do_get_streams in a new function. 2023-08-25 12:56:36 -07:00
string_validation.py python: Convert translated positional {} fields to {named} fields. 2023-07-18 15:19:07 -07:00
subdomains.py settings: Allow customization of STATIC_URL. 2023-02-14 17:17:06 -05:00
subscription_info.py streams: Don't compute traffic data for sub objects in zephyr realm. 2023-08-21 15:21:58 -07:00
templates.py requirements: Upgrade Python requirements. 2023-04-03 22:39:21 -07:00
test_classes.py mypy: Upgrade mypy from 1.4.1 to 1.5.1. 2023-09-07 17:51:42 -07:00
test_console_output.py requirements: Upgrade Python requirements. 2023-04-25 21:20:33 -07:00
test_data.source.txt
test_fixtures.py ruff: Fix ANN204 missing return type annotation for __init__. 2022-11-16 09:29:11 -08:00
test_helpers.py user_groups: Make locks required for updating user group memberships. 2023-08-24 17:21:08 -07:00
test_runner.py python: Annotate type aliases with TypeAlias. 2023-08-07 10:02:49 -07:00
tex.py
thumbnail.py docs: Remove some outdated references to thumbnailing.md doc. 2022-07-12 17:44:24 -07:00
timeout.py test_timeout: Skip test_timeout_warn on Python 3.11 for coverage issue. 2023-05-18 11:52:22 -07:00
timestamp.py timestamp: Switch to a slightly faster datetime_to_timestamp. 2023-02-23 12:15:13 -08:00
timezone.py timezone: Improve tzdata parser’s compatibility with zic(8). 2022-09-20 16:58:31 -07:00
topic.py topic: Set a max batch_size on bulk_upate call. 2023-08-14 13:33:20 -07:00
transfer.py uploads: Allow uploads to set storage class. 2023-07-19 16:19:34 -07:00
typed_endpoint.py api: Add new typed_endpoint decorators. 2023-09-08 08:20:17 -07:00
types.py settings: Disallow everyone group for new setting. 2023-09-07 14:21:01 -07:00
url_encoding.py narrow urls: Avoid complicated optional types. 2023-08-10 18:13:43 -07:00
url_redirects.py help: Rename edit-or-delete-a-message.md and update links. 2023-08-22 14:50:23 -07:00
user_agent.py
user_counts.py
user_groups.py settings: Disallow everyone group for new setting. 2023-09-07 14:21:01 -07:00
user_message.py
user_status.py black: Reformat with Black 23. 2023-02-02 10:40:13 -08:00
user_topics.py user_topics: Update 'topic_has_visibility_policy' to support INHERIT. 2023-04-18 16:40:57 -07:00
users.py ruff: Fix PERF401 Use a list comprehension to create a transformed list. 2023-08-07 17:23:55 -07:00
utils.py utils: Remove make_safe_digest wrapper. 2023-07-19 10:54:05 -07:00
validator.py api: Add new typed_endpoint decorators. 2023-09-08 08:20:17 -07:00
widget.py ruff: Fix B034 `re.split`, `re.sub` should pass keyword arguments. 2023-07-19 16:14:59 -07:00
zcommand.py ruff: Fix UP032 Use f-string instead of `format` call. 2023-08-02 15:58:55 -07:00
zephyr.py