| <!--- | |
| Licensed to the Apache Software Foundation (ASF) under one | |
| or more contributor license agreements. See the NOTICE file | |
| distributed with this work for additional information | |
| regarding copyright ownership. The ASF licenses this file | |
| to you under the Apache License, Version 2.0 (the | |
| "License"); you may not use this file except in compliance | |
| with the License. You may obtain a copy of the License at | |
| http://www.apache.org/licenses/LICENSE-2.0 | |
| Unless required by applicable law or agreed to in writing, | |
| software distributed under the License is distributed on an | |
| "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | |
| KIND, either express or implied. See the License for the | |
| specific language governing permissions and limitations | |
| under the License. | |
| --> | |
| (extension_checklist)= | |
| # Extension author checklist | |
| The rules in this section, gathered into one list to run through before you | |
| publish. Each links to the page that explains it. | |
| ## Protocol | |
| - [ ] **Every getter's capsule name matches its method name.** | |
| `__datafusion_<thing>__` returns a capsule named `datafusion_<thing>`. | |
| → {ref}`extension_capsule_protocol` | |
| - [ ] **Your getter does not inspect its argument.** Pass it to | |
| `ffi_logical_codec_from_pycapsule` and move on. It is not always a | |
| session, and when it is, it is not the Python `SessionContext` wrapper. | |
| → {ref}`extension_getter_argument` | |
| - [ ] **You never construct a `SessionContext` inside your library.** Take | |
| what the FFI constructors need off the argument you were handed. A | |
| context built inline is already dropped by the time the capsule is used. | |
| → {ref}`extension_getter_argument` | |
| - [ ] **You do not depend on the `datafusion-python` crate.** | |
| → {ref}`extension_why_ffi` | |
| ## Codecs | |
| - [ ] **Your codec claims narrowly.** Downcast to your own types. Claiming a | |
| broad category takes nodes from every library installed after you and | |
| makes your library order-sensitive for everyone downstream. | |
| → {ref}`extension_codec_order` | |
| - [ ] **You declare `__datafusion_codec_id__` if you might rename the class.** | |
| The default id is the exporting class's import path, so a rename stops | |
| older plans decoding. → {ref}`extension_codec_ids` | |
| - [ ] **Name-only decoders check `name` before trusting `buf`.** An empty | |
| payload has no id to route on, so your `try_decode_udf` can be called | |
| with another library's function name and an empty buffer. | |
| → {ref}`extension_codecs` | |
| - [ ] **You round-trip a plan in a test and assert *your* codec did the work.** | |
| Both being installed does not mean your node reached you. | |
| → {ref}`extension_codec_order` | |
| ## Bundles and planners | |
| - [ ] **You ship a bundle, not loose pieces**, if you have codecs, functions, | |
| or a planner. | |
| → {ref}`extension_bundles` | |
| - [ ] **Your bundle is configuration-only.** Fresh components on every call, | |
| no cached bound components, no retaining the context passed in, no | |
| registering anything on it — declare what you contribute instead. | |
| → {ref}`extension_bundles_transaction` | |
| - [ ] **Your codecs are objects exposing the getter, not bare capsules.** | |
| `with_extensions` refuses a capsule, because there would be nothing to | |
| name the codec by. → {ref}`extension_bundles_codecs_are_objects` | |
| - [ ] **Your planner hook wraps `fallback` and delegates to it.** Ignoring it | |
| replaces every layer beneath you, which is legal but not composable. | |
| → {ref}`extension_bundles` | |
| - [ ] **Your planner hook returns `None`, not `fallback`, when it has nothing | |
| to contribute.** Returning `fallback` installs the session's own planner | |
| as a foreign one and adds an FFI hop that was not there. | |
| → {ref}`extension_bundles` | |
| - [ ] **You read the host's codec chains in the planner hook, not the extension | |
| hook.** Phase one runs before anything is installed. | |
| → {ref}`extension_bundles_two_phases` | |
| - [ ] **If you also offer the low-level path**, document that codecs go in | |
| before a layered planner. → {ref}`planner_codec_rebinding` | |
| ## Packaging and documentation | |
| - [ ] **You state which `datafusion` version your release requires.** A | |
| mismatch raises an `ImportError` on import, which is a good failure — but | |
| only if your users know what to install. → {ref}`extension_version_mismatch` | |
| - [ ] **You tell your users to keep a context alive** for as long as anything | |
| derived from it is in use. This is the rule most likely to arrive as a | |
| bug report against your library. → {ref}`extension_sessions` | |
| - [ ] **Your production codec serializes durable metadata**, not a | |
| process-local token. The examples in this repository use tokens to make | |
| ownership observable; that is a demonstration, not a pattern. | |
| → {ref}`extension_codec_durable_metadata` | |
| - [ ] **You have integration tests across a real FFI boundary.** The two | |
| example crates in this repository are the pattern: build the cdylib, | |
| install the wheel, then exercise it from Python. |