Compare commits

...

196 Commits

Author SHA1 Message Date
Ian Chua
3dae6f45e8 fix: keep orphaned cloud plugins runnable 2026-07-20 18:33:20 +08:00
Noisyfox
c6f06ab600 Fix OpenGL framebuffer EXT support (#14794)
* Call proper EXT variant of the function if framebuffer type is EXT

* Update glad with `GL_EXT_framebuffer_blit` and `GL_EXT_framebuffer_multisample` extensions support
2026-07-20 09:05:21 +08:00
SoftFever
4e69c6a203 Fix macOS Xcode-generator build broken by bundled Python signing
Xcode's CodeSign phase rejects the bundled Python runtime's dotted dirs under Contents/MacOS. Disable it for the Xcode generator so the linker ad-hoc signs local dev builds; CI (Ninja) and the notarized bundle are unaffected.
2026-07-19 23:12:34 +08:00
SoftFever
90ecdb8f03 Fix macOS dark-theme rendering and AMS settings icon clipping (#14846)
Fixes a set of Mac only GUI rendering issues:
1. cropped icon
2. wrong color in dark theme
## Screenshots

<img width="343" height="370" alt="Screenshot 2026-07-19 at 16 16 39"
src="https://github.com/user-attachments/assets/1b89dc01-cd52-43ff-9231-ac31a7e1c18f"
/>
<img width="701" height="700" alt="Screenshot 2026-07-19 at 13 19 02"
src="https://github.com/user-attachments/assets/00fa173f-dea9-4b87-8ac8-ae311dca5c31"
/>
<img width="425" height="324" alt="Screenshot 2026-07-19 at 02 31 14"
src="https://github.com/user-attachments/assets/50740669-d5c0-4309-b0ac-b577a460cc91"
/>
<img width="1121" height="890" alt="Screenshot 2026-07-19 at 02 24 33"
src="https://github.com/user-attachments/assets/9ab380e3-63f6-41a1-9c2c-8d0247bd036f"
/>
2026-07-19 20:27:14 +08:00
SoftFever
f7f0c82abb Fix dark-theme backgrounds across device, HMS, and AMS UI on macOS
Give previously-bare panels a keyed background so the existing dark-UI walk
can theme them. Runtime-created widgets (HMS items, device firmware/nozzle
panels) route their whole subtree through one UpdateDarkUIWin(this) call
instead of per-widget darkModeColorFor, which also themes their child text
and follows live light/dark switches. Extruder-card chips re-apply their
colours from Sidebar::sys_color_changed so a live switch updates them too.
2026-07-19 20:16:17 +08:00
SoftFever
bd854c5ce5 Fix AMS settings icon clipping on macOS 2026-07-19 18:36:52 +08:00
SoftFever
edab1c0dc1 Support the 02.08.01 network plug-in and resync the Bambu device workflow (#14837)
# Description

Support the 02.08.01 network plug-in and resync the Bambu device
workflow

Brings the Bambu network plug-in up to the 02.08.01 series and reworks
the plug-in
lifecycle around it (ABI gating, OTA install, hot reload), then catches
the device and
monitor side up to what that plug-in and current firmware expose — AMS
mapping, send-flow
checks, print options, and the device status pages.

**Included:**

_Network plug-in_
- Default to the 02.08.01 series and bind its new ABI symbols; bump the
reported
  `SLIC3R_VERSION` to 02.08.01.55
- Gate loading to ABI-compatible `AA.BB.CC` series, and store plug-in
identity by series
  rather than by exact build
- Fix the OTA update flow: install immediately, hot-reload without a
restart, and destroy
  the agent before unloading the DLL
- Version selector lists same-series OTA builds newest first, with
dynamic
  "(Latest)" / "(installed)" labels
- Restart printer discovery and reload saved LAN printers after a hot
reload

_Device layer_
- Move axis, calibration, chamber, status and upgrade handling into
DeviceCore; drop the
  transitional shims
- Resync the DeviceCore state models, accessory firmware versions,
cold-pull state and
  filament checks

_Device UI_
- Resync the AMS control/item widgets, device dialogs, device tab
widgets and status pages
- Add the AMS best-position popup, filament-change stop button, hub
version row and HMS
  fallback
- Device error dialog: print-failure snapshot, purification and
don't-remind actions

_Send flow_
- Resync the send flow and port the remaining pre-send checks and
advisories
- Warn when a filament will switch extruders mid-print; block TPU on the
l
  without firmware support (O1D/O1E)
- Map switch-bound AMS trays to both extruders and show combined nozzle
mapping
- Add the shared-PA-profile toggle

_Print options / timelapse_
- Restructure DevPrintOptions around a detection-option map and parse
the
  bits on the live push path
- Add firmware print-option toggles, plus timelapse storage-location
selection with a
  free-space check

_Fixes_
- Inverted MQTT jog on i3-architecture printers, plus assorted popup,
mapping and
  status-parse defects

_Tests_
- New Catch2 coverage for network version selection and device filament
mapping

Printers that don't advertise the new capabilities are unaffected —
every added behavior is
gated on a firmware or plug-in capability flag, and the only profile
chang
`support_print_check_firmware_for_tpu_left` to O1D/O1E.

# Screenshots/Recordings/Graphs

<img width="714" height="500" alt="image"
src="https://github.com/user-attachments/assets/33e54581-3fb0-4a3e-b80c-afa8adfabe4c"
/>

<img width="530" height="212" alt="image"
src="https://github.com/user-attachments/assets/d0c55fd5-74c3-4aab-81a5-786d0aaf8828"
/>

<img width="483" height="527" alt="image"
src="https://github.com/user-attachments/assets/71ceaad1-a082-41cb-aa1a-4b9abb30d9db"
/>


## Tests

<!--
> Please describe the tests that you have conducted to verify the
changes made in this PR.
-->

<!--
> A guide for users on how to download the artifacts from this PR.
-->

[How to Download Pull Requests Artifacts for
Testing](https://www.orcaslicer.com/wiki/how_to_download_pr_artifacts)
2026-07-19 17:10:35 +08:00
Noisyfox
bb3e18c211 Fix deps python3 build failure on Windows (#14831)
* Fix deps python3 build failure on Windows

* Fix build on other platforms
2026-07-19 12:23:37 +08:00
SoftFever
8ee6095e08 fix ci test errors 2026-07-19 12:07:58 +08:00
Rodrigo Faselli
b2a7197a07 Floating final purge line fix (#14416) 2026-07-18 20:05:31 -03:00
Kiss Lorand
d6ca71be95 Fix skirt and brim handling for duplicated objects (instances) (#14683) 2026-07-18 19:57:56 -03:00
SoftFever
779768d76e update hms 2026-07-19 02:18:36 +08:00
SoftFever
3926475bb7 Fix nightly Linux test build and macOS signing after Python plugins merge
Export wxWidgets include dirs and defines from libslic3r_gui on Linux so
tests outside src/ compile against its GUI headers. Relocate the bundled
Python runtime to Contents/Resources with a Contents/MacOS/python symlink
(codesign cannot seal the dotted python3.12 dirs under Contents/MacOS) and
replace the deprecated codesign --deep with explicit inside-out signing of
every Mach-O in the bundle.
2026-07-19 01:47:59 +08:00
SoftFever
3ad69da028 bump SLIC3R_VERSION 2026-07-19 00:33:53 +08:00
SoftFever
afb4505ea7 Store network plug-in identity by AA.BB.CC series
The stored plug-in identity is now the AA.BB.CC series (matching BambuStudio)
rather than the full build version, so the meaningless 4th build digit stops
driving config, the whitelist, filenames, and the version selector. This fixes
the macOS "can't switch to an older build" bug: the cloud endpoint is
series-keyed and only ever serves a series' newest build, so downgrade-by-
download was impossible and the download silently adopted the latest.

A startup migration normalizes an existing full-version config and file name to
the series form with no re-download, the loader resolves a bare series to the
newest same-series build on disk, and user-provided custom-named plug-ins
(libbambu_networking_02.08.01_custom.*) are still enumerated and loaded.
2026-07-19 00:26:05 +08:00
SoftFever
2804e06cf2 Sort network plug-in versions newest first and mark only the loaded build
Discovered builds were inserted positionally behind the whitelist entry they
anchored to, so an OTA-installed 02.08.01.53 listed below 02.08.01.52. The list
is now built by appending and sorting once, which also drops the per-entry
insertion scans.

"(installed)" tested whether the library was present on disk, so it marked every
version ever selected - switching leaves the previous library in place. The flag
is now is_loaded, resolved against the plug-in actually loaded, and the two
combo populators share one label helper.
2026-07-18 16:23:50 +08:00
SoftFever
8b60291ed9 Restart printer discovery after a network-plugin hot reload
restart_networking() rebuilds m_agent with a null printer agent, so the bare
m_agent->start_discovery() no-oped (NetworkAgent::start_discovery returns false when
m_printer_agent is null) and LAN discovery stayed dead until the user next changed a
preset. Call switch_printer_agent() instead - it installs the printer agent for the
active preset and then starts discovery, mirroring startup.
2026-07-18 15:16:15 +08:00
SoftFever
5028a5000e Load saved LAN printers when the device manager first gets an agent
When the network plugin is not yet installed at startup, on_init_network builds
the DeviceManager without an agent, so its constructor skips loading the persisted
LAN printers. After the plugin is installed and the network stack hot-reloads, the
manager is reused via set_agent(), which never loaded them - so previously paired
printers stayed missing from the device list until an app restart. Load them once a
real agent first arrives.
2026-07-18 15:16:06 +08:00
SoftFever
01f2af94a1 fix build errors 2026-07-18 03:15:11 +08:00
Ian Bassi
a6226ba9cb Localization update (#14822)
Co-authored-by: sharanchius <41115839+sharanchius@users.noreply.github.com>
2026-07-17 15:46:28 -03:00
SoftFever
8d9b08fed9 Merge branch 'main' into feature/bambu_printer_housekeeping 2026-07-18 02:43:38 +08:00
mgoiogana
e86913266b Add Basque (eu) localization (#14782) 2026-07-17 15:27:44 -03:00
Andrij Mizyk
9020b61e9f Update Ukrainian translation (#14819)
Co-authored-by: Ian Bassi <ian.bassi@outlook.com>
2026-07-17 15:11:40 -03:00
SoftFever
ddfa961111 Merge branch 'main' into feature/bambu_printer_housekeeping
# Conflicts:
#	tests/slic3rutils/CMakeLists.txt
2026-07-18 02:08:13 +08:00
SoftFever
0b4cb89f7c Remove porting jargon and provenance notes from comments 2026-07-18 01:46:23 +08:00
SoftFever
4683c17f6f Fix device popup, mapping, and status-parse defects
- Allow mapping to EMPTY trays only from the multi-machine send page and keep
  both panels pickable in the LEFT_AND_RIGHT view
- Guard the error-dialog cloud snapshot against stale callbacks and fall back
  to the local illustration on timeout
- Parse the ipcam storage-check ack and axis/chamber pushes defensively
- Strip fan-control telemetry, initialize the upgrade error code, restore the
  .json filter in the model-id scan
- Fix best-position popup tray lookup, gradient placement, and colour-list
  ownership
- Cover switch binding sets and invalid-track transients in DevMapping tests
2026-07-18 01:46:10 +08:00
SoftFever
12720ccbd8 Gate network plugin loading to ABI-compatible series
Trim the version whitelist to the latest series plus the pinned legacy build,
and reject out-of-series configured versions at startup, compatibility check,
and load failure - falling back to the latest installed build or the clean
re-download flow so the config never keeps pointing at an unsupported build.
2026-07-18 01:45:54 +08:00
SoftFever
88fb89b5eb Plugin audit (#14821)
* Block plugins from reading or writing app config and cloud credentials

Add a denied-filename registry to the plugin audit sandbox, seeded with OrcaSlicer's config (.conf/.ini) and the cloud refresh-token file. The deny is checked above the loading-mode read exemption and the allowed roots, so a plugin cannot reach these files even though they sit inside data_dir(), which is itself an allowed root. Case-insensitive prefix matching also covers the .bak/.tmp companions that hold the same data, and os.rename/os.remove are hooked alongside open so the files cannot be deleted or clobbered either.
2026-07-18 01:24:44 +08:00
SoftFever
2717c37f63 feat: Python Plugins (#14530)
# Introducing a Python Plugin System (WIP)

This PR opens up a way to extend OrcaSlicer with **Python plugins** —
small scripts (or full wheels) that run inside an embedded CPython
interpreter, without anyone having to fork the app or touch the C++
core.

I'm putting this up **early and on purpose**. It works end-to-end today,
but it is not finished and the public surface is deliberately small.
Before we lock anything in, we want the community's opinions on the
three decisions that are hard to reverse later: **what API we expose,
which plugin types we invest in, and how the security/audit layer should
behave.** Consider this a request for comments more than a merge
candidate.

## Why

People keep wanting to bolt their own behavior onto the slicer — custom
G-code post-processing, automation, bespoke printer/host integrations,
one-off analysis. Today that means maintaining a patched fork. The goal
here is a *sanctioned* extension path: a stable, documented seam where a
plugin can hook into a specific point in OrcaSlicer's workflow, with a
clear boundary around what plugin code is allowed to do.

## What's in this PR

**An embedded Python runtime.** A single CPython interpreter is started
once (intended to be on the main thread), with proper GIL handoff so
plugin code can run from worker threads. Plugin `stderr` (including
tracebacks from threads a plugin spawns) is persisted to
`data_dir()/log/python_*.log`.

**One API module, `orca`.** This is the surface a plugin sees. It
exposes the plugin base classes, the `@orca.plugin` decorator and
`register_capability()`, a typed `ExecutionResult`, and the
`PluginType`/`PluginResult` enums, along with per-type base classes
under `orca.gcode` / `orca.script` / `orca.printer_agent`. A host
bridge, `orca.host`, provides **read-only** access to the current model
and preset/config values, plus interactive `host.plater()` and `host.ui`
helpers (messages, dialogs, windows, progress). There is deliberately no
*write* access to slicer models or config, and no general GUI/toolkit
access beyond these host helpers. The exact shape of `orca.host` is one
of the things we most want feedback on.

**Three plugin types to start:**
- `post-processing` — runs during G-code export and receives the G-code
path + output context.
- `script` — a manual "Run" action from the Plugins dialog.
- `printer-connection` — a Python "printer agent" that registers into
the network layer on load. This is still WIP, along with a printer agent
workflow that is also WIP.

(The `PluginType` enum reserves several more names — Automation,
Analysis, Importer, Exporter, Visualization — but only the three above
are wired up.)

**Two packaging forms:** a single `.py` file with [PEP
723](https://peps.python.org/pep-0723/) inline metadata, or a `.whl`
wheel (with third-party dependencies installed via a bundled `uv`).

**Discovery, install, and a Plugins dialog** — local side-loading plus a
cloud subscription service, catalog/loader lifecycle, and per-plugin
error reporting in the UI.

**Audit-hook groundwork (PEP 578).** Every C++→Python call opens a
per-call audit context, and a CPython audit hook filters filesystem
access against a write allow-list (`data_dir()`, plus scoped roots like
the current G-code folder). This is *groundwork, not a sandbox* — see
Limitations.

**Docs.** Substantially complete author and contributor guides live
under `docs/plugins/` (development guide, security/audit deep-dive,
architecture overview, worked examples); the *feature* is what's WIP,
not the docs.

## Orca Cloud integration

Plugins are **fully integrated with Orca Cloud**, distributed in a
similar way to preset bundles — so this builds directly on the cloud
foundation rather than bolting on a separate mechanism.

- **Subscribe, don't side-load.** Instead of manually copying files, you
subscribe to a plugin from the cloud and OrcaSlicer pulls it down and
loads it for you — the same one-click experience as preset bundles.
- **Tied to your account, synced across machines.** Subscribed plugins
live under your user (`orca_plugins/_subscribed/<user_id>/`) and follow
you to any machine you're signed in on, exactly like your presets. Sign
out and the cloud plugins are unloaded; sign back in and they're
restored.
- **Stays up to date.** When a new version is published, OrcaSlicer can
fetch and install the update rather than leaving you on a stale copy.
- **Managed from the Plugins dialog.** Browse, install, update, and
unsubscribe live alongside local side-loading — which still works for
development and private plugins.
- **Integrated with presets.** Plugin references travel with a preset
bundle (via the preset's `plugins` fields), so publishing a preset that
uses plugins carries those references through the existing cloud sync.
If a referenced plugin is missing when you install the bundle on another
machine, OrcaSlicer **offers to install** the missing plugins for you (a
one-click prompt), provided those plugins are on the cloud.

## Where we need feedback

Really any form of feedback would be helpful; we'd rather grow this
slowly from real use cases than expose internals we can't keep stable —
which is why the current surface is kept small. The `orca.host` API in
particular is where we'd most value opinions.

## Limitations / known gaps (it's WIP)

- **The audit hook is not a sandbox.** It currently enforces only the
`open` event's writes, and only for string paths (fd/bytes opens are not
checked). `subprocess`, sockets, `ctypes`, `os.open`, and non-`open`
filesystem mutations (`os.remove`/`rename`/`mkdir`) are **not** blocked
yet. An `Enforcing` mode is stubbed but not yet wired, so today all
calls run in the writes-only "loading" mode. More details can be found
[here](https://www.orcaslicer.com/wiki/developer_reference/plugin_development/plugin_audit_hook.html#limitations).
- **The `orca` API is unstable** and will change based on this
discussion. Don't build anything load-bearing on it yet.
- The `requires-python` field is parsed but not enforced.
- Dependency install and some of the Plugins dialog UX are functional
but still rough around the edges.

## Docs
[How to
Use](https://www.orcaslicer.com/wiki/plugins/getting_started.html)
[Developer
Reference](https://www.orcaslicer.com/wiki/developer_reference/plugin_development/plugin_system.html)

## Software Development Kit
Currently, there is a script `generate_orca_python_stubs.py` to generate
the `.pyi` files that can be used for intellisense. We will release the
stub file as an SDK in future releases, but for now, if you intend to
develop plugins, you can generate the stub files locally.

## Notes

This system was developed primarily on Windows and Linux; testing on
macOS has so far been limited. macOS-specific behavior — the bundled
Python/`uv` runtime, path handling, and the audit hook — is the most
likely to need attention, and feedback or testing from macOS users is
especially welcome.

[How to Download Pull Requests Artifacts for
Testing](https://www.orcaslicer.com/wiki/how_to_download_pr_artifacts)

## Orca Cloud to OrcaSlicer Plugins Workflow Overview:


https://github.com/user-attachments/assets/abbd7900-3062-4e33-8f77-5d30d567be1d
2026-07-17 23:39:18 +08:00
SoftFever
3576ed6445 Merge branch 'main' into feat/plugin-feature 2026-07-17 23:38:34 +08:00
SoftFever
ee2e7e7a28 Add actions speed dial to run plugin scripts (#14697)
# Description

Use Space to trigger a new **speed dial**, which allows users to run
**app actions**. The only app actions implemented currently are python
plugin scripts.

## Notes

- Only toggleable in the Prepare (3D) view. Press Space, type to filter,
Enter or double-click to run.
- Focuses on search bar automatically
- Frecency-sorted (run count + recency) with alphabetical fallback (C++
computes)
- Pin actions as favourites and they will show on the top favourites
bar. Done through star icon on each row.
- Script plugins have no icon art yet, so tiles show a collision-aware
monogram: the capability's initial, escalating only when names collide -
prepend the package initial, then add an ordinal - so same-named actions
from different plugins stay distinguishable.
- E.g., capability Bravo from plugin Alpha normally shows just B. If
another action's name also starts with B, they disambiguate by
prepending the package initial (Alpha -> AB). If two still collide on
both initials (both AB), they become AB1 and AB2.
- "Run X?" confirm with a per-plugin "don't ask again" scope, owned
C++-side; suppression persists.
- Persistence (`speed_dial` AppConfig section): `favourite_actions`
(ordered id list) + per-action `stats` + `ask_suppressed`.

- Example of shape in data_dir:
```json
{
    "speed_dial": {
        "ask_suppressed": "[\"9b12aa079924bbc4\"]",
        "favourite_actions": "[\"ccfdf8b9e492b624\",\"9b12aa079924bbc4\",\"b7abfa67626248e4\"]",
        "stats": "{\"31d9d129a616a8b7\":{\"count\":4,\"last\":1783924989},\"53ec17d430634f62\":{\"count\":3,\"last\":1783939329},\"9b12aa079924bbc4\":{\"count\":5,\"last\":1783924981},\"9f2cb0d3ca56a87c\":{\"count\":1,\"last\":1783668370},\"b7abfa67626248e4\":{\"count\":4,\"last\":1783939325},\"f93469da14248128\":{\"count\":3,\"last\":1783939337}}"
	},
}
```

# Screenshots/Recordings/Graphs

<img width="688" height="335" alt="image"
src="https://github.com/user-attachments/assets/683efa3b-9401-4977-a347-d70193188165"
/>

<img width="681" height="172" alt="image"
src="https://github.com/user-attachments/assets/fafb4965-054b-4fd5-ad6a-03145264fbe0"
/>

<img width="683" height="335" alt="image"
src="https://github.com/user-attachments/assets/00d5bd49-95c0-4f2f-966b-6c04c14c3cf3"
/>


## Tests

- **Web layer (green):** node-vm logic test `test-speeddial-logic.js`
covers `filterActions`, `visibleFavourites` (incl. the runnable guard),
`selectedActionId`, `resultCountText`, `actionLabel`, `tileCode`,
`nextSel`, and payload seeding - pure helpers, DOM-free.
- **Backend:** `ActionRegistry` FNV-1a id golden-vector Catch2 test
(`test_speed_dial_action_id`) pins the hash; the registry was verified
by fresh-context review including a threading fix (`run()` operates on a
stack copy so a queued refresh can't reallocate the action vector
mid-run).
- **Manual (all passing):**
- Space opens the dial in Prepare only; no regression to existing
Prepare-tab keys or the Plugins dialog.
- Search auto-focuses; typing filters live; a freshly-run action rises
in the frecency order.
- Up jumps to the favourites bar, Down into the list, Alt+1..9 hits
favourites; Enter and double-click run the highlighted action.
- Star pins/unpins an action; favourites persist across an app restart.
- "Run X?" confirm with per-plugin "don't ask again" is respected on
later runs.
  - The `?` shortcuts dialog shows the Space row.
  - Verified in both light and dark themes.

## Known Issues

When there are no actions, plugins, or scripts, the search bar will show
"Search 0 actions". This is bad UX. One alternative considered was to
show a call to action, for example "Please load plugin scripts so that
they appear here".

However, this is ultimately not implemented, as eventually it is not
expected that actions will be empty. The action registry will not be
expected to be empty because we will include in-app actions such as
opening dialogues or other app actions.

<img width="722" height="117" alt="image"
src="https://github.com/user-attachments/assets/a4b9c0db-b2bf-44bc-9550-398dd8b4c7aa"
/>

[How to Download Pull Requests Artifacts for
Testing](https://www.orcaslicer.com/wiki/how_to_download_pr_artifacts)
2026-07-17 23:36:34 +08:00
SoftFever
ee4fca1493 clean up 2026-07-17 23:04:42 +08:00
SoftFever
2614ef7d63 Defer speed-dial web commands off the webview callback stack 2026-07-17 22:37:56 +08:00
Ian Chua
1c82b88c0a fix: unit test shutting down pythonintepreter 2026-07-17 21:56:04 +08:00
Ian Chua
dda49a2b7b Merge branch 'feat/plugin-feature' into feature/speed-dial 2026-07-17 21:29:25 +08:00
Ian Chua
5e15a67425 fix: deprecate show_dialog api and add an option to create_window params 2026-07-17 21:12:55 +08:00
SoftFever
f0f496e9c3 Merge branch 'feat/plugin-feature' into feature/speed-dial
Adapt the speed dial's ActionRegistry to the collapsed
get_plugin_capability(PluginCapabilityId) overload, and restore the
script success/skipped status message the dialog lost when its
PluginScriptRunner refactor was superseded by ActionRegistry.
2026-07-17 19:32:44 +08:00
SoftFever
f6ff15ed99 Feat/plugin config (#14746)
# Description

This PR introduces persistent, capability-scoped configuration for plugins. Users can configure plugins through the Plugins dialog instead of manually editing the plugin’s Python source.

Configuration exists at two levels:

- **Global** — one configuration per capability, shared by every preset. Edited in the Plugins dialog’s **Config** tab.
- **Per preset** — an optional override stored on a process or printer preset, edited from that preset’s **Plugin Preferences** group. A preset that overrides a capability configures the slices it drives; presets that do not simply use the global configuration.

Plugin authors can use the built-in JSON editor or provide a custom HTML settings interface. Both levels use the same editor and the same stored shape.

## New Plugin Configuration APIs

The following APIs are available to all plugin capability types.

### Python APIs

- `get_config() -> str` — Returns a raw JSON string of the capability’s effective configuration: the active preset’s override if it has one, otherwise the global configuration, otherwise `{}`.
- `save_config(config) -> bool` — Persists JSON-compatible configuration for the capability and returns whether the write succeeded. Always writes the **global** configuration (see [Preset overrides](#preset-overrides)).
- `get_config_version() -> str` — Returns the plugin version that last saved the configuration `get_config()` returned, from that same level, or `""` if it has never been saved.
- `has_config_ui() -> bool` — Override and return `True` to use a custom configuration interface instead of the built-in JSON editor.
- `get_config_ui() -> str` — Returns the HTML used to render the custom configuration interface.
- `get_default_config() -> str` — Returns a raw JSON string of the configuration applied by **Restore defaults** in the Plugins dialog. The default implementation returns `{}`.

### Custom UI JavaScript APIs

Custom configuration interfaces receive a sandboxed `window.orca` bridge:

- `window.orca.getConfig()` — Returns the current capability configuration.
- `window.orca.saveConfig(config)` — Requests that the host persist the supplied configuration.
- `window.orca.onConfig(callback)` — Immediately invokes the callback with the current configuration and invokes it again after successful saves or restores.

`saveConfig()` is asynchronous and does not return a Promise. Custom interfaces should use `onConfig()` to observe the successfully persisted state.

## Plugins Dialog

Every activated capability appears in the Plugins dialog’s **Config** tab, where its global configuration is edited.

The editor shown for a capability is selected as follows:

- If `has_config_ui()` returns `True` and `get_config_ui()` returns valid, non-empty HTML, the dialog renders the custom interface.
- Otherwise, the dialog renders the built-in JSON editor.
- If a custom interface cannot be loaded, the dialog reports the error and falls back to the JSON editor.
- The **Restore defaults** action replaces the stored configuration with the value returned by `get_default_config()`.

Custom interfaces run in a sandboxed iframe and can access configuration only through the provided `window.orca` bridge.

## Preset overrides

Process and printer presets gain a **Plugin Preferences → Capabilities** setting (Advanced mode). Its **Configure** button opens a dialog listing the capabilities that preset actually uses — the ones its `plugins` manifest declares *and* one of its plugin-backed options points at — and edits each one’s configuration for that preset alone. The button shows the number of overrides the preset carries.

That dialog offers two actions:

- **Save** — stores the edited configuration as this preset’s override.
- **Restore defaults** — discards the preset’s override, so the capability falls back to the global configuration. A preset holding no override *is* a preset at its defaults.

### How a running capability reads its configuration

`get_config()` resolves in this order:

1. The active preset’s override for this capability, if it has one.
2. The global configuration in `config.json`.
3. `{}`.

Which preset is consulted follows from the capability’s type. A plugin-backed option declares the capability type it accepts (`ConfigOptionDef::plugin_type`) and belongs to exactly one preset type, so `slicing-pipeline` capabilities are configured by the process preset and `printer-connection` capabilities by the printer preset. Nothing is hardcoded: declaring `plugin_type` on a new option is all it takes to place a new capability type on that map.

`get_config_version()` reports the version stamp from whichever level supplied the configuration, so a plugin migrating a stale config is never handed one level’s data with another level’s version.

`save_config()` from Python always writes the global configuration, never a preset — presets are the user’s to edit, and a plugin saving from a worker thread cannot mark one dirty. A capability whose active preset overrides it will therefore keep reading that override back rather than what it saved.

### Storage

A preset’s overrides live in an ordinary string setting on the preset (`plugin_preference_overrides`), holding a JSON array of entries keyed by plugin and capability. Because it is an ordinary setting, the whole preset lifecycle carries it for free: the dirty marker, the revert arrow, inheritance, project (3MF) round-tripping, and preset sync all behave exactly as they do for every other setting. The dialog is a pure editor over that text — it never writes to the preset itself and never writes to the global config file.

## Configuration Storage

All global plugin configuration is stored in a shared file:

`data_dir()/orca_plugins/config.json`

Configuration entries are isolated by plugin and capability. The host also records the plugin version that last wrote each entry.

The configuration file is intentionally stored outside individual plugin directories. This allows settings to survive:

- Plugin upgrades and reloads
- Local plugin deletion and reinstallation
- Cloud plugin unsubscribe and resubscribe operations

Reinstalling or resubscribing to the same plugin restores access to its previously saved configuration.

## Known limitations

**Filament capabilities cannot be overridden per preset.** There is no single active filament preset — one is selected per extruder — and `get_config()` does not say which extruder the capability is running for, so a filament override could only be applied by guessing. Rather than hand a plugin another extruder's settings, filament capabilities read the global configuration.

Nothing reaches this today: no filament option declares a `plugin_type`, so no capability type maps to the filament preset. Lifting it means pushing the extruder onto the plugin call context the Python trampoline already maintains and resolving the preset from that, with the extruder optional — whole slicing steps (`posSlice`, `psGCodePostProcess`) span every extruder and have no current filament.

# Tests

`tests/slic3rutils` covers the capability config store, the Python config API, the preset override layer, the capability-type → preset-type mapping, and which capabilities a preset counts as in use.

# Screenshots/Recordings/Graphs

Custom UI
<img width="855" height="703" alt="image" src="https://github.com/user-attachments/assets/745ecb7d-9e20-4c39-b857-5aa730a27142" />

Default JSON text editor
<img width="855" height="703" alt="image" src="https://github.com/user-attachments/assets/18b7b89c-6f77-4960-a9b2-964e71f74fc3" />

Process Sidebar
<img width="717" height="360" alt="image" src="https://github.com/user-attachments/assets/8fac3e66-c06a-44e4-ad4b-4cc6c003bb2b" />

Filament dialog
<img width="1090" height="832" alt="image" src="https://github.com/user-attachments/assets/ff6a4cbe-11c0-4d04-9ecb-9a717bdeb3f4" />

Printer settings dialog
<img width="1090" height="832" alt="image" src="https://github.com/user-attachments/assets/c616afb0-4eb2-40c2-92c0-7f5edc50b4e6" />

Dialog opened from preset settings
<img width="860" height="725" alt="image" src="https://github.com/user-attachments/assets/069408a8-e94b-47e0-8e16-a81e0d58b4d4" />

# Example plugin with custom UI used in screenshot
[custom_ui_screenshot_demo.py](https://github.com/user-attachments/files/29995212/custom_ui_screenshot_demo.py)

<!--
> A guide for users on how to download the artifacts from this PR.
-->

[How to Download Pull Requests Artifacts for Testing](https://www.orcaslicer.com/wiki/how_to_download_pr_artifacts)
2026-07-17 18:45:51 +08:00
SoftFever
a152c7bcad Name the plugin capability config option consistently
The preset option was plugin_preference_overrides while the GUI field type
that renders it was GUIType::plugin_config, for one and the same thing.
Settle on "config": the store, the dialog and the Python hooks all say config
already, so renaming that way touches 4 files instead of the whole plugin
subsystem and the public plugin API.

Keep the _overrides suffix — the option is the preset's override layer over
the base PluginConfig store, a distinction EffectiveCapabilityConfig tracks.

Also wrap the printer tab's group heading in L(); it was the only one of the
three missing it, and was therefore untranslatable.
2026-07-17 18:34:15 +08:00
SoftFever
6767ab5ae0 Make the Latest and installed version labels dynamic 2026-07-17 16:25:10 +08:00
SoftFever
9d9bb9cdbd Install the OTA plugin update immediately and hot-reload it 2026-07-17 16:25:10 +08:00
SoftFever
c2f88b17be Complete the plugin settings removal after the feat/plugin-feature merge
The merge kept this branch's PluginConfig design, which deletes
PluginDescriptor::settings, get_plugin_settings() and ctx.params, but left
references to them behind: the slic3rutils target did not build, and the
bindings test still asserted the removed ctx.params attribute.

Port the two settings tests onto PluginConfig instead of dropping them. They
guard a field bug where a cloud-metadata refresh wiped a plugin's settings and
it silently ran on its own defaults, so the equivalent properties are still
worth pinning: that a stored config survives the refresh, and that an edited
config reaches the plugin through a real dispatch.

Also defer PluginsConfigDialog's web commands off the webview script-message
callback, as PluginsDialog already does. Its remove_preset_override handler put
a modal wxMessageBox on that stack, which is the GTK crash class fixed in
b779a7bfed/f2ccbfc8b5 for the sibling dialog.
2026-07-17 16:09:19 +08:00
SoftFever
79593e07c6 List same-series OTA plugin builds in the version selector 2026-07-17 14:23:40 +08:00
SoftFever
5808ae5ab0 Fix the network plugin OTA update flow 2026-07-17 14:23:39 +08:00
Ian Chua
4c60781cf4 fix: merge branch feat/plugin-feature 2026-07-17 14:02:10 +08:00
Andrew
b4f6573753 Merge branch 'feat/plugin-feature' into feature/speed-dial
# Conflicts:
#	src/slic3r/GUI/PluginsDialog.hpp
2026-07-17 13:59:56 +08:00
Ian Chua
96182e778a fix: merge pythonjsonutils into pluginfsutils 2026-07-17 13:35:51 +08:00
SoftFever
1b722de6e7 Fix latent popup defects and mark the unwired device modules 2026-07-17 13:20:41 +08:00
SoftFever
38ab986c5f Drop the transitional device-layer shims 2026-07-17 12:46:45 +08:00
SoftFever
37e27a24c4 Fix the pre-send advisories and port the remaining send-flow checks 2026-07-17 12:10:45 +08:00
SoftFever
b663f851fe Merge branch 'main' into feat/plugin-feature 2026-07-17 11:30:34 +08:00
SoftFever
7f8baf46d3 Port the pre-send checks and wire the AMS best-position popup 2026-07-17 11:10:21 +08:00
SoftFever
d097fbec9a Resync the device send flow 2026-07-17 10:20:24 +08:00
SoftFever
2ee0bbde54 Port the filament-change stop button, hub version row and HMS fallback 2026-07-17 09:41:01 +08:00
SoftFever
80d3c3908d Resync the device status pages 2026-07-17 08:30:22 +08:00
SoftFever
5e95aca42d Restore the popup accent colors and improved strings 2026-07-17 07:25:02 +08:00
SoftFever
40a875800d Resync the AMS and device dialogs 2026-07-17 06:48:15 +08:00
SoftFever
50abe02f18 Make AMS trays read-only in laser mode and add the gradient fill helper 2026-07-17 05:06:09 +08:00
SoftFever
7265a2fbfe Resync the AMS control and item widgets 2026-07-17 04:30:45 +08:00
SoftFever
db51d8ab9b Mark the accent-color divergence in the best-position popup 2026-07-17 03:50:29 +08:00
SoftFever
d4e95e3269 Resync the device tab widgets and add the AMS best-position popup 2026-07-17 03:37:18 +08:00
SoftFever
0feca8d442 Port accessory firmware versions, cold-pull state and filament checks 2026-07-17 02:49:45 +08:00
SoftFever
1c9fda463b Fix plugin settings lost on cloud metadata refresh
Cloud catalog records never carry [tool.orcaslicer.plugin.settings], so the
metadata merge wiped the locally-parsed settings and plugins silently ran on
their built-in defaults (ctx.params arrived empty).
2026-07-17 02:09:34 +08:00
SoftFever
8d211ce878 Move axis, calib, chamber, status and upgrade handling into DeviceCore 2026-07-17 02:04:25 +08:00
SoftFever
8a6609f282 Restore the extruder name fallback and fix the loading-busy check 2026-07-17 01:16:47 +08:00
SoftFever
4bca7b3008 Resync the DeviceCore state models 2026-07-17 00:49:04 +08:00
SoftFever
0a0d59b76b Fix plugins dialog hiding behind the main window on macOS 2026-07-16 22:36:31 +08:00
SoftFever
6f30d03e28 fix test errors 2026-07-16 21:40:21 +08:00
SoftFever
f2ccbfc8b5 Open the plugin terminal off the webview callback stack
open_terminal_dialog is reached from the plugins dialog's webview
command, and TerminalDialog hosts a webview of its own — same class as
the plugin-window crash. Defer the window work via CallAfter, guard the
re-front Show() per #13657, and drop the redundant Raise() on creation.
2026-07-16 21:25:30 +08:00
Ian Chua
d9f8460a4e fix: merge PythonFileUtils into PluginFsUtils 2026-07-16 20:40:32 +08:00
SoftFever
550ab5d438 Guard the don't-remind command parse and init the checker index 2026-07-16 20:09:50 +08:00
SoftFever
56ac4e1281 Mark deliberate porting divergences 2026-07-16 20:07:55 +08:00
SoftFever
b779a7bfed Create plugin windows off the webview callback stack
wx 3.3.2 delivers webview script messages synchronously inside the native
callback on GTK and macOS, so script plugins run with the plugins-dialog
webview's signal/delegate frame on the stack. Creating and presenting the
orca.host.ui window from there crashed on Linux at Raise() --
gtk_window_present while GTK's deferred show was still in flight.

Defer the whole window creation to a CallAfter with a pre-bound registry
handle (post/close stay FIFO-safe, teardown races become a no-op), and
drop Raise() plus the show_modeless_dialog wrapper: Show() already
activates and fronts a new window on every platform.
2026-07-16 20:07:41 +08:00
Ian Chua
a86202b45b fix: change speed dial from popup to dialog for consistent behavior on linux 2026-07-16 19:47:26 +08:00
SoftFever
5fd1aa6e8b Add firmware print-option toggles to the print options dialog 2026-07-16 19:28:50 +08:00
SoftFever
eeec8ab06b Parse the new detection bits on the live push path 2026-07-16 18:51:25 +08:00
SoftFever
28b7fd90d0 Restructure DevPrintOptions around a detection-option map 2026-07-16 18:40:53 +08:00
Ian Chua
f142716e51 fix: change popup to dialog with popup behavior 2026-07-16 18:29:40 +08:00
Ian Chua
74ffc46bbc fix: syntax 2026-07-16 18:22:55 +08:00
SoftFever
4a1c53e76e Stop the pending storage check when jumping to the timelapse page 2026-07-16 18:18:51 +08:00
Ian Chua
f4414dd72b fix: collapse plugincapabilityid 2026-07-16 18:18:07 +08:00
SoftFever
3ec074edb2 Stop the timelapse storage check when the send dialog closes 2026-07-16 18:11:01 +08:00
SoftFever
615deefa87 Check timelapse storage space before sending a print 2026-07-16 17:52:28 +08:00
Andrew
30170839c1 Merge branch 'feat/plugin-feature' into feature/speed-dial 2026-07-16 17:15:24 +08:00
Andrew
1c33983edf Confine plugin lifecycle callbacks to UI thread
Drop the orphaned PluginCallbackList (dead
after the PluginManager migration) and hop
run_on_*_callbacks onto the UI thread via
CallAfter, snapshotting under the mutex on the
worker first. Keeps wx subscribers off the
detached load/unload workers.
2026-07-16 17:08:03 +08:00
SoftFever
ffda4282eb Add timelapse storage location selection 2026-07-16 16:59:16 +08:00
SoftFever
5cf7e27c23 Show combined nozzle mapping when a filament switch is installed 2026-07-16 16:35:11 +08:00
Andrew
13575601ff Give speed-dial popup GUI_App ownership 2026-07-16 16:09:30 +08:00
Andrew
13f5c777cc Rename SpeedDialDialog files to SpeedDialPopup 2026-07-16 16:09:30 +08:00
SoftFever
8bb093b50b Map switch-bound AMS trays to both extruders 2026-07-16 15:54:56 +08:00
Ian Chua
49396699e7 fix: initialize embedded python from bundled runtime 2026-07-16 15:40:13 +08:00
SoftFever
47f7e09e84 Block TPU on the left extruder without firmware support 2026-07-16 15:21:35 +08:00
SoftFever
e8f8a4bb7d Add purification and don't-remind actions to the device error dialog 2026-07-16 15:15:40 +08:00
SoftFever
c7581e590c Warn when a filament will switch extruders mid-print 2026-07-16 14:58:58 +08:00
SoftFever
5f3f892a6b Fix inverted MQTT jog on i3-arch printers 2026-07-16 14:54:16 +08:00
Andrew
9279f86858 Migrate from PluginLoader to PluginManager
Refactor to streamline plugin management within
ActionRegistry by consolidating interface usage.
2026-07-16 13:32:40 +08:00
Andrew
c816e48b78 refactor: collapse speed-dial action source abstraction
Only one action source ever existed, so the
IActionSource interface and ScriptActionSource
are gone. ActionRegistry now subscribes to the
plugin loader and enumerates actions directly
in init() - no polymorphism for one impl.

Replace the opaque FNV-hash SpeedDialActionId
with a readable composed id of the form
prefix:title:source_key. Split AppAction's
single source field into source_key (stable
identity, e.g. plugin_key) and source_name
(display), so identity and display no longer
share one field.
2026-07-16 13:08:48 +08:00
Ian Chua
b6f98d9592 fix: load default config on initial load 2026-07-16 12:57:59 +08:00
Ian Chua
a15dcdfb3f move configure to plugin preferences in printer settings dialog 2026-07-16 12:16:22 +08:00
Ian Chua
525a16177c fix: bundle python runtime for macos plugin tests 2026-07-16 12:06:45 +08:00
SoftFever
0f58f23853 Destroy the network-plugin agent before unloading its DLL
A network-plugin hot reload unloaded the DLL without destroying the agent
handle it created, so the plugin's m_agent was left dangling into freed
memory. On reload create_agent() short-circuited on has_agent() and kept the
stale handle, and the next call into the new DLL (install_device_cert from the
device-refresh timer) dereferenced it and crashed with an access violation.
unload() now destroys the agent first, so a reload always gets a fresh handle.
2026-07-16 10:53:28 +08:00
SoftFever
7cc572be47 Add PA-profile sharing toggle to the device send dialog 2026-07-16 02:47:47 +08:00
SoftFever
d591d50ca0 Show the print-failure snapshot in the device error dialog
When a print fails, DeviceErrorDialog now fetches the printer's captured camera
frame of the failure and shows it in place of the generic HMS illustration,
falling back to the local image and a drawn placeholder on older plugins or errors.

- Agent: add get_hms_snapshot through NetworkAgent / IPrinterAgent (BBL calls the
  bound plugin symbol; other agents no-op, so old plugins degrade gracefully).
- DeviceManager: parse and clear m_print_error_img_id from the print-error message.
- Dialog: tiered cloud/local/placeholder image reusing the single image widget,
  with a liveness-guarded async callback decoded on the UI thread.
2026-07-16 01:44:43 +08:00
SoftFever
aa44d57eac Bind the 02.08.01.52 plugin's new ABI symbols
Add the 11 functions the newer plugin exports (HMS snapshot, GoLive camera
URL, consent report, cloud filament-spool CRUD, AMS-filament sync, login-state
and studio-info hooks) plus their four parameter structs. Everything resolves
to null on older plugins and no caller invokes them yet, so this is inert ABI
surface for later features.
2026-07-16 00:48:56 +08:00
SoftFever
bf4fb64c8a Make 02.08.01.52 the default network plugin and match its ABI
The newer plugin adds four PrintParams fields (task_timelapse_use_internal,
extruder_cali_manual_mode, svc_context, slicer_uid) and an extra dev_model
argument to bind. Both cross the by-value C ABI boundary, so match the struct
layout and thread dev_model through the bind chain, else start_print and bind
corrupt the stack on the newer plugin. Keep 02.03.00.62 selectable as a fallback.
2026-07-16 00:17:01 +08:00
Ian Chua
8ba478913f fix merge conflicts 2026-07-15 22:09:47 +08:00
Ian Chua
e21123d8e9 fix: trim configs 2026-07-15 21:43:13 +08:00
Ian Chua
d2b5008156 fix: test_slicing_pipeline_hook 2026-07-15 21:39:55 +08:00
Ian Chua
9cdd399fdd fix: test slicing pipeline hook 2026-07-15 21:32:37 +08:00
Ian Chua
cd8c42b125 fix merge conflicts 2026-07-15 21:04:42 +08:00
Ian Chua
62afea225a Fix/impl refactor (#14776)
* fix: impl refactor

* fix: unload/load python module, race conditions, freezes

* remove dead code

* remove extra hook

* remove more dead code

* fix gil run script
2026-07-15 20:12:51 +08:00
SoftFever
1551898846 Plugin-gate the reslice check and drop non-plugin leftovers
reslice() now enforces only the missing-plugin block via
refresh_missing_plugin_block (no second Print::validate); plate
ready-status returns to upstream's plain model_fits, matching
GLCanvas3D::reload_scene. Also restores main's use_bbl_device_tab and
the check_track_enable comment, and drops two unused MainFrame includes.
2026-07-15 19:18:45 +08:00
SoftFever
e116181c07 Use one agent id in switch_printer_agent and restore the preset_bundle guard
Merge-resolution cleanup. The #12506 re-select path kept main's preset_bundle
null check, and both select_machine calls now use effective_agent_id rather than
mixing it with the equal-but-differently-named agent_info.id.
2026-07-15 17:54:39 +08:00
SoftFever
bf932e8797 Merge branch 'main' into feat/plugin-feature 2026-07-15 17:19:14 +08:00
SoftFever
8cb0cb7693 Merge branch 'main' into feat/plugin-feature
Resolve five conflicts, all of which needed both sides rather than a pick:

- BackgroundSlicingProcess: ours was a pure tabs->spaces reformat of base, so
  keep main's per-filament volume/nozzle map read-back (its only change here).
- GUI_App: main's #12506 else-if attached to an `if` this branch deleted;
  re-expressed onto the same-agent early-return path (the agent factory caches
  per id, so pointer equality is the same predicate).
- MainFrame: both sides relocated Sync Presets independently; keep main's
  push_notification plus the branch's Plugins menu items.
- Tab: the "TODO: Orca: Support hybrid" blocks were unchanged base, not a branch
  decision; take main's enabled Hybrid to match the already auto-merged siblings.
- test_config: union of both sides' cases (6 plugin + 9 multi-nozzle).
2026-07-15 17:18:46 +08:00
Ian Chua
71d0380467 fix: preset resolution 2026-07-14 19:48:39 +08:00
Ian Chua
3daa4336e3 fix: resizable plugins dialog 2026-07-14 15:13:10 +08:00
Ian Chua
06cd8ad0d5 chore: UI Updates 2026-07-14 14:42:32 +08:00
Ian Chua
8cc4eaea1e update some comments 2026-07-14 13:31:28 +08:00
Ian Chua
fbed6f7dc6 cleanup 2026-07-14 13:10:42 +08:00
Ian Chua
86a4cec753 fix: preset overrides on sidebar 2026-07-14 12:57:06 +08:00
Ian Chua
796080ff76 fix: naming 2026-07-14 11:34:06 +08:00
Ian Chua
5b3e1b921c feat: sidebar plugin config UI 2026-07-13 20:39:41 +08:00
Andrew
635f5a3529 Merge remote-tracking branch 'public/feat/plugin-feature' into feature/speed-dial
# Conflicts:
#	src/slic3r/GUI/PluginsDialog.cpp
2026-07-13 19:39:42 +08:00
Andrew
476fa73e43 Prevent script execution during shutdown
Skip script action calls when the application
is closing to avoid post-teardown issues.
2026-07-13 19:20:23 +08:00
Andrew
c3ebf38a07 Prevent hidden action execution
Block execution of actions from an empty list
until user input specifies a selection, ensuring
actions not displayed don't trigger unexpectedly.
2026-07-13 19:20:15 +08:00
Andrew
87c9ab138c Protect action identity from mutation
Keep action identity and display metadata
constructor-set so registry keys cannot drift
from the objects they index.

Require sources to publish unique ownership while
the registry retains shared keepalive for runs.

Preserve opaque IDs and persisted state keys.
2026-07-13 17:32:34 +08:00
Andrew
b4c9747f09 fix(plugins): prevent callback races
Lifecycle callbacks can be registered while
another thread dispatches them, risking races
and iterator invalidation.

Snapshot shared callback objects under a mutex,
then invoke them unlocked to preserve reentrancy
and mutable callback state.
2026-07-13 17:25:39 +08:00
Andrew
592e5f92f8 Tone down inactive favourite stars 2026-07-13 16:00:32 +08:00
Andrew
39357533b2 Harden speed dial helper inputs 2026-07-13 16:00:29 +08:00
Andrew
5a3e4abb18 Catch plugin actions loaded during startup 2026-07-13 16:00:25 +08:00
Andrew
88e3e59c64 Convert actions storage to unordered_map
Enhance action lookup efficiency by switching
from a vector to an unordered_map, allowing
faster access by action ID.
2026-07-13 14:28:26 +08:00
Andrew
c29ffdfc1a Extract script actions into an action source
Move plugin capability enumeration, loader
subscriptions, and action construction into
ScriptActionSource. Keep ActionRegistry focused
on generic action state, dispatch, and snapshots.

Use source rather than package for generic origin
metadata so future non-plugin providers share the
same interface. Action IDs and persisted
configuration remain unchanged.

Subscribe before initial enumeration so plugin
events cannot be missed between the snapshot and
callback registration. Add a focused test for
source startup.
2026-07-13 14:28:05 +08:00
Andrew
2cef101ffe Make speed dial actions polymorphic
Decouple registry dispatch from plugin-specific
result types so future action types can provide
their own run implementations.

Store actions behind shared pointers to keep them
alive while plugin UI pumps a nested event loop
and queued refreshes mutate the registry. Scope
"don't ask again" to an individual action instead
of its whole plugin.
2026-07-13 14:28:05 +08:00
Ian Chua
0c69b9982d merge 2026-07-13 12:26:10 +08:00
Ian Chua
2a746a3e61 fix: plugin link text color 2026-07-13 11:59:11 +08:00
peachismomo
25d7abf81b tests 2026-07-12 17:01:45 +08:00
peachismomo
ce21a09cb1 feat: plugins config APIs 2026-07-12 16:55:04 +08:00
peachismomo
a00fac9b72 feat: plugins config UI 2026-07-12 16:20:39 +08:00
SoftFever
4e9bf47741 Plugin: Slicing-pipeline support and expose new APIs and refactoring (#14721)
# Slicing-pipeline plugins: Python hooks inside `Print::process()` with
an editable geometry API

This branch adds a new **slicing-pipeline** plugin capability on top of
the plugin framework: Python plugins can now run at defined points
inside the slicing pipeline and edit the live slicing data, with changes
cascading into perimeters, infill, and the final G-code.

## The capability

- New plugin type `slicing-pipeline`, selectable per print profile via a
new picker option (`slicing_pipeline_plugin`).
- `Print::process()` fires a hook at 13 pipeline steps (`posSlice`,
`posPerimeters`, … `psSkirtBrim`, `psGCodePostProcess`). Selected
plugins run per step with cancellation honored and failures surfaced as
ordinary slicing errors, never crashes.
- G-code post-processing is folded into this capability as the final
step (`psGCodePostProcess`); the separate "post-processing" plugin type
and its option are removed. Breaking only for the unreleased plugin API
— migrated plugins gain settings and config access in return.

## The Python API (`orca.host`)

- The live print graph is exposed as raw host classes — `Print`,
`PrintObject`, `Layer`, `LayerRegion`, `SurfaceCollection`, `Surface`,
`ExPolygon`, `Polygon`, `Point`, plus `Model`/`TriangleMesh` with
zero-copy numpy views.
- Geometry is genuinely editable through the class API: in-place
transforms, whole-surface replacement, and vertex-level rebuilds, with
`layer.make_slices()` re-deriving the C++ invariants after edits. Write
paths validate input, so malformed data raises in Python instead of
corrupting the slice.
- Bindings are organized under `src/slic3r/plugin/host/` by domain.

## Architecture

- All libslic3r hook seams (capability resolver, pipeline dispatcher)
are installed and uninstalled by one composition root,
`plugin/PluginHooks`, from `PluginManager::initialize()`/`shutdown()`.
GUI_App no longer accumulates per-capability wiring, and hooks detach
before the Python interpreter finalizes.

## Samples (`sandboxes/`) — one per editing idiom

| Sample | Step | Demonstrates |
| --- | --- | --- |
| **Inset Every Slice** | `posSlice` | Shrink every slice via polygon
offset + whole-surface replacement (`slices.set`) |
| **Twistify** | `posSlice` | Twist/taper/wobble via count-preserving
in-place transforms |
| **Fuzzy Slices** | `posSlice` | Fuzzy skin applied to the slice
contours themselves (vertex-level rebuild) — walls, infill, and the
preview all inherit it |
| **G-code Stamp** | `psGCodePostProcess` | Editing the exported G-code
file in place |

# Screenshots/Recordings/Graphs
1. Fuzzy skin example:
Orca's built-in fuzzy skin perturbs the outer-wall EXTRUSION PATHS
during
perimeter generation, so only the printed wall is fuzzy. This sample
instead
perturbs the sliced outline itself at sliced geometry:
<img width="1230" height="902" alt="image"
src="https://github.com/user-attachments/assets/bcf8b0c7-f932-4e6a-985d-7c9cc2f3d7cb"
/>

2. Twistify -- twist/taper/wobble any model at slice time
every layer's sliced surfaces are transformed by a similarity
about the object's bounding-box center as a function of Z


https://github.com/user-attachments/assets/d1309ea8-b01c-4708-adf1-821b3b00a4cc

3. Inset Every Slice -- a small, WORKING SlicingPipeline sample plugin
For every layer/region of the sliced object, this shrinks each
sliced surface by INSET_MM using a real polygon offset
<img width="1225" height="896" alt="image"
src="https://github.com/user-attachments/assets/5f2028a9-ae2a-4aea-8b38-a3d6e24f5cb4"
/>
2026-07-12 01:41:12 +08:00
SoftFever
579e58c528 Add Fuzzy Slices sample (fuzzy skin at posSlice) + coverage test
Experimental fuzzy on geometry
Mirrors libslic3r's fuzzy_polyline on the slice contours at Step.posSlice,
demonstrating the count-changing mutation idiom (rebuild ring via
Polygon.append, write back via ex.contour / ex.set_holes). C++ analogue
test proves area preservation, cascade, and bounded displacement.
2026-07-12 01:19:54 +08:00
SoftFever
03094df10e refactor(plugin): move libslic3r hook wiring out of GUI_App into PluginHooks
GUI_App::on_init_inner() carried the plugin dispatch policy inline (the
capability resolver and the slicing-pipeline dispatcher) and would grow
with every capability that fires from inside libslic3r.

plugin/PluginHooks.{hpp,cpp} now owns one file-local installer per hook,
aggregated by plugin_hooks::install() -- called from
PluginManager::initialize(), reset in shutdown() so no hook can enter
Python after the interpreter finalizes. The wx-side loader subscriptions
move into GUI_App::init_plugin_gui_wiring().

No behavior change; dispatch bodies moved verbatim.
2026-07-12 00:20:39 +08:00
SoftFever
c17d9732be refactor(plugin): bind raw TriangleMesh instead of HostTriangleMesh wrapper
Bind libslic3r's TriangleMesh directly with a shared_ptr holder rather than
wrapping it in a HostTriangleMesh snapshot struct. ModelVolume.mesh() hands
out the volume's own shared_ptr (via const_pointer_cast, which only serves
the holder type), so the Python object pins the snapshot exactly as the
wrapper did, and the zero-copy views now use the Python object as their
array base — deleting the capsule machinery.

The wrapper's type-level constness becomes a documented rule instead:
handed-out meshes are copy-on-write snapshots shared across threads, so the
binding exposes only const methods; a future mutable-mesh API must operate
on plugin-owned copies handed back via ModelVolume::set_mesh.

No Python-visible change (orca.host.TriangleMesh, same methods/docstrings),
and plugins now hold the real class a future set_mesh() will accept.
Verified with slic3rutils and fff_print suites.
2026-07-11 18:54:07 +08:00
SoftFever
126e4d5445 refactor(plugin): split orca.host bindings into host/ by domain
PluginHostApi.cpp had grown into one TU holding the module entry point plus
three unrelated domains (presets, model/mesh graph, app access), and
PluginHostSlicing.cpp mixed ownable geometry value types with the
non-owning live print graph. Reorganize the orca.host surface into
plugin/host/ with one registrar per domain:

- PluginHost.hpp/.cpp        entry point (replaces PluginHostApi)
- PluginHostBindings.hpp     internal per-domain registrar declarations
- PluginHostGeometry.cpp     BoundingBox, Point, Polygon, ExPolygon + ndarray parsing
- PluginHostMesh.hpp/.cpp    TriangleMesh snapshot (own TU ahead of planned
                             mesh construct/mutate APIs)
- PluginHostPresets.cpp      Preset, PresetCollection, PresetBundle
- PluginHostModel.cpp        scene graph: Model, ModelObject, ModelInstance, ModelVolume
- PluginHostApp.cpp          Plater + plater()/model()/preset_bundle() accessors
- PluginHostSlicing.cpp      live print graph only, now with a single lifetime story
- PluginHostUi.hpp/.cpp      moved unchanged

PluginBindingUtils.hpp stays at plugin/ root: it is shared with pluginTypes/
and tests, not host/-specific.

No Python-visible change: same submodules, class names and docstrings.
Verified with slic3rutils and fff_print suites.
2026-07-11 16:18:59 +08:00
SoftFever
a04ce5f81e docs(plugin): make comments self-contained; drop design-doc and dead-code references
Review the slicing-pipeline plugin comments for context a reader of the source
alone cannot follow, and rewrite them to stand on their own:

- drop pointers to uncommitted design/plan material ("§3.6 (Twistify design)",
  "the brief's note", "Fix 4(a)/4(b)")
- fix dangling references to code this branch removed: the retired set_slices()
  and view mutators, the former G-code post-processing capability/trampoline,
  the "Post-processing" capability family, the pre-refactor array helper
- drop "v1"/"in v1" phase labels, keeping the behavior they described
- correct stale cross-references: Twistify.py -> the real sample path;
  test_plugin_host_api.cpp:32-40 -> import_orca_module in python_test_support.hpp;
  "the binding"/"graphs above" -> the named source

Comment/string-only; no code behavior change.
2026-07-11 03:30:05 +08:00
Ian Chua
18388ffb6d feat: plugins config 2026-07-10 20:00:01 +08:00
SoftFever
19352215da feat(plugin)!: merge G-code post-processing into the slicing pipeline as psGCodePostProcess
G-code post-processing is now a step of the slicing-pipeline plugin rather than a
separate capability type. One capability class can transform slices at the geometry
seams AND edit the final G-code, behind a single picker/option.

- Add SlicingPipelineStepPlugin::psGCodePostProcess (bound as
  orca.slicing.Step.psGCodePostProcess). Unlike the geometry steps it fires from the
  GUI export path in PostProcessor.cpp, not from Print::process(): ctx.print/ctx.object
  are None and the plugin edits the file at ctx.gcode_path in place. It may run more
  than once per slice (file export and/or upload) and its output is not shown in the
  preview.
- Extend SlicingPipelineContext with gcode_path/host/output_name and a C++-only
  full_config; config_value() falls back to it when there is no live Print.
- PostProcessor.cpp dispatches SlicingPipelinePluginCapability at psGCodePostProcess,
  driven by the existing slicing_pipeline_plugin option.
- The exported G-code lives outside data_dir(), so the plugin audit sandbox would
  block the write; the trampoline's audit setup grants ctx.gcode_path's folder as a
  scoped allowed root, gated on a non-empty gcode_path so the geometry-step hooks gain
  no extra filesystem access.

BREAKING CHANGE: the separate G-code post-processing capability type is removed.
- orca.gcode.GCodePluginCapabilityBase and orca.PluginType.PostProcessing are gone;
  post-processing plugins migrate to orca.slicing.SlicingPipelineCapabilityBase +
  Step.psGCodePostProcess (and gain ctx.params / ctx.config_value()).
- The post_process_plugin config option is removed; use slicing_pipeline_plugin.
  Presets carrying the old key degrade to the standard unknown-key warning.
- Manifest type = "post-processing" now maps to Unknown (advisory only; the loader
  dispatches on the C++ get_type()).

Also repairs two latent build breaks the branch carried: stale Step enum value usages
in test_slicing_pipeline_hook.cpp and a reference to the removed
ConfigOptionDef::PluginType::None in Tab::on_value_change (now is_plugin_backed()).
Adds the orca_gcode_stamp sample plugin and a psGCodePostProcess binding test.
2026-07-10 19:57:35 +08:00
Andrew
7b19145226 Share one fuzzy matcher across both dialogs
Plugins dialog and the Speed Dial popup each
carried a private copy of the same fuzzy
matcher and had already drifted. Move the
pure functions into a shared module loaded
by both pages, and add a unit test beside
it.
2026-07-10 17:32:31 +08:00
SoftFever
21ed68963f refactor(plugin): prefix SlicingPipelineStepPlugin values with pos/ps to mirror Print steps 2026-07-10 17:28:26 +08:00
Andrew
df5c293d2e Stabilize action counts and tile ordinals 2026-07-10 17:18:30 +08:00
Andrew
35d189f1c7 Add right-click menu to reorder or unpin favs
Right-clicking a fav tile now opens a small
context menu with Move left, Move right, and
Unpin, instead of relying on drag-only reorder.

- speeddial.js: oncontextmenu handler, the
  menu build/position/dismiss logic, and an
  Escape-key close.
- style.css: .ctx-menu/.ctx-item styling.
- ActionRegistry: reorder_favourites persists
  the new bar order to AppConfig.
- SpeedDialDialog: routes the new
  reorder_favourites command from the page.
2026-07-10 17:18:00 +08:00
Andrew
7c9fa801fb Remove dead always-true runnable action field
runnable was hardcoded true on every action,
and only loaded+enabled capabilities ever
reach the registry, so every JS === false
branch was unreachable. Drop the field, its
JSON, the guards, and the orphan .disabled
CSS rule.
2026-07-10 17:12:52 +08:00
Andrew
73a1913447 Put package initial first in tile monogram (GC, not CG) 2026-07-10 15:08:33 +08:00
Andrew
672429cf17 Complete speed dial launcher helper layer; fix tile clip and arrow-nav
Wire the search-first launcher's pure helpers to their node-vm spec:
resultCountText, selectedActionId, actionLabel (accessible row/tile labels
with plugin-key disambiguation), and tileCode (collision-escalating
title/pkg/ordinal monogram). Plus three fixes surfaced by the test + review:

- visibleFavourites drops non-runnable favourites - a dead fav tile
  otherwise renders and run()s to a silent no-op on click.
- .fav-tile mirrors the list tile's inline-flex centering + 12px so a
  multi-char monogram (e.g. "EA1") no longer clips the bare button.
- Arrow Left/Right stop swallowing the search caret in the list zone;
  they only navigate when inside the favourites bar.
2026-07-10 15:06:44 +08:00
Andrew
3dfa83e407 Add search count indication 2026-07-10 14:33:25 +08:00
Andrew
4626f328e4 Route the speed dial popup through the ActionRegistry 2026-07-10 14:33:25 +08:00
Andrew
3ebb4b274d Own the speed dial ActionRegistry in GUI_App and keep it fresh from loader callbacks 2026-07-09 16:21:54 +08:00
Andrew
6463b3d976 Add ActionRegistry as the speed dial's action source of truth 2026-07-09 16:21:54 +08:00
Andrew
bcd98ea791 Add stable hashed identity for speed dial actions 2026-07-09 16:21:53 +08:00
Andrew
6daef171c1 Add actions speed dial 2026-07-09 16:21:53 +08:00
SoftFever
11dd078f64 feat(plugin)!: faithful mutable geometry bindings; edit slices via the class API
Replaces the plugin-only set_slices/set_fill_surfaces/set_lslices mutators with a
faithful, mutable binding of the core geometry types, so a plugin edits the slicing
graph through the same object model the C++ code uses.

- Point, Polygon, ExPolygon, Surface and SurfaceCollection gain constructors,
  writable accessors (contour/holes, set/append/clear, filter_by_type), transforms
  (rotate/scale/translate), boolean ops and offset. Polygon exposes a zero-copy
  writable numpy view via a make_writable_rows helper.
- LayerRegion.slices/fill_surfaces stay read-only refs but are now live,
  in-place-editable SurfaceCollections; Layer.make_slices() re-derives the islands
  and refreshes lslice bounding boxes.
- Rewrites the Inset and Twistify samples on the new API (in-place ExPolygon
  transforms, ExPolygon.offset, SurfaceCollection.set), dropping their numpy
  dependency; each touched layer calls make_slices() so downstream steps see the
  edited footprint. Adds tests covering in-place edits through a live collection.

BREAKING CHANGE: set_slices/set_fill_surfaces/set_lslices and the internal
parse_expolygon(_list)/surfaces_from_py helpers are removed. Plugins mutate through
the class API (SurfaceCollection.set/append/clear, Polygon.set_points/append,
ExPolygon.set_holes) instead.
2026-07-08 15:04:40 +08:00
SoftFever
fd2a489980 Merge branch 'feat/plugin-feature' into feature/plugin-slicing
Brings in the Plugins dialog as-you-type search with fuzzy match highlighting
and clickable column-header sorting (name, version, source, status) — PRs
#14610 and #14611.
2026-07-08 01:03:34 +08:00
SoftFever
f81a24abfb feat(plugin): expose the slicing print-graph as raw orca.host classes + Twistify sample
Adds PluginHostSlicing, which registers the print-graph data model (Print,
PrintObject, Layer, LayerRegion, Surface, ExPolygon, extrusions, ...) into the
orca.host submodule in the same raw-class style as PluginHostApi's Model/Preset
graph, with shared helpers in PluginBindingUtils. SlicingPipelinePluginCapability
is trimmed to the capability surface (the standalone SlicingNumpy helper is folded
away). Adds the Twistify example plugin next to Inset and broadens the binding,
hook, and plugin-install tests.
2026-07-08 00:05:28 +08:00
Ian Chua
05fa7ee56d Plugins dialog: as-you-type search with fuzzy match + highlighting (#14611) 2026-07-07 19:38:31 +08:00
Andrew
fb2c0ef237 Update search button icons and styles
Revise button labels and styling for search
options to improve UI consistency.
2026-07-07 16:28:48 +08:00
Andrew
9a6b861ce3 Merge branch 'feat/plugin-feature' into feature/plugins-dialog-search 2026-07-07 13:08:48 +08:00
Ian Chua
e6008c0883 Plugins dialog: sort via clickable column headers (name, version, source, status) (#14610) 2026-07-07 12:13:33 +08:00
Andrew
cfe3673b22 Refine plugin sorting to use name-first base order
Ensure plugins are sorted alphabetically by name
when no other column is sorted, and resolve ties
by source, status, type, and plugin_key.
2026-07-06 18:14:26 +08:00
Andrew
8ddb4db0de Recompute scrollbar gutter on every render
Address issues with search and sort re-renders
by ensuring the scrollbar gutter is consistently
updated with each rendering cycle.
2026-07-06 18:14:26 +08:00
Andrew
bc21551185 Implement plugin search functionality 2026-07-06 18:14:26 +08:00
Andrew
ee7339b64b Refine plugin sorting to use name-first base order
Ensure plugins are sorted alphabetically by name
when no other column is sorted, and resolve ties
by source, status, type, and plugin_key.
2026-07-06 16:25:07 +08:00
Andrew
a11e442f1d Add version sorting for plugins
Enhance plugin dialog with semver-aware sorting
by version, enabling users to sort plugins based
on version comparisons.
2026-07-06 15:25:09 +08:00
Andrew
714fe54f77 Move plugin sort from dropdown to clickable column headers
Replace the toolbar sort dropdown with sortable Name/Source/Status column
headers that cycle ascending, descending, then clear. Add a Source column
and a PluginSortKey::None baseline for the cleared state. The whole header
cell is the click target and the sort triangle snaps in without a fade.
2026-07-06 15:03:14 +08:00
Andrew
b724cb6631 Implement plugin sorting functionality
Add support for sorting plugins by status, name,
or source in both ascending and descending order.
2026-07-06 12:31:34 +08:00
SoftFever
aafcccc83c Merge branch 'feat/plugin-feature' into feature/plugin-slicing 2026-07-06 01:12:05 +08:00
SoftFever
5d8aa9610a unify orca web dialog style 2026-07-05 10:39:25 +08:00
SoftFever
383969d456 support dark theme for plugin progress dialog 2026-07-04 22:14:55 +08:00
SoftFever
f47eee24d3 fix dark theme issue for plugin web dialog 2026-07-04 22:14:35 +08:00
SoftFever
b0bacdd00b feat(plugin): add the slicing-pipeline plugin capability
Introduces a plugin capability that runs Python at the seams of Print::process(),
letting a plugin read and rewrite slicing state as it is computed.

- New slicing_pipeline_plugin config option; selected plugin refs are serialized
  into the print manifest.
- Print gains an injectable hook fired at each pipeline step (posSlice,
  posPerimeters, posInfill, ...). It is a no-op when unset, fires only on genuine
  (re)computation, and never on the use-cache path.
- orca.slicing submodule: SlicingPipelineCapabilityBase plus a trampoline and a
  Step enum. Capabilities read the live graph through zero-copy int64 numpy views
  (contour/holes geometry with unscaled coordinates, flattened toolpath data) and
  edit it through 2D-geometry mutators with cache-invariant refresh.
- GUI dispatcher runs capabilities during slicing under the GIL, turns plugin
  errors into slicing errors, honors cancellation, and adds the plugin picker.
- Ships the InsetEverySlice sample plugin and binding/hook tests.
2026-07-04 04:33:20 +08:00
SoftFever
4e26e7233e Merge branch 'main' into feat/plugin-feature 2026-07-04 00:19:39 +08:00
SoftFever
43bc76d9a9 update to python 3.12.13 and attempt to fix windows arm build 2026-07-03 22:30:58 +08:00
Ian Chua
e4566d32be fix(flatpak): prefetch CPython source archive 2026-07-03 17:22:40 +08:00
SoftFever
0918f9319c rename example plugin 2026-07-03 16:46:28 +08:00
SoftFever
da04681289 rename example plugin 2026-07-03 16:41:54 +08:00
SoftFever
32756f0402 add orca plugin example 2026-07-03 16:30:28 +08:00
SoftFever
6c89dd4e50 expose more assemble api 2026-07-03 16:30:16 +08:00
Ian Chua
c00d284786 Remove 'Open Terminal' button in PluginsDialog HTML. (#14552)
# Description

<!--
> Please provide a summary of the changes made in this PR. Include
details such as:
  > * What issue does this PR address or fix?
  > * What new features or enhancements does this PR introduce?
> * Are there any breaking changes or dependencies that need to be
considered?
-->

# Screenshots/Recordings/Graphs

<!--
> Please attach relevant screenshots to showcase the UI changes.
> Please attach images that can help explain the changes.
-->

## Tests

<!--
> Please describe the tests that you have conducted to verify the
changes made in this PR.
-->

<!--
> A guide for users on how to download the artifacts from this PR.
-->

[How to Download Pull Requests Artifacts for
Testing](https://www.orcaslicer.com/wiki/how_to_download_pr_artifacts)
2026-07-03 15:41:30 +08:00
Andrew
c334d05214 Remove 'Open Terminal' button in PluginsDialog HTML. 2026-07-03 15:40:13 +08:00
SoftFever
6fd1176661 add status bar for plugin/capability status instead of message box 2026-07-03 14:57:35 +08:00
Ian Chua
e3c6ec309d feat: UI for mixed capability state 2026-07-03 14:48:49 +08:00
Ian Chua
ba41b54c4b Fix display issues in post-processing options group (#14549)
# Description

This issus is only on windows.

# Screenshots/Recordings/Graphs

before:

<img width="300" alt="image"
src="https://github.com/user-attachments/assets/1f0dd1bb-fe37-442b-ba75-81c0c895d1f3"
/>

after:

<img width="300" alt="image"
src="https://github.com/user-attachments/assets/92f42ad5-b5c8-415f-8e10-f78d2a3cc45c"
/>

<!--
> Please attach relevant screenshots to showcase the UI changes.
> Please attach images that can help explain the changes.
-->

## Tests

<!--
> Please describe the tests that you have conducted to verify the
changes made in this PR.
-->

<!--
> A guide for users on how to download the artifacts from this PR.
-->

[How to Download Pull Requests Artifacts for
Testing](https://www.orcaslicer.com/wiki/how_to_download_pr_artifacts)
2026-07-03 14:42:42 +08:00
Ian Chua
3668b01721 Merge branch 'main' into feat/plugin-feature 2026-07-03 13:29:40 +08:00
Ian Chua
db8e03dbc7 chore: migrate docs over to wiki 2026-07-03 13:28:42 +08:00
Andrew
e5fd028caa Fix display issues in post-processing options group 2026-07-03 12:38:41 +08:00
Ian Chua
25b29c0b53 update docs and comments 2026-07-02 19:34:04 +08:00
Ian Chua
ecddf3d18f feat: Python Plugins 2026-07-02 17:49:36 +08:00
616 changed files with 2317242 additions and 1240798 deletions

View File

@@ -221,10 +221,41 @@ jobs:
security import $CERTIFICATE_PATH -P $P12_PASSWORD -A -t cert -f pkcs12 -k $KEYCHAIN_PATH
security list-keychain -d user -s $KEYCHAIN_PATH
security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k $P12_PASSWORD $KEYCHAIN_PATH
codesign --deep --force --verbose --options runtime --timestamp --entitlements ${{ github.workspace }}/scripts/disable_validation.entitlements --sign "$CERTIFICATE_ID" ${{ github.workspace }}/build/universal/OrcaSlicer/OrcaSlicer.app
# codesign --deep is deprecated and cannot sign the bundled Python
# runtime (see relocate_python_runtime in build_release_macos.sh).
# Sign every nested Mach-O in the bundle explicitly -- notarization
# requires the hardened-runtime signature on each -- then seal the
# bundle itself last, and verify so coverage gaps fail at CI time
# rather than at notarization.
ENTITLEMENTS=${{ github.workspace }}/scripts/disable_validation.entitlements
sign() {
codesign --force --options runtime --timestamp --entitlements "$ENTITLEMENTS" --sign "$CERTIFICATE_ID" "$@"
}
sign_app() {
local app="$1"
local machos=()
# file is batched via xargs (per-file it costs minutes); universal
# binaries also print per-architecture lines, dropped by grep -v.
while IFS= read -r f; do machos+=("$f"); done < <(
find "$app" -type f -print0 |
xargs -0 file --no-pad --mime-type -- |
grep -v ' (for architecture ' |
grep ': application/x-mach-binary$' |
sed 's|: application/x-mach-binary$||'
)
if [ "${#machos[@]}" -eq 0 ]; then
echo "ERROR: no Mach-O files found in $app -- detection is broken" >&2
exit 1
fi
echo "signing ${#machos[@]} Mach-O files in $app"
sign "${machos[@]}"
sign --verbose "$app"
codesign --verify --deep --strict --verbose=2 "$app"
}
sign_app "${{ github.workspace }}/build/universal/OrcaSlicer/OrcaSlicer.app"
# Sign OrcaSlicer_profile_validator.app if it exists
if [ -f "${{ github.workspace }}/build/universal/OrcaSlicer/OrcaSlicer_profile_validator.app/Contents/MacOS/OrcaSlicer_profile_validator" ]; then
codesign --deep --force --verbose --options runtime --timestamp --entitlements ${{ github.workspace }}/scripts/disable_validation.entitlements --sign "$CERTIFICATE_ID" ${{ github.workspace }}/build/universal/OrcaSlicer/OrcaSlicer_profile_validator.app
sign_app "${{ github.workspace }}/build/universal/OrcaSlicer/OrcaSlicer_profile_validator.app"
fi
# Create main OrcaSlicer DMG without the profile validator helper
@@ -233,7 +264,7 @@ jobs:
cp -R ${{ github.workspace }}/build/universal/OrcaSlicer/OrcaSlicer.app ${{ github.workspace }}/build/universal/OrcaSlicer_dmg/
ln -sfn /Applications ${{ github.workspace }}/build/universal/OrcaSlicer_dmg/Applications
retry hdiutil create -volname "OrcaSlicer" -srcfolder ${{ github.workspace }}/build/universal/OrcaSlicer_dmg -ov -format UDZO OrcaSlicer_Mac_universal_${{ env.ver }}.dmg
codesign --deep --force --verbose --options runtime --timestamp --entitlements ${{ github.workspace }}/scripts/disable_validation.entitlements --sign "$CERTIFICATE_ID" OrcaSlicer_Mac_universal_${{ env.ver }}.dmg
codesign --deep --force --verbose --options runtime --timestamp --entitlements "$ENTITLEMENTS" --sign "$CERTIFICATE_ID" OrcaSlicer_Mac_universal_${{ env.ver }}.dmg
# Create separate OrcaSlicer_profile_validator DMG if the app exists
if [ -f "${{ github.workspace }}/build/universal/OrcaSlicer/OrcaSlicer_profile_validator.app/Contents/MacOS/OrcaSlicer_profile_validator" ]; then
@@ -242,7 +273,7 @@ jobs:
cp -R ${{ github.workspace }}/build/universal/OrcaSlicer/OrcaSlicer_profile_validator.app ${{ github.workspace }}/build/universal/OrcaSlicer_profile_validator_dmg/
ln -sfn /Applications ${{ github.workspace }}/build/universal/OrcaSlicer_profile_validator_dmg/Applications
retry hdiutil create -volname "OrcaSlicer Profile Validator" -srcfolder ${{ github.workspace }}/build/universal/OrcaSlicer_profile_validator_dmg -ov -format UDZO OrcaSlicer_profile_validator_Mac_universal_${{ env.ver }}.dmg
codesign --deep --force --verbose --options runtime --timestamp --entitlements ${{ github.workspace }}/scripts/disable_validation.entitlements --sign "$CERTIFICATE_ID" OrcaSlicer_profile_validator_Mac_universal_${{ env.ver }}.dmg
codesign --deep --force --verbose --options runtime --timestamp --entitlements "$ENTITLEMENTS" --sign "$CERTIFICATE_ID" OrcaSlicer_profile_validator_Mac_universal_${{ env.ver }}.dmg
fi
# Notarize main DMG

View File

@@ -125,6 +125,131 @@ option(SLIC3R_PCH "Use precompiled headers" 1)
option(SLIC3R_MSVC_COMPILE_PARALLEL "Compile on Visual Studio in parallel" 1)
option(SLIC3R_MSVC_PDB "Generate PDB files on MSVC in Release mode" 1)
option(SLIC3R_ASAN "Enable ASan on Clang and GCC" 0)
# Python stubgen module
option(ORCA_BUILD_PYTHON_STUBGEN_MODULE "Build importable Python module for pybind11-stubgen" ON)
set(ORCA_BUNDLED_UV_EXECUTABLE "" CACHE FILEPATH "Path to a uv executable to bundle for Python package installation. Leave empty to auto-download.")
# Auto-download uv if not provided by the user.
# uv is pinned: the executable ships inside the signed app, so the build must
# be reproducible and the download verified. To upgrade, bump ORCA_UV_VERSION
# and refresh every hash below from the release's .sha256 assets, e.g.:
# curl -sL https://github.com/astral-sh/uv/releases/download/<ver>/uv-<triple>.tar.gz.sha256
set(ORCA_UV_VERSION "0.11.21")
set(ORCA_UV_SHA256_aarch64-apple-darwin "1f921d491ba5ffeea774eb04d6681ecee379101341cbb1500394993b541bf3f4")
set(ORCA_UV_SHA256_x86_64-apple-darwin "f3c8e5708a84b920c18b691214d54d2b0da6b984789caae95d47c95120cb7765")
set(ORCA_UV_SHA256_aarch64-unknown-linux-gnu "88e800834007cc5efd4675f166eb2a51e7e3ad19876d85fa8805a6fb5c922397")
set(ORCA_UV_SHA256_x86_64-unknown-linux-gnu "8c88519b0ef0af9801fcdee419bbb12116bd9e6b18e162ae093c932d8b264050")
set(ORCA_UV_SHA256_x86_64-pc-windows-msvc "ace861f360c6de2babedc1607d0f454b6b09a820dbc8182dc15af927e4df9589")
# Version-scoped cache dir so a version bump invalidates the cached binary.
set(ORCA_UV_DOWNLOAD_DIR "${CMAKE_BINARY_DIR}/.uv/${ORCA_UV_VERSION}")
set(ORCA_UV_BINARY "${ORCA_UV_DOWNLOAD_DIR}/uv")
if(WIN32)
set(ORCA_UV_BINARY "${ORCA_UV_DOWNLOAD_DIR}/uv.exe")
endif()
# Older configures FORCE-cached the auto-downloaded path; any cache entry
# under .uv/ is that legacy value -- clear it so auto-download re-resolves
# (user-provided paths never live under .uv/).
if(ORCA_BUNDLED_UV_EXECUTABLE MATCHES "/\\.uv/")
set(ORCA_BUNDLED_UV_EXECUTABLE "" CACHE FILEPATH "Path to the auto-downloaded uv executable" FORCE)
endif()
if(NOT ORCA_BUNDLED_UV_EXECUTABLE)
if(NOT EXISTS "${ORCA_UV_BINARY}")
# Select uv by TARGET arch. On macOS universal builds each leg sets a single
# CMAKE_OSX_ARCHITECTURES (and the x86_64 leg cross-builds on an arm64 runner),
# so prefer it over the host CMAKE_SYSTEM_PROCESSOR -- otherwise both legs fetch
# the same arch and the later universal lipo merge of tools/uv/uv fails.
set(_orca_uv_proc "${CMAKE_SYSTEM_PROCESSOR}")
if(APPLE AND CMAKE_OSX_ARCHITECTURES)
set(_orca_uv_proc "${CMAKE_OSX_ARCHITECTURES}")
endif()
# All release archives are tar.gz except the Windows zip.
set(ORCA_UV_EXT "tar.gz")
if(_orca_uv_proc MATCHES "x86_64|AMD64|amd64")
if(WIN32)
set(ORCA_UV_ARCH "x86_64-pc-windows-msvc")
set(ORCA_UV_EXT "zip")
elseif(APPLE)
set(ORCA_UV_ARCH "x86_64-apple-darwin")
else()
set(ORCA_UV_ARCH "x86_64-unknown-linux-gnu")
endif()
elseif(_orca_uv_proc MATCHES "aarch64|arm64|ARM64")
if(APPLE)
set(ORCA_UV_ARCH "aarch64-apple-darwin")
else()
set(ORCA_UV_ARCH "aarch64-unknown-linux-gnu")
endif()
else()
message(WARNING "Unsupported architecture for auto-downloading uv: ${_orca_uv_proc}")
endif()
if(ORCA_UV_ARCH)
set(ORCA_UV_URL "https://github.com/astral-sh/uv/releases/download/${ORCA_UV_VERSION}/uv-${ORCA_UV_ARCH}.${ORCA_UV_EXT}")
set(ORCA_UV_ARCHIVE "${ORCA_UV_DOWNLOAD_DIR}/uv-archive.${ORCA_UV_EXT}")
file(MAKE_DIRECTORY "${ORCA_UV_DOWNLOAD_DIR}")
message(STATUS "Downloading uv ${ORCA_UV_VERSION} from ${ORCA_UV_URL} ...")
file(DOWNLOAD "${ORCA_UV_URL}" "${ORCA_UV_ARCHIVE}" STATUS ORCA_UV_DL_STATUS TLS_VERIFY ON)
list(GET ORCA_UV_DL_STATUS 0 ORCA_UV_DL_CODE)
list(GET ORCA_UV_DL_STATUS 1 ORCA_UV_DL_MSG)
if(NOT ORCA_UV_DL_CODE EQUAL 0)
# Network failure keeps the historical graceful degradation (uv is
# optional at build time) -- but a hash mismatch below is fatal.
message(WARNING "Failed to download uv: ${ORCA_UV_DL_MSG}")
file(REMOVE "${ORCA_UV_ARCHIVE}")
else()
file(SHA256 "${ORCA_UV_ARCHIVE}" _orca_uv_actual_sha256)
if(NOT _orca_uv_actual_sha256 STREQUAL "${ORCA_UV_SHA256_${ORCA_UV_ARCH}}")
file(REMOVE "${ORCA_UV_ARCHIVE}")
message(FATAL_ERROR
"uv archive checksum mismatch for ${ORCA_UV_ARCH} ${ORCA_UV_VERSION}:\n"
" expected ${ORCA_UV_SHA256_${ORCA_UV_ARCH}}\n"
" actual ${_orca_uv_actual_sha256}\n"
"Possible tampering or a stale pin; refusing to bundle.")
endif()
message(STATUS "Extracting uv ...")
file(ARCHIVE_EXTRACT INPUT "${ORCA_UV_ARCHIVE}" DESTINATION "${ORCA_UV_DOWNLOAD_DIR}")
file(REMOVE "${ORCA_UV_ARCHIVE}")
# Pinned archives have a fixed layout: the tarballs hold
# uv-<triple>/uv, the Windows zip holds uv.exe at the root
# (already at ORCA_UV_BINARY). A layout change implies a new
# archive, hence a hash bump -- and RENAME fails loudly.
if(NOT WIN32)
file(RENAME "${ORCA_UV_DOWNLOAD_DIR}/uv-${ORCA_UV_ARCH}/uv" "${ORCA_UV_BINARY}")
file(REMOVE_RECURSE "${ORCA_UV_DOWNLOAD_DIR}/uv-${ORCA_UV_ARCH}")
endif()
endif()
endif()
endif()
if(EXISTS "${ORCA_UV_BINARY}")
# Plain set (shadows the empty cache entry for this configure run):
# the version-scoped path re-derives every configure, so a version
# bump takes effect in warm build dirs without cache surgery.
set(ORCA_BUNDLED_UV_EXECUTABLE "${ORCA_UV_BINARY}")
endif()
endif()
# Resolve ORCA_BUNDLED_UV_EXECUTABLE -> ORCA_BUNDLED_UV_EXECUTABLE_CONFIG / ORCA_BUNDLED_UV_FILENAME
# Must run before add_subdirectory(src) so target_compile_definitions sees it.
if(ORCA_BUNDLED_UV_EXECUTABLE)
if(EXISTS "${ORCA_BUNDLED_UV_EXECUTABLE}")
file(TO_CMAKE_PATH "${ORCA_BUNDLED_UV_EXECUTABLE}" ORCA_BUNDLED_UV_EXECUTABLE_CONFIG)
get_filename_component(ORCA_BUNDLED_UV_FILENAME "${ORCA_BUNDLED_UV_EXECUTABLE}" NAME)
else()
message(WARNING "ORCA_BUNDLED_UV_EXECUTABLE does not exist: ${ORCA_BUNDLED_UV_EXECUTABLE}")
set(ORCA_BUNDLED_UV_EXECUTABLE "")
set(ORCA_BUNDLED_UV_EXECUTABLE_CONFIG "")
set(ORCA_BUNDLED_UV_FILENAME "")
endif()
else()
set(ORCA_BUNDLED_UV_EXECUTABLE_CONFIG "")
set(ORCA_BUNDLED_UV_FILENAME "")
endif()
# If SLIC3R_FHS is 1 -> SLIC3R_DESKTOP_INTEGRATION is always 0, othrewise variable.
CMAKE_DEPENDENT_OPTION(SLIC3R_DESKTOP_INTEGRATION "Allow performing desktop integration during runtime" 1 "NOT SLIC3R_FHS" 0)
@@ -750,6 +875,86 @@ endforeach()
find_package(NLopt 1.4 REQUIRED)
# Use bundled Python from deps instead of system Python
set(_bundled_python_version "3.12.13")
set(_bundled_python_abi "312")
string(REGEX REPLACE "^([0-9]+\\.[0-9]+)\\..*$" "\\1" _bundled_python_version_short "${_bundled_python_version}")
set(_bundled_python_root "${CMAKE_PREFIX_PATH}/libpython")
set(Python3_ROOT_DIR "${_bundled_python_root}" CACHE PATH "Root directory for bundled Python" FORCE)
set(Python3_USE_STATIC_LIBS OFF)
set(Python3_FIND_STRATEGY LOCATION)
set(Python3_FIND_IMPLEMENTATIONS CPython)
if(WIN32)
set(_bundled_python_executable "${_bundled_python_root}/python.exe")
set(_bundled_python_library "${_bundled_python_root}/libs/python${_bundled_python_abi}.lib")
if(EXISTS "${_bundled_python_root}/python_d.exe")
set(_bundled_python_executable "${_bundled_python_root}/python_d.exe")
endif()
if(EXISTS "${_bundled_python_root}/libs/python${_bundled_python_abi}_d.lib")
set(_bundled_python_library "${_bundled_python_root}/libs/python${_bundled_python_abi}_d.lib")
endif()
set(Python3_FIND_REGISTRY NEVER)
set(Python3_EXECUTABLE "${_bundled_python_executable}" CACHE FILEPATH "Bundled Python executable" FORCE)
set(Python3_INCLUDE_DIR "${_bundled_python_root}/include" CACHE PATH "Bundled Python include directory" FORCE)
set(Python3_LIBRARY "${_bundled_python_library}" CACHE FILEPATH "Bundled Python embed import library" FORCE)
elseif(APPLE)
set(Python3_FIND_FRAMEWORK NEVER)
find_program(_bundled_python_executable
NAMES python${_bundled_python_version_short} python3
PATHS "${_bundled_python_root}/bin"
NO_DEFAULT_PATH
)
find_path(_bundled_python_include_dir
NAMES Python.h
PATHS
"${_bundled_python_root}/include/python${_bundled_python_version_short}"
"${_bundled_python_root}/include"
NO_DEFAULT_PATH
)
find_library(_bundled_python_library
NAMES python${_bundled_python_version_short} libpython${_bundled_python_version_short}
PATHS "${_bundled_python_root}/lib"
NO_DEFAULT_PATH
)
if(NOT _bundled_python_executable)
message(FATAL_ERROR "Bundled Python executable not found under ${_bundled_python_root}/bin")
endif()
if(NOT _bundled_python_include_dir)
message(FATAL_ERROR "Bundled Python headers not found under ${_bundled_python_root}/include")
endif()
if(NOT _bundled_python_library)
message(FATAL_ERROR "Bundled Python library not found under ${_bundled_python_root}/lib")
endif()
set(Python3_EXECUTABLE "${_bundled_python_executable}" CACHE FILEPATH "Bundled Python executable" FORCE)
set(Python3_INCLUDE_DIR "${_bundled_python_include_dir}" CACHE PATH "Bundled Python include directory" FORCE)
set(Python3_LIBRARY "${_bundled_python_library}" CACHE FILEPATH "Bundled Python embed library" FORCE)
endif()
find_package(Python3 ${_bundled_python_version} EXACT REQUIRED
COMPONENTS Interpreter Development.Embed
)
# Provide a minimal pybind11::embed target sourced from deps_src/pybind11 headers.
set(PYBIND11_SOURCE_DIR "${CMAKE_SOURCE_DIR}/deps_src/pybind11")
if(NOT EXISTS "${PYBIND11_SOURCE_DIR}/include/pybind11/pybind11.h")
message(FATAL_ERROR "pybind11 headers not found in ${PYBIND11_SOURCE_DIR}. Did you initialize submodules?")
endif()
add_library(pybind11_headers INTERFACE)
target_include_directories(pybind11_headers INTERFACE "${PYBIND11_SOURCE_DIR}/include")
add_library(pybind11::headers ALIAS pybind11_headers)
add_library(pybind11::pybind11 ALIAS pybind11_headers)
add_library(pybind11_embed INTERFACE)
target_link_libraries(pybind11_embed INTERFACE pybind11_headers Python3::Python)
target_compile_definitions(pybind11_embed INTERFACE PYBIND11_SIMPLE_GIL_MANAGEMENT)
add_library(pybind11::embed ALIAS pybind11_embed)
if(SLIC3R_STATIC)
set(OPENVDB_USE_STATIC_LIBS ON)
@@ -899,10 +1104,12 @@ if (NOT WIN32 AND NOT APPLE)
configure_file(${LIBDIR}/dev-utils/platform/unix/build_appimage.sh.in ${CMAKE_CURRENT_BINARY_DIR}/build_appimage.sh USE_SOURCE_PERMISSIONS @ONLY)
endif()
# Resources install target, configure fhs.hpp on UNIX
if (WIN32)
install(DIRECTORY "${SLIC3R_RESOURCES_DIR}/" DESTINATION "./resources")
if(ORCA_BUNDLED_UV_EXECUTABLE)
install(PROGRAMS "${ORCA_BUNDLED_UV_EXECUTABLE}" DESTINATION "./resources/tools/uv" RENAME "${ORCA_BUNDLED_UV_FILENAME}")
endif()
set(CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS_SKIP TRUE)
include(InstallRequiredSystemLibraries)
install (PROGRAMS ${CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS} DESTINATION ".")
@@ -912,6 +1119,9 @@ elseif (SLIC3R_FHS)
install(DIRECTORY ${SLIC3R_RESOURCES_DIR}/ DESTINATION ${SLIC3R_FHS_RESOURCES}
PATTERN "*/udev" EXCLUDE
)
if(ORCA_BUNDLED_UV_EXECUTABLE)
install(PROGRAMS "${ORCA_BUNDLED_UV_EXECUTABLE}" DESTINATION "${SLIC3R_FHS_RESOURCES}/tools/uv" RENAME "${ORCA_BUNDLED_UV_FILENAME}")
endif()
install(FILES src/dev-utils/platform/unix/com.orcaslicer.OrcaSlicer.desktop DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/applications)
foreach(SIZE 32 128 192)
install(FILES ${SLIC3R_RESOURCES_DIR}/images/OrcaSlicer_${SIZE}px.png
@@ -920,9 +1130,15 @@ elseif (SLIC3R_FHS)
endforeach()
elseif (CMAKE_MACOSX_BUNDLE)
# install(DIRECTORY "${SLIC3R_RESOURCES_DIR}/" DESTINATION "${CMAKE_INSTALL_PREFIX}/OrcaSlicer.app/Contents/resources")
if(ORCA_BUNDLED_UV_EXECUTABLE)
install(PROGRAMS "${ORCA_BUNDLED_UV_EXECUTABLE}" DESTINATION "${CMAKE_INSTALL_PREFIX}/OrcaSlicer.app/Contents/Resources/tools/uv" RENAME "${ORCA_BUNDLED_UV_FILENAME}")
endif()
else ()
install(FILES src/dev-utils/platform/unix/com.orcaslicer.OrcaSlicer.desktop DESTINATION ${CMAKE_INSTALL_PREFIX}/resources/applications)
install(DIRECTORY "${SLIC3R_RESOURCES_DIR}/" DESTINATION "${CMAKE_INSTALL_PREFIX}/resources")
if(ORCA_BUNDLED_UV_EXECUTABLE)
install(PROGRAMS "${ORCA_BUNDLED_UV_EXECUTABLE}" DESTINATION "${CMAKE_INSTALL_PREFIX}/resources/tools/uv" RENAME "${ORCA_BUNDLED_UV_FILENAME}")
endif()
endif ()
install(FILES ${CMAKE_SOURCE_DIR}/LICENSE.txt DESTINATION ".")

View File

@@ -179,6 +179,66 @@ function pack_deps() {
)
}
# codesign cannot seal the runtime's dotted directories (include/python3.12,
# lib/python3.12) anywhere under Contents/MacOS -- it mistakes any dotted
# directory there for a nested bundle and fails with "bundle format
# unrecognized" -- so packaged apps ship the runtime under Contents/Resources
# with a compatibility symlink that keeps every Contents/MacOS/python path and
# the @executable_path/python/lib rpath resolving unchanged.
function relocate_python_runtime() {
local app="$1"
local pydir="$app/Contents/MacOS/python"
if [ -d "$pydir" ] && [ ! -L "$pydir" ]; then
rm -rf "$app/Contents/Resources/python"
mv "$pydir" "$app/Contents/Resources/python"
ln -s ../Resources/python "$pydir"
fi
}
# --- Bundled Python runtime verification --------------------------------------
# Relocation is handled at the source: deps/python3/python3.cmake stamps
# libpython with an @rpath id and src/CMakeLists.txt gives the app a matching
# rpath. This gate catches regressions that would otherwise only surface as
# launch failures on end users' machines (the absolute deps path still exists
# on the build host, so a plain run can pass while relocation is broken --
# hence the otool checks). The x86_64 leg runs under Rosetta on arm64 hosts.
function verify_python_runtime() {
local app="$1"
local pydir="$app/Contents/MacOS/python"
[ -d "$pydir" ] || return 0 # app doesn't bundle Python (e.g. profile validator)
if [ ! -L "$pydir" ]; then
echo "ERROR: Contents/MacOS/python must be a symlink into Contents/Resources" >&2
echo " (see relocate_python_runtime in this script)" >&2
exit 1
fi
# Version-agnostic interpreter name so a CPython version bump cannot
# silently skip the gate; if the dir exists the interpreter must too.
local pybin="$pydir/bin/python3"
if [ ! -x "$pybin" ]; then
echo "ERROR: bundled python/ present but no interpreter at $pybin" >&2
exit 1
fi
echo " Verifying bundled Python runtime in $(basename "$app")..."
local bad
bad=$(otool -arch all -L "$pybin" "$app/Contents/MacOS/OrcaSlicer" | grep "libpython" | grep -v "@rpath/" || true)
if [ -n "$bad" ]; then
echo "ERROR: a bundled binary references libpython by absolute path (relocation regression):" >&2
echo "$bad" >&2
exit 1
fi
# otool -L shows load commands only; assert the consumer rpath separately.
# Its loss is masked on the build host by CMake's absolute build-tree rpath.
if ! otool -arch all -l "$app/Contents/MacOS/OrcaSlicer" | grep -q "path @executable_path/python/lib "; then
echo "ERROR: OrcaSlicer lacks the @executable_path/python/lib rpath (relocation regression)" >&2
exit 1
fi
if ! "$pybin" -c "import ssl"; then
echo "ERROR: bundled Python failed to start (libpython relocation broken," >&2
echo " or missing Rosetta 2 for the x86_64 leg?)" >&2
exit 1
fi
}
function build_slicer() {
# iterate over two architectures: x86_64 and arm64
for _ARCH in x86_64 arm64; do
@@ -234,8 +294,11 @@ function build_slicer() {
resources_path=$(readlink ./OrcaSlicer.app/Contents/Resources)
rm ./OrcaSlicer.app/Contents/Resources
cp -R "$resources_path" ./OrcaSlicer.app/Contents/Resources
relocate_python_runtime ./OrcaSlicer.app
# delete .DS_Store file
find ./OrcaSlicer.app/ -name '.DS_Store' -delete
verify_python_runtime ./OrcaSlicer.app
# Copy OrcaSlicer_profile_validator.app if it exists
if [ -f "../src$BUILD_DIR_CONFIG_SUBDIR/OrcaSlicer_profile_validator.app/Contents/MacOS/OrcaSlicer_profile_validator" ]; then
@@ -244,6 +307,7 @@ function build_slicer() {
cp -pR "../src$BUILD_DIR_CONFIG_SUBDIR/OrcaSlicer_profile_validator.app" ./OrcaSlicer_profile_validator.app
# delete .DS_Store file
find ./OrcaSlicer_profile_validator.app/ -name '.DS_Store' -delete
verify_python_runtime ./OrcaSlicer_profile_validator.app
fi
)
@@ -299,6 +363,7 @@ function build_universal() {
echo "Creating universal binaries for OrcaSlicer.app..."
lipo_dir "$UNIVERSAL_APP" "$X86_64_APP"
echo "Universal OrcaSlicer.app created at $UNIVERSAL_APP"
verify_python_runtime "$UNIVERSAL_APP"
# Create universal binary for profile validator if it exists
ARM64_VALIDATOR="$PROJECT_DIR/build/arm64/OrcaSlicer/OrcaSlicer_profile_validator.app"

2
deps/CMakeLists.txt vendored
View File

@@ -422,6 +422,7 @@ endif ()
include(OCCT/OCCT.cmake)
include(OpenCV/OpenCV.cmake)
include(python3/python3.cmake)
set(_dep_list
dep_Boost
@@ -444,6 +445,7 @@ set(_dep_list
${ZLIB_PKG}
${EXPAT_PKG}
dep_libnoise
dep_python3
)
if (MSVC)

71
deps/python3/01-windows-nuget.patch vendored Normal file
View File

@@ -0,0 +1,71 @@
From b32e63f75046d186d93ee7d627c978f2f7c892f3 Mon Sep 17 00:00:00 2001
From: Steve Dower <steve.dower@python.org>
Date: Fri, 10 Jul 2026 14:04:00 +0100
Subject: [PATCH] [3.13] gh-153438: Update NuGet download URL (GH-153482)
(GH-153515)
gh-153438: Update NuGet download URL (GH-153482)
(cherry picked from commit 106eb532ea3b243423e62a702719e9d3c0e40c16)
(cherry picked from commit 62eb50d65d538dda5164f9c4a097a896454a0d1c)
Co-authored-by: Steve Dower <steve.dower@python.org>
Co-authored-by: Harjoth Khara <harjoth.khara@gmail.com>
---
Doc/using/windows.rst | 6 +++---
.../Build/2026-07-09-22-45-00.gh-issue-153438.Qr7N2p.rst | 2 ++
PCbuild/find_python.bat | 2 +-
Tools/msi/get_externals.bat | 2 +-
4 files changed, 7 insertions(+), 5 deletions(-)
create mode 100644 Misc/NEWS.d/next/Build/2026-07-09-22-45-00.gh-issue-153438.Qr7N2p.rst
diff --git a/Doc/using/windows.rst b/Doc/using/windows.rst
index 2a507675044666..4800789ca2d6cc 100644
--- a/Doc/using/windows.rst
+++ b/Doc/using/windows.rst
@@ -414,9 +414,9 @@ on using nuget. What follows is a summary that is sufficient for Python
developers.
The ``nuget.exe`` command line tool may be downloaded directly from
-``https://aka.ms/nugetclidl``, for example, using curl or PowerShell. With the
-tool, the latest version of Python for 64-bit or 32-bit machines is installed
-using::
+``https://dist.nuget.org/win-x86-commandline/latest/nuget.exe``, for example,
+using curl or PowerShell. With the tool, the latest version of Python for
+64-bit or 32-bit machines is installed using::
nuget.exe install python -ExcludeVersion -OutputDirectory .
nuget.exe install pythonx86 -ExcludeVersion -OutputDirectory .
diff --git a/Misc/NEWS.d/next/Build/2026-07-09-22-45-00.gh-issue-153438.Qr7N2p.rst b/Misc/NEWS.d/next/Build/2026-07-09-22-45-00.gh-issue-153438.Qr7N2p.rst
new file mode 100644
index 00000000000000..edab8e6ba7b259
--- /dev/null
+++ b/Misc/NEWS.d/next/Build/2026-07-09-22-45-00.gh-issue-153438.Qr7N2p.rst
@@ -0,0 +1,2 @@
+Update Windows build and installer tooling and documentation to use the
+current download URL for ``nuget.exe``.
diff --git a/PCbuild/find_python.bat b/PCbuild/find_python.bat
index 0af367a3efafad..9612a2860ef9c3 100644
--- a/PCbuild/find_python.bat
+++ b/PCbuild/find_python.bat
@@ -52,7 +52,7 @@
@set _Py_HOST_PYTHON=%HOST_PYTHON%
@if "%_Py_HOST_PYTHON%"=="" set _Py_HOST_PYTHON=py
@if "%_Py_NUGET%"=="" (set _Py_NUGET=%_Py_EXTERNALS_DIR%\nuget.exe)
-@if "%_Py_NUGET_URL%"=="" (set _Py_NUGET_URL=https://aka.ms/nugetclidl)
+@if "%_Py_NUGET_URL%"=="" (set _Py_NUGET_URL=https://dist.nuget.org/win-x86-commandline/latest/nuget.exe)
@if NOT exist "%_Py_NUGET%" (
@if not "%_Py_Quiet%"=="1" @echo Downloading nuget...
@rem NB: Must use single quotes around NUGET here, NOT double!
diff --git a/Tools/msi/get_externals.bat b/Tools/msi/get_externals.bat
index f6602ce9588ff4..c7c7e9f470bc25 100644
--- a/Tools/msi/get_externals.bat
+++ b/Tools/msi/get_externals.bat
@@ -6,7 +6,7 @@ set HERE=%~dp0
if "%PCBUILD%"=="" (set PCBUILD=%HERE%..\..\PCbuild\)
if "%EXTERNALS_DIR%"=="" (set EXTERNALS_DIR=%HERE%..\..\externals\windows-installer)
if "%NUGET%"=="" (set NUGET=%EXTERNALS_DIR%\..\nuget.exe)
-if "%NUGET_URL%"=="" (set NUGET_URL=https://aka.ms/nugetclidl)
+if "%NUGET_URL%"=="" (set NUGET_URL=https://dist.nuget.org/win-x86-commandline/latest/nuget.exe)
set DO_FETCH=true
set DO_CLEAN=false

279
deps/python3/python3.cmake vendored Normal file
View File

@@ -0,0 +1,279 @@
include(ProcessorCount)
ProcessorCount(NPROC)
set(_python_version "3.12.13")
string(REGEX REPLACE "^([0-9]+\\.[0-9]+)\\..*" "\\1" _python_version_short "${_python_version}")
set(_python_url "https://www.python.org/ftp/python/${_python_version}/Python-${_python_version}.tar.xz")
set(_python_sha256 "c08bc65a81971c1dd5783182826503369466c7e67374d1646519adf05207b684")
set(_patch_cmd "")
if(WIN32)
# Fix python build failure on Windows if python is not available, due to wrong nuget download URL
# See https://github.com/python/cpython/issues/153438
# Patch from https://github.com/python/cpython/pull/153608
# This patch has not been merged to 3.12 yet so we need to apply it manually
set(_patch_cmd git init && ${PATCH_CMD} ${CMAKE_CURRENT_LIST_DIR}/01-windows-nuget.patch)
if(MSVC_VERSION EQUAL 1800)
set(_python_platform_toolset v120)
elseif(MSVC_VERSION EQUAL 1900)
set(_python_platform_toolset v140)
elseif(MSVC_VERSION LESS 1920)
set(_python_platform_toolset v141)
elseif(MSVC_VERSION LESS 1930)
set(_python_platform_toolset v142)
elseif(MSVC_VERSION LESS 1950)
set(_python_platform_toolset v143)
elseif(MSVC_VERSION LESS 1960)
set(_python_platform_toolset v145)
else()
message(FATAL_ERROR "Unsupported MSVC version for CPython build: ${MSVC_VERSION}")
endif()
# 64-bit-hosted MSBuild selection (see the build-step comment below). Default
# to the amd64 host + x64 tools; only the native ARM64 build differs.
set(_python_msbuild_host amd64)
set(_python_tool_arch x64)
if(CMAKE_SYSTEM_PROCESSOR MATCHES "ARM64|aarch64")
set(_python_pcbuild_platform ARM64)
set(_python_layout_arch arm64)
set(_python_pcbuild_output_dir arm64)
set(_python_msbuild_host arm64) # native ARM64 MSBuild already hosts arm64 tools
set(_python_tool_arch "")
elseif(CMAKE_SIZEOF_VOID_P EQUAL 8)
set(_python_pcbuild_platform x64)
set(_python_layout_arch amd64)
set(_python_pcbuild_output_dir amd64)
else()
set(_python_pcbuild_platform Win32)
set(_python_layout_arch win32)
set(_python_pcbuild_output_dir win32)
endif()
set(_python_pcbuild_config Release)
set(_python_layout_debug OFF)
if(DEFINED DEP_DEBUG AND DEP_DEBUG)
set(_python_pcbuild_config Debug)
set(_python_layout_debug ON)
endif()
# CPython's PCbuild needs a 64-bit-hosted toolchain: find_msbuild.bat picks the
# 32-bit Bin\MSBuild.exe, whose x86 cl.exe/link.exe run out of address space
# (fatal C1002 "out of heap space") building the LTCG-optimized pythoncore.
# That 32-bit MSBuild ignores PreferredToolArchitecture, so build.bat must be
# pointed at a 64-bit MSBuild via the MSBUILD env var. The native arm64 MSBuild
# then hosts arm64 tools on its own; the amd64 MSBuild still defaults to x86, so
# PreferredToolArchitecture pins it to x64. Scoped to this build step, so
# CPython's own sources stay untouched.
set(_python_env_args "GIT_CEILING_DIRECTORIES=<SOURCE_DIR>/..")
if(CMAKE_GENERATOR_INSTANCE) # empty for non-VS generators (e.g. Ninja)
set(_python_msbuild "${CMAKE_GENERATOR_INSTANCE}/MSBuild/Current/Bin/${_python_msbuild_host}/MSBuild.exe")
if(EXISTS "${_python_msbuild}")
file(TO_NATIVE_PATH "${_python_msbuild}" _python_msbuild_native)
list(APPEND _python_env_args "MSBUILD=${_python_msbuild_native}")
else()
# Loud signal: a silent fall-through to the 32-bit MSBuild reintroduces C1002.
message(WARNING "Bundled Python: 64-bit MSBuild not found at '${_python_msbuild}'. "
"CPython will fall back to find_msbuild.bat's default (32-bit) MSBuild, which may "
"fail with C1002 (out of heap space) building the optimized pythoncore.")
endif()
endif()
if(_python_tool_arch)
list(APPEND _python_env_args "PreferredToolArchitecture=${_python_tool_arch}")
endif()
set(_conf_cmd
cmd /c "echo /p:PlatformToolset=${_python_platform_toolset}>PCbuild\\msbuild.rsp"
)
set(_build_cmd
${CMAKE_COMMAND} -E env ${_python_env_args}
cmd /c PCbuild\\build.bat
-p ${_python_pcbuild_platform}
-c ${_python_pcbuild_config}
--no-tkinter
)
set(_install_cmd
${CMAKE_COMMAND}
-DPYTHON_SOURCE_DIR=<SOURCE_DIR>
-DPYTHON_BUILD_DIR=<SOURCE_DIR>/PCbuild/${_python_pcbuild_output_dir}
-DPYTHON_DEST_DIR=${DESTDIR}/libpython
-DPYTHON_LAYOUT_ARCH=${_python_layout_arch}
-DPYTHON_DEBUG=${_python_layout_debug}
-P ${CMAKE_CURRENT_LIST_DIR}/stage_windows.cmake
)
elseif(APPLE)
# macOS configuration
if(CMAKE_OSX_ARCHITECTURES)
set(_python_target_arch "${CMAKE_OSX_ARCHITECTURES}")
else()
set(_python_target_arch "${CMAKE_SYSTEM_PROCESSOR}")
endif()
if(CMAKE_SYSTEM_PROCESSOR MATCHES "ARM64|arm64|aarch64")
set(_python_build_arch aarch64)
set(_python_build_arch_flag "arm64")
elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "x86_64|AMD64|amd64")
set(_python_build_arch x86_64)
set(_python_build_arch_flag "x86_64")
else()
set(_python_build_arch "${CMAKE_SYSTEM_PROCESSOR}")
set(_python_build_arch_flag "${CMAKE_SYSTEM_PROCESSOR}")
endif()
if(_python_target_arch MATCHES "ARM64|arm64|aarch64")
set(_python_host_arch aarch64)
set(_python_arch_flag "arm64")
elseif(_python_target_arch MATCHES "x86_64|AMD64|amd64")
set(_python_host_arch x86_64)
set(_python_arch_flag "x86_64")
else()
message(FATAL_ERROR "Unsupported macOS Python target architecture: ${_python_target_arch}")
endif()
set(_python_arch_flags "-arch ${_python_arch_flag} -mmacosx-version-min=${CMAKE_OSX_DEPLOYMENT_TARGET}")
# No -rpath: all other deps are static, so libpython has no shared
# dependencies to find there. headerpad reserves load-command space for
# the post-install -add_rpath below.
set(_python_ldflags "${_python_arch_flags} -Wl,-headerpad_max_install_names")
if(IS_CROSS_COMPILE)
set(_python_build_tgt --build=${_python_build_arch}-apple-darwin --host=${_python_host_arch}-apple-darwin)
set(_python_build_arch_flags "-arch ${_python_build_arch_flag} -mmacosx-version-min=${CMAKE_OSX_DEPLOYMENT_TARGET}")
set(_python_build_ldflags "${_python_build_arch_flags} -Wl,-rpath,${DESTDIR}/lib")
set(_python_build_python_dir "<SOURCE_DIR>/build-python-host")
set(_python_build_python "${_python_build_python_dir}/python")
set(_conf_cmd
/bin/sh -c
"rm -rf '${_python_build_python_dir}' && \
mkdir -p '${_python_build_python_dir}' && \
cd '${_python_build_python_dir}' && \
env \
CC='${CMAKE_C_COMPILER}' \
CXX='${CMAKE_CXX_COMPILER}' \
CFLAGS='${_python_build_arch_flags}' \
CXXFLAGS='${_python_build_arch_flags}' \
LDFLAGS='${_python_build_ldflags}' \
MACOSX_DEPLOYMENT_TARGET='${CMAKE_OSX_DEPLOYMENT_TARGET}' \
../configure \
--prefix='${_python_build_python_dir}/install' \
--enable-shared \
--without-static-libpython \
--disable-test-modules \
--build=${_python_build_arch}-apple-darwin && \
make -j${NPROC} python && \
cd '<SOURCE_DIR>' && \
env \
CC='${CMAKE_C_COMPILER}' \
CXX='${CMAKE_CXX_COMPILER}' \
CFLAGS='${_python_arch_flags}' \
CXXFLAGS='${_python_arch_flags}' \
LDFLAGS='${_python_ldflags}' \
MACOSX_DEPLOYMENT_TARGET='${CMAKE_OSX_DEPLOYMENT_TARGET}' \
./configure \
--prefix='${DESTDIR}/libpython' \
--enable-shared \
--enable-optimizations \
--without-static-libpython \
--with-openssl='${DESTDIR}' \
--disable-test-modules \
${_python_build_tgt} \
--with-build-python='${_python_build_python}' \
py_cv_module__tkinter=n/a"
)
else()
set(_python_build_tgt --build=${_python_host_arch}-apple-darwin)
set(_conf_cmd
env
"CC=${CMAKE_C_COMPILER}"
"CXX=${CMAKE_CXX_COMPILER}"
"CFLAGS=${_python_arch_flags}"
"CXXFLAGS=${_python_arch_flags}"
"LDFLAGS=${_python_ldflags}"
"MACOSX_DEPLOYMENT_TARGET=${CMAKE_OSX_DEPLOYMENT_TARGET}"
./configure
--prefix=${DESTDIR}/libpython
--enable-shared
--enable-optimizations
--without-static-libpython
--with-openssl=${DESTDIR}
--disable-test-modules
${_python_build_tgt}
# Tcl/Tk 9.0 (e.g. from Homebrew) is incompatible with CPython 3.12's
# _tkinter; OrcaSlicer's embedded Python does not need tkinter anyway.
py_cv_module__tkinter=n/a
)
endif()
set(_build_cmd make -j${NPROC})
# CPython stamps libpython with an absolute install name ($prefix/lib/...),
# which every consumer inherits at link time and which only exists on the
# build host. Normalize once here, before anything links against the dep:
# give the dylib an @rpath id and teach the interpreter to find it relative
# to itself. Consumers then just need an rpath entry (src/CMakeLists.txt).
# install_name_tool invalidates code signatures, so re-sign ad-hoc; CI
# re-signs the whole bundle with the real identity later.
# ld collapses '//' in -install_name (but not in -rpath) strings, while
# ${DESTDIR} ends with a slash -- collapse slashes so -change matches the
# recorded install name.
string(REGEX REPLACE "/+" "/" _python_prefix "${DESTDIR}/libpython")
set(_python_dylib "${_python_prefix}/lib/libpython${_python_version_short}.dylib")
set(_python_bin "${_python_prefix}/bin/python${_python_version_short}")
set(_install_cmd make install
COMMAND install_name_tool -id "@rpath/libpython${_python_version_short}.dylib" "${_python_dylib}"
COMMAND install_name_tool -change "${_python_dylib}" "@rpath/libpython${_python_version_short}.dylib" "${_python_bin}"
COMMAND install_name_tool -add_rpath "@loader_path/../lib" "${_python_bin}"
COMMAND codesign --force --sign - "${_python_dylib}"
COMMAND codesign --force --sign - "${_python_bin}"
)
else()
# Linux/Unix
# Kept verbatim, no slash normalization (unlike the macOS branch's
# collapsed copy): the LDFLAGS rpath below is recorded byte-for-byte in
# the ELF, and the OLD_RPATH handed to relocate_linux.cmake must match it
# exactly -- both derive from this one variable to make that structural.
set(_python_prefix "${DESTDIR}/libpython")
# The rpath points at libpython's real install dir, so the interpreter runs
# in-tree pre-relocation -- and, critically, it reserves enough RUNPATH
# bytes for the in-place $ORIGIN rewrite at install time (Flatpak's
# DESTDIR is the short /app) -- see relocate_linux.cmake.
set(_conf_cmd ./configure
--prefix=${_python_prefix}
--enable-shared
--enable-optimizations
--with-openssl=${DESTDIR}
--without-static-libpython
--disable-test-modules
# Tcl/Tk 9.0 is incompatible with CPython 3.12's _tkinter; not needed here.
py_cv_module__tkinter=n/a
LDFLAGS=-Wl,-rpath,${_python_prefix}/lib
)
set(_build_cmd make -j${NPROC})
set(_install_cmd make install
COMMAND ${CMAKE_COMMAND}
"-DPYTHON_BIN=${_python_prefix}/bin/python${_python_version_short}"
"-DOLD_RPATH=${_python_prefix}/lib"
-P "${CMAKE_CURRENT_LIST_DIR}/relocate_linux.cmake"
)
endif()
ExternalProject_Add(dep_python3
URL "${_python_url}"
URL_HASH SHA256=${_python_sha256}
PATCH_COMMAND ${_patch_cmd}
DOWNLOAD_DIR ${DEP_DOWNLOAD_DIR}/python3
BUILD_IN_SOURCE ON
CONFIGURE_COMMAND ${_conf_cmd}
BUILD_COMMAND ${_build_cmd}
INSTALL_COMMAND ${_install_cmd}
)
# Python depends on OpenSSL and ZLIB
if(TARGET dep_OpenSSL)
add_dependencies(dep_python3 dep_OpenSSL)
endif()
if(TARGET dep_ZLIB)
add_dependencies(dep_python3 dep_ZLIB)
endif()

10
deps/python3/relocate_linux.cmake vendored Normal file
View File

@@ -0,0 +1,10 @@
# Repoint the installed interpreter's RUNPATH from the absolute deps dir to a
# self-relative entry so the bundled runtime is relocatable (the deps tree,
# Flatpak /app/libpython, and AppImage $APPDIR/lib/python all keep bin/ and
# lib/ as siblings). $ORIGIN is expanded by the dynamic loader; CMake leaves
# it alone (only ${...} is expanded here). RPATH_CHANGE edits the ELF in
# place, so the new entry must not be longer than the old one: the reserved
# ${DESTDIR}/libpython/lib is at least 18 bytes even for the shortest
# supported DESTDIR (Flatpak's /app), longer than the 14-byte $ORIGIN/../lib.
# Invoked from python3.cmake with -DPYTHON_BIN=... -DOLD_RPATH=...
file(RPATH_CHANGE FILE "${PYTHON_BIN}" OLD_RPATH "${OLD_RPATH}" NEW_RPATH "$ORIGIN/../lib")

72
deps/python3/stage_windows.cmake vendored Normal file
View File

@@ -0,0 +1,72 @@
cmake_minimum_required(VERSION 3.13)
set(_python_abi "312")
foreach(_var PYTHON_SOURCE_DIR PYTHON_BUILD_DIR PYTHON_DEST_DIR PYTHON_LAYOUT_ARCH)
if(NOT DEFINED ${_var} OR "${${_var}}" STREQUAL "")
message(FATAL_ERROR "${_var} is required")
endif()
endforeach()
set(_python_exe "${PYTHON_BUILD_DIR}/python.exe")
if(PYTHON_DEBUG)
set(_python_exe "${PYTHON_BUILD_DIR}/python_d.exe")
endif()
if(NOT EXISTS "${_python_exe}")
message(FATAL_ERROR "Built Python executable not found: ${_python_exe}")
endif()
file(REMOVE_RECURSE "${PYTHON_DEST_DIR}")
file(MAKE_DIRECTORY "${PYTHON_DEST_DIR}")
# CPython's Windows layout helper reads LICENSE.txt from the build output.
# Source archives ship this file as LICENSE, so provide the expected name.
if(EXISTS "${PYTHON_SOURCE_DIR}/LICENSE" AND NOT EXISTS "${PYTHON_BUILD_DIR}/LICENSE.txt")
configure_file("${PYTHON_SOURCE_DIR}/LICENSE" "${PYTHON_BUILD_DIR}/LICENSE.txt" COPYONLY)
endif()
execute_process(
COMMAND
"${CMAKE_COMMAND}" -E env
"PYTHONHOME="
"PYTHONPATH=${PYTHON_SOURCE_DIR}/Lib"
"${_python_exe}"
"${PYTHON_SOURCE_DIR}/PC/layout"
--source "${PYTHON_SOURCE_DIR}"
--build "${PYTHON_BUILD_DIR}"
--arch "${PYTHON_LAYOUT_ARCH}"
--copy "${PYTHON_DEST_DIR}"
--include-dev
WORKING_DIRECTORY "${PYTHON_SOURCE_DIR}"
RESULT_VARIABLE _layout_result
)
if(NOT _layout_result EQUAL 0)
message(FATAL_ERROR "CPython Windows layout staging failed with exit code ${_layout_result}")
endif()
set(_required_files
"${PYTHON_DEST_DIR}/Lib/encodings/__init__.py"
"${PYTHON_DEST_DIR}/include/Python.h"
)
if(PYTHON_DEBUG)
list(APPEND _required_files
"${PYTHON_DEST_DIR}/python_d.exe"
"${PYTHON_DEST_DIR}/python${_python_abi}_d.dll"
"${PYTHON_DEST_DIR}/libs/python${_python_abi}_d.lib"
)
else()
list(APPEND _required_files
"${PYTHON_DEST_DIR}/python.exe"
"${PYTHON_DEST_DIR}/python${_python_abi}.dll"
"${PYTHON_DEST_DIR}/libs/python${_python_abi}.lib"
)
endif()
foreach(_required_file IN LISTS _required_files)
if(NOT EXISTS "${_required_file}")
message(FATAL_ERROR "Staged Python file missing: ${_required_file}")
endif()
endforeach()

29
deps_src/pybind11/LICENSE Normal file
View File

@@ -0,0 +1,29 @@
Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch>, All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its contributors
may be used to endorse or promote products derived from this software
without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Please also refer to the file .github/CONTRIBUTING.md, which clarifies licensing of
external contributions to this project including patches, pull requests, etc.

View File

@@ -0,0 +1,216 @@
.. figure:: https://github.com/pybind/pybind11/raw/master/docs/pybind11-logo.png
:alt: pybind11 logo
**pybind11 (v3) — Seamless interoperability between C++ and Python**
|Latest Documentation Status| |Stable Documentation Status| |Gitter chat| |GitHub Discussions|
|CI| |Build status| |SPEC 4 — Using and Creating Nightly Wheels|
|Repology| |PyPI package| |Conda-forge| |Python Versions|
`Setuptools example <https://github.com/pybind/python_example>`_
`Scikit-build example <https://github.com/pybind/scikit_build_example>`_
`CMake example <https://github.com/pybind/cmake_example>`_
.. start
**pybind11** is a lightweight header-only library that exposes C++ types
in Python and vice versa, mainly to create Python bindings of existing
C++ code. Its goals and syntax are similar to the excellent
`Boost.Python <http://www.boost.org/doc/libs/1_58_0/libs/python/doc/>`_
library by David Abrahams: to minimize boilerplate code in traditional
extension modules by inferring type information using compile-time
introspection.
The main issue with Boost.Python—and the reason for creating such a
similar project—is Boost. Boost is an enormously large and complex suite
of utility libraries that works with almost every C++ compiler in
existence. This compatibility has its cost: arcane template tricks and
workarounds are necessary to support the oldest and buggiest of compiler
specimens. Now that C++11-compatible compilers are widely available,
this heavy machinery has become an excessively large and unnecessary
dependency.
Think of this library as a tiny self-contained version of Boost.Python
with everything stripped away that isn't relevant for binding
generation. Without comments, the core header files only require ~4K
lines of code and depend on Python (CPython 3.8+, PyPy, or GraalPy) and the C++
standard library. This compact implementation was possible thanks to some C++11
language features (specifically: tuples, lambda functions and variadic
templates). Since its creation, this library has grown beyond Boost.Python in
many ways, leading to dramatically simpler binding code in many common
situations.
Tutorial and reference documentation is provided at
`pybind11.readthedocs.io <https://pybind11.readthedocs.io/en/latest>`_.
A PDF version of the manual is available
`here <https://pybind11.readthedocs.io/_/downloads/en/latest/pdf/>`_.
And the source code is always available at
`github.com/pybind/pybind11 <https://github.com/pybind/pybind11>`_.
Core features
-------------
pybind11 can map the following core C++ features to Python:
- Functions accepting and returning custom data structures per value,
reference, or pointer
- Instance methods and static methods
- Overloaded functions
- Instance attributes and static attributes
- Arbitrary exception types
- Enumerations
- Callbacks
- Iterators and ranges
- Custom operators
- Single and multiple inheritance
- STL data structures
- Smart pointers with reference counting like ``std::shared_ptr``
- Internal references with correct reference counting
- C++ classes with virtual (and pure virtual) methods can be extended
in Python
- Integrated NumPy support (NumPy 2 requires pybind11 2.12+)
Goodies
-------
In addition to the core functionality, pybind11 provides some extra
goodies:
- CPython 3.8+, PyPy3 7.3.17+, and GraalPy 24.1+ are supported with an
implementation-agnostic interface (see older versions for older CPython
and PyPy versions).
- It is possible to bind C++11 lambda functions with captured
variables. The lambda capture data is stored inside the resulting
Python function object.
- pybind11 uses C++11 move constructors and move assignment operators
whenever possible to efficiently transfer custom data types.
- It's easy to expose the internal storage of custom data types through
Pythons' buffer protocols. This is handy e.g. for fast conversion
between C++ matrix classes like Eigen and NumPy without expensive
copy operations.
- pybind11 can automatically vectorize functions so that they are
transparently applied to all entries of one or more NumPy array
arguments.
- Python's slice-based access and assignment operations can be
supported with just a few lines of code.
- Everything is contained in just a few header files; there is no need
to link against any additional libraries.
- Binaries are generally smaller by a factor of at least 2 compared to
equivalent bindings generated by Boost.Python. A recent pybind11
conversion of PyRosetta, an enormous Boost.Python binding project,
`reported <https://graylab.jhu.edu/Sergey/2016.RosettaCon/PyRosetta-4.pdf>`_
a binary size reduction of **5.4x** and compile time reduction by
**5.8x**.
- Function signatures are precomputed at compile time (using
``constexpr``), leading to smaller binaries.
- With little extra effort, C++ types can be pickled and unpickled
similar to regular Python objects.
Supported compilers
-------------------
1. Clang/LLVM 3.3 or newer (for Apple Xcode's clang, this is 5.0.0 or
newer)
2. GCC 4.8 or newer
3. Microsoft Visual Studio 2022 or newer (2019 probably works, but was dropped in CI)
4. Intel classic C++ compiler 18 or newer (ICC 20.2 tested in CI)
5. Cygwin/GCC (previously tested on 2.5.1)
6. NVCC (CUDA 11.0 tested in CI)
7. NVIDIA PGI (20.9 tested in CI)
Supported Platforms
-------------------
* Windows, Linux, macOS, and iOS
* CPython 3.8+, Pyodide, PyPy, and GraalPy
* C++11, C++14, C++17, C++20, and C++23
About
-----
This project was created by `Wenzel
Jakob <http://rgl.epfl.ch/people/wjakob>`_. Significant features and/or
improvements to the code were contributed by
Jonas Adler,
Lori A. Burns,
Sylvain Corlay,
Eric Cousineau,
Aaron Gokaslan,
Ralf Grosse-Kunstleve,
Trent Houliston,
Axel Huebl,
@hulucc,
Yannick Jadoul,
Sergey Lyskov,
Johan Mabille,
Tomasz Miąsko,
Dean Moldovan,
Ben Pritchard,
Jason Rhinelander,
Boris Schäling,
Pim Schellart,
Henry Schreiner,
Ivan Smirnov,
Dustin Spicuzza,
Boris Staletic,
Ethan Steinberg,
Patrick Stewart,
Ivor Wanders,
and
Xiaofei Wang.
We thank Google for a generous financial contribution to the continuous
integration infrastructure used by this project.
Contributing
~~~~~~~~~~~~
See the `contributing
guide <https://github.com/pybind/pybind11/blob/master/.github/CONTRIBUTING.md>`_
for information on building and contributing to pybind11.
License
~~~~~~~
pybind11 is provided under a BSD-style license that can be found in the
`LICENSE <https://github.com/pybind/pybind11/blob/master/LICENSE>`_
file. By using, distributing, or contributing to this project, you agree
to the terms and conditions of this license.
.. |Latest Documentation Status| image:: https://readthedocs.org/projects/pybind11/badge?version=latest
:target: http://pybind11.readthedocs.org/en/latest
.. |Stable Documentation Status| image:: https://img.shields.io/badge/docs-stable-blue.svg
:target: http://pybind11.readthedocs.org/en/stable
.. |Gitter chat| image:: https://img.shields.io/gitter/room/gitterHQ/gitter.svg
:target: https://gitter.im/pybind/Lobby
.. |CI| image:: https://github.com/pybind/pybind11/workflows/CI/badge.svg
:target: https://github.com/pybind/pybind11/actions
.. |Build status| image:: https://ci.appveyor.com/api/projects/status/riaj54pn4h08xy40?svg=true
:target: https://ci.appveyor.com/project/wjakob/pybind11
.. |PyPI package| image:: https://img.shields.io/pypi/v/pybind11.svg
:target: https://pypi.org/project/pybind11/
.. |Conda-forge| image:: https://img.shields.io/conda/vn/conda-forge/pybind11.svg
:target: https://github.com/conda-forge/pybind11-feedstock
.. |Repology| image:: https://repology.org/badge/latest-versions/python:pybind11.svg
:target: https://repology.org/project/python:pybind11/versions
.. |Python Versions| image:: https://img.shields.io/pypi/pyversions/pybind11.svg
:target: https://pypi.org/project/pybind11/
.. |GitHub Discussions| image:: https://img.shields.io/static/v1?label=Discussions&message=Ask&color=blue&logo=github
:target: https://github.com/pybind/pybind11/discussions
.. |SPEC 4 — Using and Creating Nightly Wheels| image:: https://img.shields.io/badge/SPEC-4-green?labelColor=%23004811&color=%235CA038
:target: https://scientific-python.org/specs/spec-0004/

View File

@@ -0,0 +1,722 @@
/*
pybind11/attr.h: Infrastructure for processing custom
type and function attributes
Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch>
All rights reserved. Use of this source code is governed by a
BSD-style license that can be found in the LICENSE file.
*/
#pragma once
#include "detail/common.h"
#include "cast.h"
#include "trampoline_self_life_support.h"
#include <functional>
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
/// \addtogroup annotations
/// @{
/// Annotation for methods
struct is_method {
handle class_;
explicit is_method(const handle &c) : class_(c) {}
};
/// Annotation for setters
struct is_setter {};
/// Annotation for operators
struct is_operator {};
/// Annotation for classes that cannot be subclassed
struct is_final {};
/// Annotation for parent scope
struct scope {
handle value;
explicit scope(const handle &s) : value(s) {}
};
/// Annotation for documentation
struct doc {
const char *value;
explicit doc(const char *value) : value(value) {}
};
/// Annotation for function names
struct name {
const char *value;
explicit name(const char *value) : value(value) {}
};
/// Annotation indicating that a function is an overload associated with a given "sibling"
struct sibling {
handle value;
explicit sibling(const handle &value) : value(value.ptr()) {}
};
/// Annotation indicating that a class derives from another given type
template <typename T>
struct base {
PYBIND11_DEPRECATED(
"base<T>() was deprecated in favor of specifying 'T' as a template argument to class_")
base() = default;
};
/// Keep patient alive while nurse lives
template <size_t Nurse, size_t Patient>
struct keep_alive {};
/// Annotation indicating that a class is involved in a multiple inheritance relationship
struct multiple_inheritance {};
/// Annotation which enables dynamic attributes, i.e. adds `__dict__` to a class
struct dynamic_attr {};
/// Annotation which enables the buffer protocol for a type
struct buffer_protocol {};
/// Annotation which enables releasing the GIL before calling the C++ destructor of wrapped
/// instances (pybind/pybind11#1446).
struct release_gil_before_calling_cpp_dtor {};
/// Annotation which requests that a special metaclass is created for a type
struct metaclass {
handle value;
PYBIND11_DEPRECATED("py::metaclass() is no longer required. It's turned on by default now.")
metaclass() = default;
/// Override pybind11's default metaclass
explicit metaclass(handle value) : value(value) {}
};
/// Specifies a custom callback with signature `void (PyHeapTypeObject*)` that
/// may be used to customize the Python type.
///
/// The callback is invoked immediately before `PyType_Ready`.
///
/// Note: This is an advanced interface, and uses of it may require changes to
/// work with later versions of pybind11. You may wish to consult the
/// implementation of `make_new_python_type` in `detail/classes.h` to understand
/// the context in which the callback will be run.
struct custom_type_setup {
using callback = std::function<void(PyHeapTypeObject *heap_type)>;
explicit custom_type_setup(callback value) : value(std::move(value)) {}
callback value;
};
/// Annotation that marks a class as local to the module:
struct module_local {
const bool value;
constexpr explicit module_local(bool v = true) : value(v) {}
};
/// Annotation to mark enums as an arithmetic type
struct arithmetic {};
/// Mark a function for addition at the beginning of the existing overload chain instead of the end
struct prepend {};
/** \rst
A call policy which places one or more guard variables (``Ts...``) around the function call.
For example, this definition:
.. code-block:: cpp
m.def("foo", foo, py::call_guard<T>());
is equivalent to the following pseudocode:
.. code-block:: cpp
m.def("foo", [](args...) {
T scope_guard;
return foo(args...); // forwarded arguments
});
\endrst */
template <typename... Ts>
struct call_guard;
template <>
struct call_guard<> {
using type = detail::void_type;
};
template <typename T>
struct call_guard<T> {
static_assert(std::is_default_constructible<T>::value,
"The guard type must be default constructible");
using type = T;
};
template <typename T, typename... Ts>
struct call_guard<T, Ts...> {
struct type {
T guard{}; // Compose multiple guard types with left-to-right default-constructor order
typename call_guard<Ts...>::type next{};
};
};
/// @} annotations
PYBIND11_NAMESPACE_BEGIN(detail)
/* Forward declarations */
enum op_id : int;
enum op_type : int;
struct undefined_t;
template <op_id id, op_type ot, typename L = undefined_t, typename R = undefined_t>
struct op_;
void keep_alive_impl(size_t Nurse, size_t Patient, function_call &call, handle ret);
/// Internal data structure which holds metadata about a keyword argument
struct argument_record {
const char *name; ///< Argument name
const char *descr; ///< Human-readable version of the argument value
handle value; ///< Associated Python object
bool convert : 1; ///< True if the argument is allowed to convert when loading
bool none : 1; ///< True if None is allowed when loading
argument_record(const char *name, const char *descr, handle value, bool convert, bool none)
: name(name), descr(descr), value(value), convert(convert), none(none) {}
};
/// Internal data structure which holds metadata about a bound function (signature, overloads,
/// etc.)
#define PYBIND11_DETAIL_FUNCTION_RECORD_ABI_ID "v1" // PLEASE UPDATE if the struct is changed.
struct function_record {
function_record()
: is_constructor(false), is_new_style_constructor(false), is_stateless(false),
is_operator(false), is_method(false), is_setter(false), has_args(false),
has_kwargs(false), prepend(false) {}
/// Function name
char *name = nullptr; /* why no C++ strings? They generate heavier code.. */
// User-specified documentation string
char *doc = nullptr;
/// Human-readable version of the function signature
char *signature = nullptr;
/// List of registered keyword arguments
std::vector<argument_record> args;
/// Pointer to lambda function which converts arguments and performs the actual call
handle (*impl)(function_call &) = nullptr;
/// Storage for the wrapped function pointer and captured data, if any
void *data[3] = {};
/// Pointer to custom destructor for 'data' (if needed)
void (*free_data)(function_record *ptr) = nullptr;
/// Return value policy associated with this function
return_value_policy policy = return_value_policy::automatic;
/// True if name == '__init__'
bool is_constructor : 1;
/// True if this is a new-style `__init__` defined in `detail/init.h`
bool is_new_style_constructor : 1;
/// True if this is a stateless function pointer
bool is_stateless : 1;
/// True if this is an operator (__add__), etc.
bool is_operator : 1;
/// True if this is a method
bool is_method : 1;
/// True if this is a setter
bool is_setter : 1;
/// True if the function has a '*args' argument
bool has_args : 1;
/// True if the function has a '**kwargs' argument
bool has_kwargs : 1;
/// True if this function is to be inserted at the beginning of the overload resolution chain
bool prepend : 1;
/// Number of arguments (including py::args and/or py::kwargs, if present)
std::uint16_t nargs;
/// Number of leading positional arguments, which are terminated by a py::args or py::kwargs
/// argument or by a py::kw_only annotation.
std::uint16_t nargs_pos = 0;
/// Number of leading arguments (counted in `nargs`) that are positional-only
std::uint16_t nargs_pos_only = 0;
/// Python method object
PyMethodDef *def = nullptr;
/// Python handle to the parent scope (a class or a module)
handle scope;
/// Python handle to the sibling function representing an overload chain
handle sibling;
/// Pointer to next overload
function_record *next = nullptr;
};
// The main purpose of this macro is to make it easy to pin-point the critically related code
// sections.
#define PYBIND11_ENSURE_PRECONDITION_FOR_FUNCTIONAL_H_PERFORMANCE_OPTIMIZATIONS(...) \
static_assert( \
__VA_ARGS__, \
"Violation of precondition for pybind11/functional.h performance optimizations!")
/// Special data structure which (temporarily) holds metadata about a bound class
struct type_record {
PYBIND11_NOINLINE type_record()
: multiple_inheritance(false), dynamic_attr(false), buffer_protocol(false),
module_local(false), is_final(false), release_gil_before_calling_cpp_dtor(false) {}
/// Handle to the parent scope
handle scope;
/// Name of the class
const char *name = nullptr;
// Pointer to RTTI type_info data structure
const std::type_info *type = nullptr;
/// How large is the underlying C++ type?
size_t type_size = 0;
/// What is the alignment of the underlying C++ type?
size_t type_align = 0;
/// How large is the type's holder?
size_t holder_size = 0;
/// The global operator new can be overridden with a class-specific variant
void *(*operator_new)(size_t) = nullptr;
/// Function pointer to class_<..>::init_instance
void (*init_instance)(instance *, const void *) = nullptr;
/// Function pointer to class_<..>::dealloc
void (*dealloc)(detail::value_and_holder &) = nullptr;
/// Function pointer for casting alias class (aka trampoline) pointer to
/// trampoline_self_life_support pointer. Sidesteps cross-DSO RTTI issues
/// on platforms like macOS (see PR #5728 for details).
get_trampoline_self_life_support_fn get_trampoline_self_life_support
= [](void *) -> trampoline_self_life_support * { return nullptr; };
/// List of base classes of the newly created type
list bases;
/// Optional docstring
const char *doc = nullptr;
/// Custom metaclass (optional)
handle metaclass;
/// Custom type setup.
custom_type_setup::callback custom_type_setup_callback;
/// Multiple inheritance marker
bool multiple_inheritance : 1;
/// Does the class manage a __dict__?
bool dynamic_attr : 1;
/// Does the class implement the buffer protocol?
bool buffer_protocol : 1;
/// Is the class definition local to the module shared object?
bool module_local : 1;
/// Is the class inheritable from python classes?
bool is_final : 1;
/// Solves pybind/pybind11#1446
bool release_gil_before_calling_cpp_dtor : 1;
holder_enum_t holder_enum_v = holder_enum_t::undefined;
PYBIND11_NOINLINE void add_base(const std::type_info &base, void *(*caster)(void *) ) {
auto *base_info = detail::get_type_info(base, false);
if (!base_info) {
std::string tname(base.name());
detail::clean_type_id(tname);
pybind11_fail("generic_type: type \"" + std::string(name)
+ "\" referenced unknown base type \"" + tname + "\"");
}
// SMART_HOLDER_BAKEIN_FOLLOW_ON: Refine holder compatibility checks.
bool this_has_unique_ptr_holder = (holder_enum_v == holder_enum_t::std_unique_ptr);
bool base_has_unique_ptr_holder
= (base_info->holder_enum_v == holder_enum_t::std_unique_ptr);
if (this_has_unique_ptr_holder != base_has_unique_ptr_holder) {
std::string tname(base.name());
detail::clean_type_id(tname);
pybind11_fail("generic_type: type \"" + std::string(name) + "\" "
+ (this_has_unique_ptr_holder ? "does not have" : "has")
+ " a non-default holder type while its base \"" + tname + "\" "
+ (base_has_unique_ptr_holder ? "does not" : "does"));
}
bases.append((PyObject *) base_info->type);
#ifdef PYBIND11_BACKWARD_COMPATIBILITY_TP_DICTOFFSET
dynamic_attr |= base_info->type->tp_dictoffset != 0;
#else
dynamic_attr |= (base_info->type->tp_flags & Py_TPFLAGS_MANAGED_DICT) != 0;
#endif
if (caster) {
base_info->implicit_casts.emplace_back(type, caster);
}
}
};
inline function_call::function_call(const function_record &f, handle p) : func(f), parent(p) {
args.reserve(f.nargs);
args_convert.reserve(f.nargs);
}
/// Tag for a new-style `__init__` defined in `detail/init.h`
struct is_new_style_constructor {};
/**
* Partial template specializations to process custom attributes provided to
* cpp_function_ and class_. These are either used to initialize the respective
* fields in the type_record and function_record data structures or executed at
* runtime to deal with custom call policies (e.g. keep_alive).
*/
template <typename T, typename SFINAE = void>
struct process_attribute;
template <typename T>
struct process_attribute_default {
/// Default implementation: do nothing
static void init(const T &, function_record *) {}
static void init(const T &, type_record *) {}
static void precall(function_call &) {}
static void postcall(function_call &, handle) {}
};
/// Process an attribute specifying the function's name
template <>
struct process_attribute<name> : process_attribute_default<name> {
static void init(const name &n, function_record *r) { r->name = const_cast<char *>(n.value); }
};
/// Process an attribute specifying the function's docstring
template <>
struct process_attribute<doc> : process_attribute_default<doc> {
static void init(const doc &n, function_record *r) { r->doc = const_cast<char *>(n.value); }
};
/// Process an attribute specifying the function's docstring (provided as a C-style string)
template <>
struct process_attribute<const char *> : process_attribute_default<const char *> {
static void init(const char *d, function_record *r) { r->doc = const_cast<char *>(d); }
static void init(const char *d, type_record *r) { r->doc = d; }
};
template <>
struct process_attribute<char *> : process_attribute<const char *> {};
/// Process an attribute indicating the function's return value policy
template <>
struct process_attribute<return_value_policy> : process_attribute_default<return_value_policy> {
static void init(const return_value_policy &p, function_record *r) { r->policy = p; }
};
/// Process an attribute which indicates that this is an overloaded function associated with a
/// given sibling
template <>
struct process_attribute<sibling> : process_attribute_default<sibling> {
static void init(const sibling &s, function_record *r) { r->sibling = s.value; }
};
/// Process an attribute which indicates that this function is a method
template <>
struct process_attribute<is_method> : process_attribute_default<is_method> {
static void init(const is_method &s, function_record *r) {
r->is_method = true;
r->scope = s.class_;
}
};
/// Process an attribute which indicates that this function is a setter
template <>
struct process_attribute<is_setter> : process_attribute_default<is_setter> {
static void init(const is_setter &, function_record *r) { r->is_setter = true; }
};
/// Process an attribute which indicates the parent scope of a method
template <>
struct process_attribute<scope> : process_attribute_default<scope> {
static void init(const scope &s, function_record *r) { r->scope = s.value; }
};
/// Process an attribute which indicates that this function is an operator
template <>
struct process_attribute<is_operator> : process_attribute_default<is_operator> {
static void init(const is_operator &, function_record *r) { r->is_operator = true; }
};
template <>
struct process_attribute<is_new_style_constructor>
: process_attribute_default<is_new_style_constructor> {
static void init(const is_new_style_constructor &, function_record *r) {
r->is_new_style_constructor = true;
}
};
inline void check_kw_only_arg(const arg &a, function_record *r) {
if (r->args.size() > r->nargs_pos && (!a.name || a.name[0] == '\0')) {
pybind11_fail("arg(): cannot specify an unnamed argument after a kw_only() annotation or "
"args() argument");
}
}
inline void append_self_arg_if_needed(function_record *r) {
if (r->is_method && r->args.empty()) {
r->args.emplace_back("self", nullptr, handle(), /*convert=*/true, /*none=*/false);
}
}
/// Process a keyword argument attribute (*without* a default value)
template <>
struct process_attribute<arg> : process_attribute_default<arg> {
static void init(const arg &a, function_record *r) {
append_self_arg_if_needed(r);
r->args.emplace_back(a.name, nullptr, handle(), !a.flag_noconvert, a.flag_none);
check_kw_only_arg(a, r);
}
};
/// Process a keyword argument attribute (*with* a default value)
template <>
struct process_attribute<arg_v> : process_attribute_default<arg_v> {
static void init(const arg_v &a, function_record *r) {
if (r->is_method && r->args.empty()) {
r->args.emplace_back(
"self", /*descr=*/nullptr, /*parent=*/handle(), /*convert=*/true, /*none=*/false);
}
if (!a.value) {
#if defined(PYBIND11_DETAILED_ERROR_MESSAGES)
std::string descr("'");
if (a.name) {
descr += std::string(a.name) + ": ";
}
descr += a.type + "'";
if (r->is_method) {
if (r->name) {
descr += " in method '" + (std::string) str(r->scope) + "."
+ (std::string) r->name + "'";
} else {
descr += " in method of '" + (std::string) str(r->scope) + "'";
}
} else if (r->name) {
descr += " in function '" + (std::string) r->name + "'";
}
pybind11_fail("arg(): could not convert default argument " + descr
+ " into a Python object (type not registered yet?)");
#else
pybind11_fail("arg(): could not convert default argument "
"into a Python object (type not registered yet?). "
"#define PYBIND11_DETAILED_ERROR_MESSAGES or compile in debug mode for "
"more information.");
#endif
}
r->args.emplace_back(a.name, a.descr, a.value.inc_ref(), !a.flag_noconvert, a.flag_none);
check_kw_only_arg(a, r);
}
};
/// Process a keyword-only-arguments-follow pseudo argument
template <>
struct process_attribute<kw_only> : process_attribute_default<kw_only> {
static void init(const kw_only &, function_record *r) {
append_self_arg_if_needed(r);
if (r->has_args && r->nargs_pos != static_cast<std::uint16_t>(r->args.size())) {
pybind11_fail("Mismatched args() and kw_only(): they must occur at the same relative "
"argument location (or omit kw_only() entirely)");
}
r->nargs_pos = static_cast<std::uint16_t>(r->args.size());
}
};
/// Process a positional-only-argument maker
template <>
struct process_attribute<pos_only> : process_attribute_default<pos_only> {
static void init(const pos_only &, function_record *r) {
append_self_arg_if_needed(r);
r->nargs_pos_only = static_cast<std::uint16_t>(r->args.size());
if (r->nargs_pos_only > r->nargs_pos) {
pybind11_fail("pos_only(): cannot follow a py::args() argument");
}
// It also can't follow a kw_only, but a static_assert in pybind11.h checks that
}
};
/// Process a parent class attribute. Single inheritance only (class_ itself already guarantees
/// that)
template <typename T>
struct process_attribute<T, enable_if_t<is_pyobject<T>::value>>
: process_attribute_default<handle> {
static void init(const handle &h, type_record *r) { r->bases.append(h); }
};
/// Process a parent class attribute (deprecated, does not support multiple inheritance)
template <typename T>
struct process_attribute<base<T>> : process_attribute_default<base<T>> {
static void init(const base<T> &, type_record *r) { r->add_base(typeid(T), nullptr); }
};
/// Process a multiple inheritance attribute
template <>
struct process_attribute<multiple_inheritance> : process_attribute_default<multiple_inheritance> {
static void init(const multiple_inheritance &, type_record *r) {
r->multiple_inheritance = true;
}
};
template <>
struct process_attribute<dynamic_attr> : process_attribute_default<dynamic_attr> {
static void init(const dynamic_attr &, type_record *r) { r->dynamic_attr = true; }
};
template <>
struct process_attribute<custom_type_setup> {
static void init(const custom_type_setup &value, type_record *r) {
r->custom_type_setup_callback = value.value;
}
};
template <>
struct process_attribute<is_final> : process_attribute_default<is_final> {
static void init(const is_final &, type_record *r) { r->is_final = true; }
};
template <>
struct process_attribute<buffer_protocol> : process_attribute_default<buffer_protocol> {
static void init(const buffer_protocol &, type_record *r) { r->buffer_protocol = true; }
};
template <>
struct process_attribute<metaclass> : process_attribute_default<metaclass> {
static void init(const metaclass &m, type_record *r) { r->metaclass = m.value; }
};
template <>
struct process_attribute<module_local> : process_attribute_default<module_local> {
static void init(const module_local &l, type_record *r) { r->module_local = l.value; }
};
template <>
struct process_attribute<release_gil_before_calling_cpp_dtor>
: process_attribute_default<release_gil_before_calling_cpp_dtor> {
static void init(const release_gil_before_calling_cpp_dtor &, type_record *r) {
r->release_gil_before_calling_cpp_dtor = true;
}
};
/// Process a 'prepend' attribute, putting this at the beginning of the overload chain
template <>
struct process_attribute<prepend> : process_attribute_default<prepend> {
static void init(const prepend &, function_record *r) { r->prepend = true; }
};
/// Process an 'arithmetic' attribute for enums (does nothing here)
template <>
struct process_attribute<arithmetic> : process_attribute_default<arithmetic> {};
template <typename... Ts>
struct process_attribute<call_guard<Ts...>> : process_attribute_default<call_guard<Ts...>> {};
/**
* Process a keep_alive call policy -- invokes keep_alive_impl during the
* pre-call handler if both Nurse, Patient != 0 and use the post-call handler
* otherwise
*/
template <size_t Nurse, size_t Patient>
struct process_attribute<keep_alive<Nurse, Patient>>
: public process_attribute_default<keep_alive<Nurse, Patient>> {
template <size_t N = Nurse, size_t P = Patient, enable_if_t<N != 0 && P != 0, int> = 0>
static void precall(function_call &call) {
keep_alive_impl(Nurse, Patient, call, handle());
}
template <size_t N = Nurse, size_t P = Patient, enable_if_t<N != 0 && P != 0, int> = 0>
static void postcall(function_call &, handle) {}
template <size_t N = Nurse, size_t P = Patient, enable_if_t<N == 0 || P == 0, int> = 0>
static void precall(function_call &) {}
template <size_t N = Nurse, size_t P = Patient, enable_if_t<N == 0 || P == 0, int> = 0>
static void postcall(function_call &call, handle ret) {
keep_alive_impl(Nurse, Patient, call, ret);
}
};
/// Recursively iterate over variadic template arguments
template <typename... Args>
struct process_attributes {
static void init(const Args &...args, function_record *r) {
PYBIND11_WORKAROUND_INCORRECT_MSVC_C4100(r);
PYBIND11_WORKAROUND_INCORRECT_GCC_UNUSED_BUT_SET_PARAMETER(r);
using expander = int[];
(void) expander{
0, ((void) process_attribute<typename std::decay<Args>::type>::init(args, r), 0)...};
}
static void init(const Args &...args, type_record *r) {
PYBIND11_WORKAROUND_INCORRECT_MSVC_C4100(r);
PYBIND11_WORKAROUND_INCORRECT_GCC_UNUSED_BUT_SET_PARAMETER(r);
using expander = int[];
(void) expander{0,
(process_attribute<typename std::decay<Args>::type>::init(args, r), 0)...};
}
static void precall(function_call &call) {
PYBIND11_WORKAROUND_INCORRECT_MSVC_C4100(call);
using expander = int[];
(void) expander{0,
(process_attribute<typename std::decay<Args>::type>::precall(call), 0)...};
}
static void postcall(function_call &call, handle fn_ret) {
PYBIND11_WORKAROUND_INCORRECT_MSVC_C4100(call, fn_ret);
PYBIND11_WORKAROUND_INCORRECT_GCC_UNUSED_BUT_SET_PARAMETER(fn_ret);
using expander = int[];
(void) expander{
0, (process_attribute<typename std::decay<Args>::type>::postcall(call, fn_ret), 0)...};
}
};
template <typename T>
using is_call_guard = is_instantiation<call_guard, T>;
/// Extract the ``type`` from the first `call_guard` in `Extras...` (or `void_type` if none found)
template <typename... Extra>
using extract_guard_t = typename exactly_one_t<is_call_guard, call_guard<>, Extra...>::type;
/// Check the number of named arguments at compile time
template <typename... Extra,
size_t named = constexpr_sum(std::is_base_of<arg, Extra>::value...),
size_t self = constexpr_sum(std::is_same<is_method, Extra>::value...)>
constexpr bool expected_num_args(size_t nargs, bool has_args, bool has_kwargs) {
PYBIND11_WORKAROUND_INCORRECT_MSVC_C4100(nargs, has_args, has_kwargs);
return named == 0 || (self + named + size_t(has_args) + size_t(has_kwargs)) == nargs;
}
PYBIND11_NAMESPACE_END(detail)
PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)

View File

@@ -0,0 +1,208 @@
/*
pybind11/buffer_info.h: Python buffer object interface
Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch>
All rights reserved. Use of this source code is governed by a
BSD-style license that can be found in the LICENSE file.
*/
#pragma once
#include "detail/common.h"
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
PYBIND11_NAMESPACE_BEGIN(detail)
// Default, C-style strides
inline std::vector<ssize_t> c_strides(const std::vector<ssize_t> &shape, ssize_t itemsize) {
auto ndim = shape.size();
std::vector<ssize_t> strides(ndim, itemsize);
if (ndim > 0) {
for (size_t i = ndim - 1; i > 0; --i) {
strides[i - 1] = strides[i] * shape[i];
}
}
return strides;
}
// F-style strides; default when constructing an array_t with `ExtraFlags & f_style`
inline std::vector<ssize_t> f_strides(const std::vector<ssize_t> &shape, ssize_t itemsize) {
auto ndim = shape.size();
std::vector<ssize_t> strides(ndim, itemsize);
for (size_t i = 1; i < ndim; ++i) {
strides[i] = strides[i - 1] * shape[i - 1];
}
return strides;
}
template <typename T, typename SFINAE = void>
struct compare_buffer_info;
PYBIND11_NAMESPACE_END(detail)
/// Information record describing a Python buffer object
struct buffer_info {
void *ptr = nullptr; // Pointer to the underlying storage
ssize_t itemsize = 0; // Size of individual items in bytes
ssize_t size = 0; // Total number of entries
std::string format; // For homogeneous buffers, this should be set to
// format_descriptor<T>::format()
ssize_t ndim = 0; // Number of dimensions
std::vector<ssize_t> shape; // Shape of the tensor (1 entry per dimension)
std::vector<ssize_t> strides; // Number of bytes between adjacent entries
// (for each per dimension)
bool readonly = false; // flag to indicate if the underlying storage may be written to
buffer_info() = default;
buffer_info(void *ptr,
ssize_t itemsize,
const std::string &format,
ssize_t ndim,
detail::any_container<ssize_t> shape_in,
detail::any_container<ssize_t> strides_in,
bool readonly = false)
: ptr(ptr), itemsize(itemsize), size(1), format(format), ndim(ndim),
shape(std::move(shape_in)), strides(std::move(strides_in)), readonly(readonly) {
if (ndim != (ssize_t) shape.size() || ndim != (ssize_t) strides.size()) {
pybind11_fail("buffer_info: ndim doesn't match shape and/or strides length");
}
for (size_t i = 0; i < (size_t) ndim; ++i) {
size *= shape[i];
}
}
template <typename T>
buffer_info(T *ptr,
detail::any_container<ssize_t> shape_in,
detail::any_container<ssize_t> strides_in,
bool readonly = false)
: buffer_info(private_ctr_tag(),
ptr,
sizeof(T),
format_descriptor<T>::format(),
static_cast<ssize_t>(shape_in->size()),
std::move(shape_in),
std::move(strides_in),
readonly) {}
buffer_info(void *ptr,
ssize_t itemsize,
const std::string &format,
ssize_t size,
bool readonly = false)
: buffer_info(ptr, itemsize, format, 1, {size}, {itemsize}, readonly) {}
template <typename T>
buffer_info(T *ptr, ssize_t size, bool readonly = false)
: buffer_info(ptr, sizeof(T), format_descriptor<T>::format(), size, readonly) {}
template <typename T>
buffer_info(const T *ptr, ssize_t size, bool readonly = true)
: buffer_info(
const_cast<T *>(ptr), sizeof(T), format_descriptor<T>::format(), size, readonly) {}
explicit buffer_info(Py_buffer *view, bool ownview = true)
: buffer_info(
view->buf,
view->itemsize,
view->format,
view->ndim,
{view->shape, view->shape + view->ndim},
/* Though buffer::request() requests PyBUF_STRIDES, ctypes objects
* ignore this flag and return a view with NULL strides.
* When strides are NULL, build them manually. */
view->strides
? std::vector<ssize_t>(view->strides, view->strides + view->ndim)
: detail::c_strides({view->shape, view->shape + view->ndim}, view->itemsize),
(view->readonly != 0)) {
// NOLINTNEXTLINE(cppcoreguidelines-prefer-member-initializer)
this->m_view = view;
// NOLINTNEXTLINE(cppcoreguidelines-prefer-member-initializer)
this->ownview = ownview;
}
buffer_info(const buffer_info &) = delete;
buffer_info &operator=(const buffer_info &) = delete;
buffer_info(buffer_info &&other) noexcept { (*this) = std::move(other); }
buffer_info &operator=(buffer_info &&rhs) noexcept {
ptr = rhs.ptr;
itemsize = rhs.itemsize;
size = rhs.size;
format = std::move(rhs.format);
ndim = rhs.ndim;
shape = std::move(rhs.shape);
strides = std::move(rhs.strides);
std::swap(m_view, rhs.m_view);
std::swap(ownview, rhs.ownview);
readonly = rhs.readonly;
return *this;
}
~buffer_info() {
if (m_view && ownview) {
PyBuffer_Release(m_view);
delete m_view;
}
}
Py_buffer *view() const { return m_view; }
Py_buffer *&view() { return m_view; }
/* True if the buffer item type is equivalent to `T`. */
// To define "equivalent" by example:
// `buffer_info::item_type_is_equivalent_to<int>(b)` and
// `buffer_info::item_type_is_equivalent_to<long>(b)` may both be true
// on some platforms, but `int` and `unsigned` will never be equivalent.
// For the ground truth, please inspect `detail::compare_buffer_info<>`.
template <typename T>
bool item_type_is_equivalent_to() const {
return detail::compare_buffer_info<T>::compare(*this);
}
private:
struct private_ctr_tag {};
buffer_info(private_ctr_tag,
void *ptr,
ssize_t itemsize,
const std::string &format,
ssize_t ndim,
detail::any_container<ssize_t> &&shape_in,
detail::any_container<ssize_t> &&strides_in,
bool readonly)
: buffer_info(
ptr, itemsize, format, ndim, std::move(shape_in), std::move(strides_in), readonly) {}
Py_buffer *m_view = nullptr;
bool ownview = false;
};
PYBIND11_NAMESPACE_BEGIN(detail)
template <typename T, typename SFINAE>
struct compare_buffer_info {
static bool compare(const buffer_info &b) {
// NOLINTNEXTLINE(bugprone-sizeof-expression) Needed for `PyObject *`
return b.format == format_descriptor<T>::format() && b.itemsize == (ssize_t) sizeof(T);
}
};
template <typename T>
struct compare_buffer_info<T, detail::enable_if_t<std::is_integral<T>::value>> {
static bool compare(const buffer_info &b) {
return (size_t) b.itemsize == sizeof(T)
&& (b.format == format_descriptor<T>::value
|| ((sizeof(T) == sizeof(long))
&& b.format == (std::is_unsigned<T>::value ? "L" : "l"))
|| ((sizeof(T) == sizeof(size_t))
&& b.format == (std::is_unsigned<T>::value ? "N" : "n")));
}
};
PYBIND11_NAMESPACE_END(detail)
PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,228 @@
/*
pybind11/chrono.h: Transparent conversion between std::chrono and python's datetime
Copyright (c) 2016 Trent Houliston <trent@houliston.me> and
Wenzel Jakob <wenzel.jakob@epfl.ch>
All rights reserved. Use of this source code is governed by a
BSD-style license that can be found in the LICENSE file.
*/
#pragma once
#include "pybind11.h"
#include <chrono>
#include <cmath>
#include <ctime>
#include <datetime.h>
#include <mutex>
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
PYBIND11_NAMESPACE_BEGIN(detail)
template <typename type>
class duration_caster {
public:
using rep = typename type::rep;
using period = typename type::period;
// signed 25 bits required by the standard.
using days = std::chrono::duration<int_least32_t, std::ratio<86400>>;
bool load(handle src, bool) {
using namespace std::chrono;
// Lazy initialise the PyDateTime import
if (!PyDateTimeAPI) {
PyDateTime_IMPORT;
}
if (!src) {
return false;
}
// If invoked with datetime.delta object
if (PyDelta_Check(src.ptr())) {
value = type(duration_cast<duration<rep, period>>(
days(PyDateTime_DELTA_GET_DAYS(src.ptr()))
+ seconds(PyDateTime_DELTA_GET_SECONDS(src.ptr()))
+ microseconds(PyDateTime_DELTA_GET_MICROSECONDS(src.ptr()))));
return true;
}
// If invoked with a float we assume it is seconds and convert
if (PyFloat_Check(src.ptr())) {
value = type(duration_cast<duration<rep, period>>(
duration<double>(PyFloat_AsDouble(src.ptr()))));
return true;
}
return false;
}
// If this is a duration just return it back
static const std::chrono::duration<rep, period> &
get_duration(const std::chrono::duration<rep, period> &src) {
return src;
}
static const std::chrono::duration<rep, period> &
get_duration(const std::chrono::duration<rep, period> &&)
= delete;
// If this is a time_point get the time_since_epoch
template <typename Clock>
static std::chrono::duration<rep, period>
get_duration(const std::chrono::time_point<Clock, std::chrono::duration<rep, period>> &src) {
return src.time_since_epoch();
}
static handle cast(const type &src, return_value_policy /* policy */, handle /* parent */) {
using namespace std::chrono;
// Use overloaded function to get our duration from our source
// Works out if it is a duration or time_point and get the duration
auto d = get_duration(src);
// Lazy initialise the PyDateTime import
if (!PyDateTimeAPI) {
PyDateTime_IMPORT;
}
// Declare these special duration types so the conversions happen with the correct
// primitive types (int)
using dd_t = duration<int, std::ratio<86400>>;
using ss_t = duration<int, std::ratio<1>>;
using us_t = duration<int, std::micro>;
auto dd = duration_cast<dd_t>(d);
auto subd = d - dd;
auto ss = duration_cast<ss_t>(subd);
auto us = duration_cast<us_t>(subd - ss);
return PyDelta_FromDSU(dd.count(), ss.count(), us.count());
}
PYBIND11_TYPE_CASTER(type, const_name("datetime.timedelta"));
};
inline std::tm *localtime_thread_safe(const std::time_t *time, std::tm *buf) {
#if (defined(__STDC_LIB_EXT1__) && defined(__STDC_WANT_LIB_EXT1__)) || defined(_MSC_VER)
if (localtime_s(buf, time))
return nullptr;
return buf;
#else
static std::mutex mtx;
std::lock_guard<std::mutex> lock(mtx);
std::tm *tm_ptr = std::localtime(time);
if (tm_ptr != nullptr) {
*buf = *tm_ptr;
}
return tm_ptr;
#endif
}
// This is for casting times on the system clock into datetime.datetime instances
template <typename Duration>
class type_caster<std::chrono::time_point<std::chrono::system_clock, Duration>> {
public:
using type = std::chrono::time_point<std::chrono::system_clock, Duration>;
bool load(handle src, bool) {
using namespace std::chrono;
// Lazy initialise the PyDateTime import
if (!PyDateTimeAPI) {
PyDateTime_IMPORT;
}
if (!src) {
return false;
}
std::tm cal;
microseconds msecs;
if (PyDateTime_Check(src.ptr())) {
cal.tm_sec = PyDateTime_DATE_GET_SECOND(src.ptr());
cal.tm_min = PyDateTime_DATE_GET_MINUTE(src.ptr());
cal.tm_hour = PyDateTime_DATE_GET_HOUR(src.ptr());
cal.tm_mday = PyDateTime_GET_DAY(src.ptr());
cal.tm_mon = PyDateTime_GET_MONTH(src.ptr()) - 1;
cal.tm_year = PyDateTime_GET_YEAR(src.ptr()) - 1900;
cal.tm_isdst = -1;
msecs = microseconds(PyDateTime_DATE_GET_MICROSECOND(src.ptr()));
} else if (PyDate_Check(src.ptr())) {
cal.tm_sec = 0;
cal.tm_min = 0;
cal.tm_hour = 0;
cal.tm_mday = PyDateTime_GET_DAY(src.ptr());
cal.tm_mon = PyDateTime_GET_MONTH(src.ptr()) - 1;
cal.tm_year = PyDateTime_GET_YEAR(src.ptr()) - 1900;
cal.tm_isdst = -1;
msecs = microseconds(0);
} else if (PyTime_Check(src.ptr())) {
cal.tm_sec = PyDateTime_TIME_GET_SECOND(src.ptr());
cal.tm_min = PyDateTime_TIME_GET_MINUTE(src.ptr());
cal.tm_hour = PyDateTime_TIME_GET_HOUR(src.ptr());
cal.tm_mday = 1; // This date (day, month, year) = (1, 0, 70)
cal.tm_mon = 0; // represents 1-Jan-1970, which is the first
cal.tm_year = 70; // earliest available date for Python's datetime
cal.tm_isdst = -1;
msecs = microseconds(PyDateTime_TIME_GET_MICROSECOND(src.ptr()));
} else {
return false;
}
value = time_point_cast<Duration>(system_clock::from_time_t(std::mktime(&cal)) + msecs);
return true;
}
static handle cast(const std::chrono::time_point<std::chrono::system_clock, Duration> &src,
return_value_policy /* policy */,
handle /* parent */) {
using namespace std::chrono;
// Lazy initialise the PyDateTime import
if (!PyDateTimeAPI) {
PyDateTime_IMPORT;
}
// Get out microseconds, and make sure they are positive, to avoid bug in eastern
// hemisphere time zones (cfr. https://github.com/pybind/pybind11/issues/2417)
using us_t = duration<int, std::micro>;
auto us = duration_cast<us_t>(src.time_since_epoch() % seconds(1));
if (us.count() < 0) {
us += duration_cast<us_t>(seconds(1));
}
// Subtract microseconds BEFORE `system_clock::to_time_t`, because:
// > If std::time_t has lower precision, it is implementation-defined whether the value is
// rounded or truncated. (https://en.cppreference.com/w/cpp/chrono/system_clock/to_time_t)
std::time_t tt
= system_clock::to_time_t(time_point_cast<system_clock::duration>(src - us));
std::tm localtime;
std::tm *localtime_ptr = localtime_thread_safe(&tt, &localtime);
if (!localtime_ptr) {
throw cast_error("Unable to represent system_clock in local time");
}
return PyDateTime_FromDateAndTime(localtime.tm_year + 1900,
localtime.tm_mon + 1,
localtime.tm_mday,
localtime.tm_hour,
localtime.tm_min,
localtime.tm_sec,
us.count());
}
PYBIND11_TYPE_CASTER(type, const_name("datetime.datetime"));
};
// Other clocks that are not the system clock are not measured as datetime.datetime objects
// since they are not measured on calendar time. So instead we just make them timedeltas
// Or if they have passed us a time as a float we convert that
template <typename Clock, typename Duration>
class type_caster<std::chrono::time_point<Clock, Duration>>
: public duration_caster<std::chrono::time_point<Clock, Duration>> {};
template <typename Rep, typename Period>
class type_caster<std::chrono::duration<Rep, Period>>
: public duration_caster<std::chrono::duration<Rep, Period>> {};
PYBIND11_NAMESPACE_END(detail)
PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)

View File

@@ -0,0 +1,2 @@
#include "detail/common.h"
#warning "Including 'common.h' is deprecated. It will be removed in v3.0. Use 'pybind11.h'."

View File

@@ -0,0 +1,74 @@
/*
pybind11/complex.h: Complex number support
Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch>
All rights reserved. Use of this source code is governed by a
BSD-style license that can be found in the LICENSE file.
*/
#pragma once
#include "pybind11.h"
#include <complex>
/// glibc defines I as a macro which breaks things, e.g., boost template names
#ifdef I
# undef I
#endif
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
template <typename T>
struct format_descriptor<std::complex<T>, detail::enable_if_t<std::is_floating_point<T>::value>> {
static constexpr const char c = format_descriptor<T>::c;
static constexpr const char value[3] = {'Z', c, '\0'};
static std::string format() { return std::string(value); }
};
#ifndef PYBIND11_CPP17
template <typename T>
constexpr const char
format_descriptor<std::complex<T>,
detail::enable_if_t<std::is_floating_point<T>::value>>::value[3];
#endif
PYBIND11_NAMESPACE_BEGIN(detail)
template <typename T>
struct is_fmt_numeric<std::complex<T>, detail::enable_if_t<std::is_floating_point<T>::value>> {
static constexpr bool value = true;
static constexpr int index = is_fmt_numeric<T>::index + 3;
};
template <typename T>
class type_caster<std::complex<T>> {
public:
bool load(handle src, bool convert) {
if (!src) {
return false;
}
if (!convert && !PyComplex_Check(src.ptr())) {
return false;
}
Py_complex result = PyComplex_AsCComplex(src.ptr());
if (result.real == -1.0 && PyErr_Occurred()) {
PyErr_Clear();
return false;
}
value = std::complex<T>((T) result.real, (T) result.imag);
return true;
}
static handle
cast(const std::complex<T> &src, return_value_policy /* policy */, handle /* parent */) {
return PyComplex_FromDoubles((double) src.real(), (double) src.imag());
}
PYBIND11_TYPE_CASTER(std::complex<T>, const_name("complex"));
};
PYBIND11_NAMESPACE_END(detail)
PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)

View File

@@ -0,0 +1,15 @@
NOTE
----
The C++ code here
** only depends on <Python.h> **
and nothing else.
DO NOT ADD CODE WITH OTHER EXTERNAL DEPENDENCIES TO THIS DIRECTORY.
Read on:
pybind11_conduit_v1.h — Type-safe interoperability between different
independent Python/C++ bindings systems.

View File

@@ -0,0 +1,116 @@
// Copyright (c) 2024 The pybind Community.
/* The pybind11_conduit_v1 feature enables type-safe interoperability between
* different independent Python/C++ bindings systems,
* including pybind11 versions with different PYBIND11_INTERNALS_VERSION's.
* NOTE: The conduit feature
only covers from-Python-to-C++ conversions, it
does not cover from-C++-to-Python conversions.
(For the latter, a different feature would have to be added.)
The naming of the feature is a bit misleading:
* The feature is in no way tied to pybind11 internals.
* It just happens to originate from pybind11 and currently still lives there.
* The only external dependency is <Python.h>.
The implementation is a VERY light-weight dependency. It is designed to be
compatible with any ISO C++11 (or higher) compiler, and does NOT require
C++ Exception Handling to be enabled.
Please see https://github.com/pybind/pybind11/pull/5296 for more background.
The implementation involves a
def _pybind11_conduit_v1_(
self,
pybind11_platform_abi_id: bytes,
cpp_type_info_capsule: capsule,
pointer_kind: bytes) -> capsule
method that is meant to be added to Python objects wrapping C++ objects
(e.g. pybind11::class_-wrapped types).
The design of the _pybind11_conduit_v1_ feature provides two layers of
protection against C++ ABI mismatches:
* The first and most important layer is that the pybind11_platform_abi_id's
must match between extensions. — This will never be perfect, but is the same
pragmatic approach used in pybind11 since 2017
(https://github.com/pybind/pybind11/commit/96997a4b9d4ec3d389a570604394af5d5eee2557,
PYBIND11_INTERNALS_ID).
* The second layer is that the typeid(std::type_info).name()'s must match
between extensions.
The implementation below (which is shorter than this comment!), serves as a
battle-tested specification. The main API is this one function:
auto *cpp_pointer = pybind11_conduit_v1::get_type_pointer_ephemeral<YourType>(py_obj);
It is meant to be a minimalistic reference implementation, intentionally
without comprehensive error reporting. It is expected that major bindings
systems will roll their own, compatible implementations, potentially with
system-specific error reporting. The essential specifications all bindings
systems need to agree on are merely:
* PYBIND11_PLATFORM_ABI_ID (const char* literal).
* The cpp_type_info capsule (see below: a void *ptr and a const char *name).
* The cpp_conduit capsule (see below: a void *ptr and a const char *name).
* "raw_pointer_ephemeral" means: the lifetime of the pointer is the lifetime
of the py_obj.
*/
// THIS MUST STAY AT THE TOP!
#include "pybind11_platform_abi_id.h"
#include <Python.h>
#include <typeinfo>
namespace pybind11_conduit_v1 {
inline void *get_raw_pointer_ephemeral(PyObject *py_obj, const std::type_info *cpp_type_info) {
PyObject *cpp_type_info_capsule
= PyCapsule_New(const_cast<void *>(static_cast<const void *>(cpp_type_info)),
typeid(std::type_info).name(),
nullptr);
if (cpp_type_info_capsule == nullptr) {
return nullptr;
}
PyObject *cpp_conduit = PyObject_CallMethod(py_obj,
"_pybind11_conduit_v1_",
"yOy",
PYBIND11_PLATFORM_ABI_ID,
cpp_type_info_capsule,
"raw_pointer_ephemeral");
Py_DECREF(cpp_type_info_capsule);
if (cpp_conduit == nullptr) {
return nullptr;
}
void *raw_ptr = PyCapsule_GetPointer(cpp_conduit, cpp_type_info->name());
Py_DECREF(cpp_conduit);
if (PyErr_Occurred()) {
return nullptr;
}
return raw_ptr;
}
template <typename T>
T *get_type_pointer_ephemeral(PyObject *py_obj) {
void *raw_ptr = get_raw_pointer_ephemeral(py_obj, &typeid(T));
if (raw_ptr == nullptr) {
return nullptr;
}
return static_cast<T *>(raw_ptr);
}
} // namespace pybind11_conduit_v1

View File

@@ -0,0 +1,87 @@
#pragma once
// Copyright (c) 2024 The pybind Community.
// To maximize reusability:
// DO NOT ADD CODE THAT REQUIRES C++ EXCEPTION HANDLING.
#include "wrap_include_python_h.h"
// Implementation details. DO NOT USE ELSEWHERE. (Unfortunately we cannot #undef them.)
// This is duplicated here to maximize portability.
#define PYBIND11_PLATFORM_ABI_ID_STRINGIFY(x) #x
#define PYBIND11_PLATFORM_ABI_ID_TOSTRING(x) PYBIND11_PLATFORM_ABI_ID_STRINGIFY(x)
#ifdef PYBIND11_COMPILER_TYPE
// // To maintain backward compatibility (see PR #5439).
# define PYBIND11_COMPILER_TYPE_LEADING_UNDERSCORE ""
#else
# define PYBIND11_COMPILER_TYPE_LEADING_UNDERSCORE "_"
# if defined(__MINGW32__)
# define PYBIND11_COMPILER_TYPE "mingw"
# elif defined(__CYGWIN__)
# define PYBIND11_COMPILER_TYPE "gcc_cygwin"
# elif defined(_MSC_VER)
# define PYBIND11_COMPILER_TYPE "msvc"
# elif defined(__clang__) || defined(__GNUC__)
# define PYBIND11_COMPILER_TYPE "system" // Assumed compatible with system compiler.
# else
# error "Unknown PYBIND11_COMPILER_TYPE: PLEASE REVISE THIS CODE."
# endif
#endif
// PR #5439 made this macro obsolete. However, there are many manipulations of this macro in the
// wild. Therefore, to maintain backward compatibility, it is kept around.
#ifndef PYBIND11_STDLIB
# define PYBIND11_STDLIB ""
#endif
#ifndef PYBIND11_BUILD_ABI
# if defined(_MSC_VER) // See PR #4953.
# if defined(_MT) && defined(_DLL) // Corresponding to CL command line options /MD or /MDd.
# if (_MSC_VER) / 100 == 19
# define PYBIND11_BUILD_ABI "_md_mscver19"
# else
# error "Unknown major version for MSC_VER: PLEASE REVISE THIS CODE."
# endif
# elif defined(_MT) // Corresponding to CL command line options /MT or /MTd.
# define PYBIND11_BUILD_ABI "_mt_mscver" PYBIND11_PLATFORM_ABI_ID_TOSTRING(_MSC_VER)
# else
# if (_MSC_VER) / 100 == 19
# define PYBIND11_BUILD_ABI "_none_mscver19"
# else
# error "Unknown major version for MSC_VER: PLEASE REVISE THIS CODE."
# endif
# endif
# elif defined(_LIBCPP_ABI_VERSION) // https://libcxx.llvm.org/DesignDocs/ABIVersioning.html
# define PYBIND11_BUILD_ABI \
"_libcpp_abi" PYBIND11_PLATFORM_ABI_ID_TOSTRING(_LIBCPP_ABI_VERSION)
# elif defined(_GLIBCXX_USE_CXX11_ABI) // See PR #5439.
# if defined(__NVCOMPILER)
// // Assume that NVHPC is in the 1xxx ABI family.
// // THIS ASSUMPTION IS NOT FUTURE PROOF but apparently the best we can do.
// // Please let us know if there is a way to validate the assumption here.
# elif !defined(__GXX_ABI_VERSION)
# error \
"Unknown platform or compiler (_GLIBCXX_USE_CXX11_ABI): PLEASE REVISE THIS CODE."
# endif
# if defined(__GXX_ABI_VERSION) && __GXX_ABI_VERSION < 1002 || __GXX_ABI_VERSION >= 2000
# error "Unknown platform or compiler (__GXX_ABI_VERSION): PLEASE REVISE THIS CODE."
# endif
# define PYBIND11_BUILD_ABI \
"_libstdcpp_gxx_abi_1xxx_use_cxx11_abi_" PYBIND11_PLATFORM_ABI_ID_TOSTRING( \
_GLIBCXX_USE_CXX11_ABI)
# else
# error "Unknown platform or compiler: PLEASE REVISE THIS CODE."
# endif
#endif
// On MSVC, debug and release builds are not ABI-compatible!
#if defined(_MSC_VER) && defined(_DEBUG)
# define PYBIND11_BUILD_TYPE "_debug"
#else
# define PYBIND11_BUILD_TYPE ""
#endif
#define PYBIND11_PLATFORM_ABI_ID \
PYBIND11_COMPILER_TYPE PYBIND11_STDLIB PYBIND11_BUILD_ABI PYBIND11_BUILD_TYPE

View File

@@ -0,0 +1,72 @@
#pragma once
// Copyright (c) 2024 The pybind Community.
// STRONG REQUIREMENT:
// This header is a wrapper around `#include <Python.h>`, therefore it
// MUST BE INCLUDED BEFORE ANY STANDARD HEADERS are included.
// See also:
// https://docs.python.org/3/c-api/intro.html#include-files
// Quoting from there:
// Note: Since Python may define some pre-processor definitions which affect
// the standard headers on some systems, you must include Python.h before
// any standard headers are included.
// To maximize reusability:
// DO NOT ADD CODE THAT REQUIRES C++ EXCEPTION HANDLING.
// Disable linking to pythonX_d.lib on Windows in debug mode.
#if defined(_MSC_VER) && defined(_DEBUG) && !defined(Py_DEBUG)
// Workaround for a VS 2022 issue.
// See https://github.com/pybind/pybind11/pull/3497 for full context.
// NOTE: This workaround knowingly violates the Python.h include order
// requirement (see above).
# include <yvals.h>
# if _MSVC_STL_VERSION >= 143
# include <crtdefs.h>
# endif
# define PYBIND11_DEBUG_MARKER
# undef _DEBUG
#endif
// Don't let Python.h #define (v)snprintf as macro because they are implemented
// properly in Visual Studio since 2015.
#if defined(_MSC_VER)
# define HAVE_SNPRINTF 1
#endif
#if defined(_MSC_VER)
# pragma warning(push)
# pragma warning(disable : 4505)
// C4505: 'PySlice_GetIndicesEx': unreferenced local function has been removed
#endif
#include <Python.h>
#include <frameobject.h>
#include <pythread.h>
#if defined(_MSC_VER)
# pragma warning(pop)
#endif
#if defined(PYBIND11_DEBUG_MARKER)
# define _DEBUG 1
# undef PYBIND11_DEBUG_MARKER
#endif
// Python #defines overrides on all sorts of core functions, which
// tends to wreak havok in C++ codebases that expect these to work
// like regular functions (potentially with several overloads).
#if defined(isalnum)
# undef isalnum
# undef isalpha
# undef islower
# undef isspace
# undef isupper
# undef tolower
# undef toupper
#endif
#if defined(copysign)
# undef copysign
#endif

View File

@@ -0,0 +1,56 @@
// Copyright (c) 2016-2025 The Pybind Development Team.
// All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
#pragma once
#include "pytypes.h"
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
/// This does not do anything if there's a GIL. On free-threaded Python,
/// it locks an object. This uses the CPython API, which has limits
class scoped_critical_section {
public:
#ifdef Py_GIL_DISABLED
explicit scoped_critical_section(handle obj1, handle obj2 = handle{}) {
if (obj1) {
if (obj2) {
PyCriticalSection2_Begin(&section2, obj1.ptr(), obj2.ptr());
rank = 2;
} else {
PyCriticalSection_Begin(&section, obj1.ptr());
rank = 1;
}
} else if (obj2) {
PyCriticalSection_Begin(&section, obj2.ptr());
rank = 1;
}
}
~scoped_critical_section() {
if (rank == 1) {
PyCriticalSection_End(&section);
} else if (rank == 2) {
PyCriticalSection2_End(&section2);
}
}
#else
explicit scoped_critical_section(handle, handle = handle{}) {};
~scoped_critical_section() = default;
#endif
scoped_critical_section(const scoped_critical_section &) = delete;
scoped_critical_section &operator=(const scoped_critical_section &) = delete;
private:
#ifdef Py_GIL_DISABLED
int rank{0};
union {
PyCriticalSection section;
PyCriticalSection2 section2;
};
#endif
};
PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)

View File

@@ -0,0 +1,823 @@
/*
pybind11/detail/class.h: Python C API implementation details for py::class_
Copyright (c) 2017 Wenzel Jakob <wenzel.jakob@epfl.ch>
All rights reserved. Use of this source code is governed by a
BSD-style license that can be found in the LICENSE file.
*/
#pragma once
#include <pybind11/attr.h>
#include <pybind11/options.h>
#include "exception_translation.h"
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
PYBIND11_NAMESPACE_BEGIN(detail)
#if !defined(PYPY_VERSION)
# define PYBIND11_BUILTIN_QUALNAME
# define PYBIND11_SET_OLDPY_QUALNAME(obj, nameobj)
#else
// In PyPy, we still set __qualname__ so that we can produce reliable function type
// signatures; in CPython this macro expands to nothing:
# define PYBIND11_SET_OLDPY_QUALNAME(obj, nameobj) \
setattr((PyObject *) obj, "__qualname__", nameobj)
#endif
inline std::string get_fully_qualified_tp_name(PyTypeObject *type) {
#if !defined(PYPY_VERSION)
return type->tp_name;
#else
auto module_name = handle((PyObject *) type).attr("__module__").cast<std::string>();
if (module_name == PYBIND11_BUILTINS_MODULE)
return type->tp_name;
else
return std::move(module_name) + "." + type->tp_name;
#endif
}
inline PyTypeObject *type_incref(PyTypeObject *type) {
Py_INCREF(type);
return type;
}
#if !defined(PYPY_VERSION)
/// `pybind11_static_property.__get__()`: Always pass the class instead of the instance.
extern "C" inline PyObject *pybind11_static_get(PyObject *self, PyObject * /*ob*/, PyObject *cls) {
return PyProperty_Type.tp_descr_get(self, cls, cls);
}
/// `pybind11_static_property.__set__()`: Just like the above `__get__()`.
extern "C" inline int pybind11_static_set(PyObject *self, PyObject *obj, PyObject *value) {
PyObject *cls = PyType_Check(obj) ? obj : (PyObject *) Py_TYPE(obj);
return PyProperty_Type.tp_descr_set(self, cls, value);
}
// Forward declaration to use in `make_static_property_type()`
inline void enable_dynamic_attributes(PyHeapTypeObject *heap_type);
/** A `static_property` is the same as a `property` but the `__get__()` and `__set__()`
methods are modified to always use the object type instead of a concrete instance.
Return value: New reference. */
inline PyTypeObject *make_static_property_type() {
constexpr auto *name = "pybind11_static_property";
auto name_obj = reinterpret_steal<object>(PYBIND11_FROM_STRING(name));
/* Danger zone: from now (and until PyType_Ready), make sure to
issue no Python C API calls which could potentially invoke the
garbage collector (the GC will call type_traverse(), which will in
turn find the newly constructed type in an invalid state) */
auto *heap_type = (PyHeapTypeObject *) PyType_Type.tp_alloc(&PyType_Type, 0);
if (!heap_type) {
pybind11_fail("make_static_property_type(): error allocating type!");
}
heap_type->ht_name = name_obj.inc_ref().ptr();
# ifdef PYBIND11_BUILTIN_QUALNAME
heap_type->ht_qualname = name_obj.inc_ref().ptr();
# endif
auto *type = &heap_type->ht_type;
type->tp_name = name;
type->tp_base = type_incref(&PyProperty_Type);
type->tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HEAPTYPE;
type->tp_descr_get = pybind11_static_get;
type->tp_descr_set = pybind11_static_set;
# if PY_VERSION_HEX >= 0x030C0000
// Since Python-3.12 property-derived types are required to
// have dynamic attributes (to set `__doc__`)
enable_dynamic_attributes(heap_type);
# endif
if (PyType_Ready(type) < 0) {
pybind11_fail("make_static_property_type(): failure in PyType_Ready()!");
}
setattr((PyObject *) type, "__module__", str(PYBIND11_DUMMY_MODULE_NAME));
PYBIND11_SET_OLDPY_QUALNAME(type, name_obj);
return type;
}
#else // PYPY
/** PyPy has some issues with the above C API, so we evaluate Python code instead.
This function will only be called once so performance isn't really a concern.
Return value: New reference. */
inline PyTypeObject *make_static_property_type() {
auto d = dict();
PyObject *result = PyRun_String(R"(\
class pybind11_static_property(property):
def __get__(self, obj, cls):
return property.__get__(self, cls, cls)
def __set__(self, obj, value):
cls = obj if isinstance(obj, type) else type(obj)
property.__set__(self, cls, value)
)",
Py_file_input,
d.ptr(),
d.ptr());
if (result == nullptr)
throw error_already_set();
Py_DECREF(result);
return (PyTypeObject *) d["pybind11_static_property"].cast<object>().release().ptr();
}
#endif // PYPY
/** Types with static properties need to handle `Type.static_prop = x` in a specific way.
By default, Python replaces the `static_property` itself, but for wrapped C++ types
we need to call `static_property.__set__()` in order to propagate the new value to
the underlying C++ data structure. */
extern "C" inline int pybind11_meta_setattro(PyObject *obj, PyObject *name, PyObject *value) {
// Use `_PyType_Lookup()` instead of `PyObject_GetAttr()` in order to get the raw
// descriptor (`property`) instead of calling `tp_descr_get` (`property.__get__()`).
PyObject *descr = _PyType_Lookup((PyTypeObject *) obj, name);
// The following assignment combinations are possible:
// 1. `Type.static_prop = value` --> descr_set: `Type.static_prop.__set__(value)`
// 2. `Type.static_prop = other_static_prop` --> setattro: replace existing `static_prop`
// 3. `Type.regular_attribute = value` --> setattro: regular attribute assignment
auto *const static_prop = (PyObject *) get_internals().static_property_type;
const auto call_descr_set = (descr != nullptr) && (value != nullptr)
&& (PyObject_IsInstance(descr, static_prop) != 0)
&& (PyObject_IsInstance(value, static_prop) == 0);
if (call_descr_set) {
// Call `static_property.__set__()` instead of replacing the `static_property`.
#if !defined(PYPY_VERSION)
return Py_TYPE(descr)->tp_descr_set(descr, obj, value);
#else
if (PyObject *result = PyObject_CallMethod(descr, "__set__", "OO", obj, value)) {
Py_DECREF(result);
return 0;
} else {
return -1;
}
#endif
} else {
// Replace existing attribute.
return PyType_Type.tp_setattro(obj, name, value);
}
}
/**
* Python 3's PyInstanceMethod_Type hides itself via its tp_descr_get, which prevents aliasing
* methods via cls.attr("m2") = cls.attr("m1"): instead the tp_descr_get returns a plain function,
* when called on a class, or a PyMethod, when called on an instance. Override that behaviour here
* to do a special case bypass for PyInstanceMethod_Types.
*/
extern "C" inline PyObject *pybind11_meta_getattro(PyObject *obj, PyObject *name) {
PyObject *descr = _PyType_Lookup((PyTypeObject *) obj, name);
if (descr && PyInstanceMethod_Check(descr)) {
Py_INCREF(descr);
return descr;
}
return PyType_Type.tp_getattro(obj, name);
}
/// metaclass `__call__` function that is used to create all pybind11 objects.
extern "C" inline PyObject *pybind11_meta_call(PyObject *type, PyObject *args, PyObject *kwargs) {
// use the default metaclass call to create/initialize the object
PyObject *self = PyType_Type.tp_call(type, args, kwargs);
if (self == nullptr) {
return nullptr;
}
// Ensure that the base __init__ function(s) were called
values_and_holders vhs(self);
for (const auto &vh : vhs) {
if (!vh.holder_constructed() && !vhs.is_redundant_value_and_holder(vh)) {
PyErr_Format(PyExc_TypeError,
"%.200s.__init__() must be called when overriding __init__",
get_fully_qualified_tp_name(vh.type->type).c_str());
Py_DECREF(self);
return nullptr;
}
}
return self;
}
/// Cleanup the type-info for a pybind11-registered type.
extern "C" inline void pybind11_meta_dealloc(PyObject *obj) {
with_internals([obj](internals &internals) {
auto *type = (PyTypeObject *) obj;
// A pybind11-registered type will:
// 1) be found in internals.registered_types_py
// 2) have exactly one associated `detail::type_info`
auto found_type = internals.registered_types_py.find(type);
if (found_type != internals.registered_types_py.end() && found_type->second.size() == 1
&& found_type->second[0]->type == type) {
auto *tinfo = found_type->second[0];
auto tindex = std::type_index(*tinfo->cpptype);
internals.direct_conversions.erase(tindex);
if (tinfo->module_local) {
get_local_internals().registered_types_cpp.erase(tindex);
} else {
internals.registered_types_cpp.erase(tindex);
}
internals.registered_types_py.erase(tinfo->type);
// Actually just `std::erase_if`, but that's only available in C++20
auto &cache = internals.inactive_override_cache;
for (auto it = cache.begin(), last = cache.end(); it != last;) {
if (it->first == (PyObject *) tinfo->type) {
it = cache.erase(it);
} else {
++it;
}
}
delete tinfo;
}
});
PyType_Type.tp_dealloc(obj);
}
/** This metaclass is assigned by default to all pybind11 types and is required in order
for static properties to function correctly. Users may override this using `py::metaclass`.
Return value: New reference. */
inline PyTypeObject *make_default_metaclass() {
constexpr auto *name = "pybind11_type";
auto name_obj = reinterpret_steal<object>(PYBIND11_FROM_STRING(name));
/* Danger zone: from now (and until PyType_Ready), make sure to
issue no Python C API calls which could potentially invoke the
garbage collector (the GC will call type_traverse(), which will in
turn find the newly constructed type in an invalid state) */
auto *heap_type = (PyHeapTypeObject *) PyType_Type.tp_alloc(&PyType_Type, 0);
if (!heap_type) {
pybind11_fail("make_default_metaclass(): error allocating metaclass!");
}
heap_type->ht_name = name_obj.inc_ref().ptr();
#ifdef PYBIND11_BUILTIN_QUALNAME
heap_type->ht_qualname = name_obj.inc_ref().ptr();
#endif
auto *type = &heap_type->ht_type;
type->tp_name = name;
type->tp_base = type_incref(&PyType_Type);
type->tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HEAPTYPE;
type->tp_call = pybind11_meta_call;
type->tp_setattro = pybind11_meta_setattro;
type->tp_getattro = pybind11_meta_getattro;
type->tp_dealloc = pybind11_meta_dealloc;
if (PyType_Ready(type) < 0) {
pybind11_fail("make_default_metaclass(): failure in PyType_Ready()!");
}
setattr((PyObject *) type, "__module__", str(PYBIND11_DUMMY_MODULE_NAME));
PYBIND11_SET_OLDPY_QUALNAME(type, name_obj);
return type;
}
/// For multiple inheritance types we need to recursively register/deregister base pointers for any
/// base classes with pointers that are difference from the instance value pointer so that we can
/// correctly recognize an offset base class pointer. This calls a function with any offset base
/// ptrs.
inline void traverse_offset_bases(void *valueptr,
const detail::type_info *tinfo,
instance *self,
bool (*f)(void * /*parentptr*/, instance * /*self*/)) {
for (handle h : reinterpret_borrow<tuple>(tinfo->type->tp_bases)) {
if (auto *parent_tinfo = get_type_info((PyTypeObject *) h.ptr())) {
for (auto &c : parent_tinfo->implicit_casts) {
if (c.first == tinfo->cpptype) {
auto *parentptr = c.second(valueptr);
if (parentptr != valueptr) {
f(parentptr, self);
}
traverse_offset_bases(parentptr, parent_tinfo, self, f);
break;
}
}
}
}
}
#ifdef Py_GIL_DISABLED
inline void enable_try_inc_ref(PyObject *obj) {
// TODO: Replace with PyUnstable_Object_EnableTryIncRef when available.
// See https://github.com/python/cpython/issues/128844
if (_Py_IsImmortal(obj)) {
return;
}
for (;;) {
Py_ssize_t shared = _Py_atomic_load_ssize_relaxed(&obj->ob_ref_shared);
if ((shared & _Py_REF_SHARED_FLAG_MASK) != 0) {
// Nothing to do if it's in WEAKREFS, QUEUED, or MERGED states.
return;
}
if (_Py_atomic_compare_exchange_ssize(
&obj->ob_ref_shared, &shared, shared | _Py_REF_MAYBE_WEAKREF)) {
return;
}
}
}
#endif
inline bool register_instance_impl(void *ptr, instance *self) {
#ifdef Py_GIL_DISABLED
enable_try_inc_ref(reinterpret_cast<PyObject *>(self));
#endif
with_instance_map(ptr, [&](instance_map &instances) { instances.emplace(ptr, self); });
return true; // unused, but gives the same signature as the deregister func
}
inline bool deregister_instance_impl(void *ptr, instance *self) {
return with_instance_map(ptr, [&](instance_map &instances) {
auto range = instances.equal_range(ptr);
for (auto it = range.first; it != range.second; ++it) {
if (self == it->second) {
instances.erase(it);
return true;
}
}
return false;
});
}
inline void register_instance(instance *self, void *valptr, const type_info *tinfo) {
register_instance_impl(valptr, self);
if (!tinfo->simple_ancestors) {
traverse_offset_bases(valptr, tinfo, self, register_instance_impl);
}
}
inline bool deregister_instance(instance *self, void *valptr, const type_info *tinfo) {
bool ret = deregister_instance_impl(valptr, self);
if (!tinfo->simple_ancestors) {
traverse_offset_bases(valptr, tinfo, self, deregister_instance_impl);
}
return ret;
}
/// Instance creation function for all pybind11 types. It allocates the internal instance layout
/// for holding C++ objects and holders. Allocation is done lazily (the first time the instance is
/// cast to a reference or pointer), and initialization is done by an `__init__` function.
inline PyObject *make_new_instance(PyTypeObject *type) {
#if defined(PYPY_VERSION)
// PyPy gets tp_basicsize wrong (issue 2482) under multiple inheritance when the first
// inherited object is a plain Python type (i.e. not derived from an extension type). Fix it.
ssize_t instance_size = static_cast<ssize_t>(sizeof(instance));
if (type->tp_basicsize < instance_size) {
type->tp_basicsize = instance_size;
}
#endif
PyObject *self = type->tp_alloc(type, 0);
auto *inst = reinterpret_cast<instance *>(self);
// Allocate the value/holder internals:
inst->allocate_layout();
return self;
}
/// Instance creation function for all pybind11 types. It only allocates space for the
/// C++ object, but doesn't call the constructor -- an `__init__` function must do that.
extern "C" inline PyObject *pybind11_object_new(PyTypeObject *type, PyObject *, PyObject *) {
return make_new_instance(type);
}
/// An `__init__` function constructs the C++ object. Users should provide at least one
/// of these using `py::init` or directly with `.def(__init__, ...)`. Otherwise, the
/// following default function will be used which simply throws an exception.
extern "C" inline int pybind11_object_init(PyObject *self, PyObject *, PyObject *) {
PyTypeObject *type = Py_TYPE(self);
std::string msg = get_fully_qualified_tp_name(type) + ": No constructor defined!";
set_error(PyExc_TypeError, msg.c_str());
return -1;
}
inline void add_patient(PyObject *nurse, PyObject *patient) {
auto *instance = reinterpret_cast<detail::instance *>(nurse);
instance->has_patients = true;
Py_INCREF(patient);
with_internals([&](internals &internals) { internals.patients[nurse].push_back(patient); });
}
inline void clear_patients(PyObject *self) {
auto *instance = reinterpret_cast<detail::instance *>(self);
std::vector<PyObject *> patients;
with_internals([&](internals &internals) {
auto pos = internals.patients.find(self);
if (pos == internals.patients.end()) {
pybind11_fail(
"FATAL: Internal consistency check failed: Invalid clear_patients() call.");
}
// Clearing the patients can cause more Python code to run, which
// can invalidate the iterator. Extract the vector of patients
// from the unordered_map first.
patients = std::move(pos->second);
internals.patients.erase(pos);
});
instance->has_patients = false;
for (PyObject *&patient : patients) {
Py_CLEAR(patient);
}
}
/// Clears all internal data from the instance and removes it from registered instances in
/// preparation for deallocation.
inline void clear_instance(PyObject *self) {
auto *instance = reinterpret_cast<detail::instance *>(self);
// Deallocate any values/holders, if present:
for (auto &v_h : values_and_holders(instance)) {
if (v_h) {
// We have to deregister before we call dealloc because, for virtual MI types, we still
// need to be able to get the parent pointers.
if (v_h.instance_registered()
&& !deregister_instance(instance, v_h.value_ptr(), v_h.type)) {
pybind11_fail(
"pybind11_object_dealloc(): Tried to deallocate unregistered instance!");
}
if (instance->owned || v_h.holder_constructed()) {
v_h.type->dealloc(v_h);
}
} else if (v_h.holder_constructed()) {
v_h.type->dealloc(v_h); // Disowned instance.
}
}
// Deallocate the value/holder layout internals:
instance->deallocate_layout();
if (instance->weakrefs) {
PyObject_ClearWeakRefs(self);
}
PyObject **dict_ptr = _PyObject_GetDictPtr(self);
if (dict_ptr) {
Py_CLEAR(*dict_ptr);
}
if (instance->has_patients) {
clear_patients(self);
}
}
/// Instance destructor function for all pybind11 types. It calls `type_info.dealloc`
/// to destroy the C++ object itself, while the rest is Python bookkeeping.
extern "C" inline void pybind11_object_dealloc(PyObject *self) {
auto *type = Py_TYPE(self);
// If this is a GC tracked object, untrack it first
// Note that the track call is implicitly done by the
// default tp_alloc, which we never override.
if (PyType_HasFeature(type, Py_TPFLAGS_HAVE_GC) != 0) {
PyObject_GC_UnTrack(self);
}
clear_instance(self);
type->tp_free(self);
// This was not needed before Python 3.8 (Python issue 35810)
// https://github.com/pybind/pybind11/issues/1946
Py_DECREF(type);
}
PYBIND11_WARNING_PUSH
PYBIND11_WARNING_DISABLE_GCC("-Wredundant-decls")
std::string error_string();
PYBIND11_WARNING_POP
/** Create the type which can be used as a common base for all classes. This is
needed in order to satisfy Python's requirements for multiple inheritance.
Return value: New reference. */
inline PyObject *make_object_base_type(PyTypeObject *metaclass) {
constexpr auto *name = "pybind11_object";
auto name_obj = reinterpret_steal<object>(PYBIND11_FROM_STRING(name));
/* Danger zone: from now (and until PyType_Ready), make sure to
issue no Python C API calls which could potentially invoke the
garbage collector (the GC will call type_traverse(), which will in
turn find the newly constructed type in an invalid state) */
auto *heap_type = (PyHeapTypeObject *) metaclass->tp_alloc(metaclass, 0);
if (!heap_type) {
pybind11_fail("make_object_base_type(): error allocating type!");
}
heap_type->ht_name = name_obj.inc_ref().ptr();
#ifdef PYBIND11_BUILTIN_QUALNAME
heap_type->ht_qualname = name_obj.inc_ref().ptr();
#endif
auto *type = &heap_type->ht_type;
type->tp_name = name;
type->tp_base = type_incref(&PyBaseObject_Type);
type->tp_basicsize = static_cast<ssize_t>(sizeof(instance));
type->tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HEAPTYPE;
type->tp_new = pybind11_object_new;
type->tp_init = pybind11_object_init;
type->tp_dealloc = pybind11_object_dealloc;
/* Support weak references (needed for the keep_alive feature) */
type->tp_weaklistoffset = offsetof(instance, weakrefs);
if (PyType_Ready(type) < 0) {
pybind11_fail("PyType_Ready failed in make_object_base_type(): " + error_string());
}
setattr((PyObject *) type, "__module__", str(PYBIND11_DUMMY_MODULE_NAME));
PYBIND11_SET_OLDPY_QUALNAME(type, name_obj);
assert(!PyType_HasFeature(type, Py_TPFLAGS_HAVE_GC));
return (PyObject *) heap_type;
}
/// dynamic_attr: Allow the garbage collector to traverse the internal instance `__dict__`.
extern "C" inline int pybind11_traverse(PyObject *self, visitproc visit, void *arg) {
#if PY_VERSION_HEX >= 0x030D0000
PyObject_VisitManagedDict(self, visit, arg);
#else
PyObject *&dict = *_PyObject_GetDictPtr(self);
Py_VISIT(dict);
#endif
// https://docs.python.org/3/c-api/typeobj.html#c.PyTypeObject.tp_traverse
#if PY_VERSION_HEX >= 0x03090000
Py_VISIT(Py_TYPE(self));
#endif
return 0;
}
/// dynamic_attr: Allow the GC to clear the dictionary.
extern "C" inline int pybind11_clear(PyObject *self) {
#if PY_VERSION_HEX >= 0x030D0000
PyObject_ClearManagedDict(self);
#else
PyObject *&dict = *_PyObject_GetDictPtr(self);
Py_CLEAR(dict);
#endif
return 0;
}
/// Give instances of this type a `__dict__` and opt into garbage collection.
inline void enable_dynamic_attributes(PyHeapTypeObject *heap_type) {
auto *type = &heap_type->ht_type;
type->tp_flags |= Py_TPFLAGS_HAVE_GC;
#ifdef PYBIND11_BACKWARD_COMPATIBILITY_TP_DICTOFFSET
type->tp_dictoffset = type->tp_basicsize; // place dict at the end
type->tp_basicsize += (ssize_t) sizeof(PyObject *); // and allocate enough space for it
#else
type->tp_flags |= Py_TPFLAGS_MANAGED_DICT;
#endif
type->tp_traverse = pybind11_traverse;
type->tp_clear = pybind11_clear;
static PyGetSetDef getset[]
= {{"__dict__", PyObject_GenericGetDict, PyObject_GenericSetDict, nullptr, nullptr},
{nullptr, nullptr, nullptr, nullptr, nullptr}};
type->tp_getset = getset;
}
/// buffer_protocol: Fill in the view as specified by flags.
extern "C" inline int pybind11_getbuffer(PyObject *obj, Py_buffer *view, int flags) {
// Look for a `get_buffer` implementation in this type's info or any bases (following MRO).
type_info *tinfo = nullptr;
for (auto type : reinterpret_borrow<tuple>(Py_TYPE(obj)->tp_mro)) {
tinfo = get_type_info((PyTypeObject *) type.ptr());
if (tinfo && tinfo->get_buffer) {
break;
}
}
if (view == nullptr || !tinfo || !tinfo->get_buffer) {
if (view) {
view->obj = nullptr;
}
set_error(PyExc_BufferError, "pybind11_getbuffer(): Internal error");
return -1;
}
std::memset(view, 0, sizeof(Py_buffer));
std::unique_ptr<buffer_info> info = nullptr;
try {
info.reset(tinfo->get_buffer(obj, tinfo->get_buffer_data));
} catch (...) {
try_translate_exceptions();
raise_from(PyExc_BufferError, "Error getting buffer");
return -1;
}
if (info == nullptr) {
pybind11_fail("FATAL UNEXPECTED SITUATION: tinfo->get_buffer() returned nullptr.");
}
if ((flags & PyBUF_WRITABLE) == PyBUF_WRITABLE && info->readonly) {
// view->obj = nullptr; // Was just memset to 0, so not necessary
set_error(PyExc_BufferError, "Writable buffer requested for readonly storage");
return -1;
}
// Fill in all the information, and then downgrade as requested by the caller, or raise an
// error if that's not possible.
view->itemsize = info->itemsize;
view->len = view->itemsize;
for (auto s : info->shape) {
view->len *= s;
}
view->ndim = static_cast<int>(info->ndim);
view->shape = info->shape.data();
view->strides = info->strides.data();
view->readonly = static_cast<int>(info->readonly);
if ((flags & PyBUF_FORMAT) == PyBUF_FORMAT) {
view->format = const_cast<char *>(info->format.c_str());
}
// Note, all contiguity flags imply PyBUF_STRIDES and lower.
if ((flags & PyBUF_C_CONTIGUOUS) == PyBUF_C_CONTIGUOUS) {
if (PyBuffer_IsContiguous(view, 'C') == 0) {
std::memset(view, 0, sizeof(Py_buffer));
set_error(PyExc_BufferError,
"C-contiguous buffer requested for discontiguous storage");
return -1;
}
} else if ((flags & PyBUF_F_CONTIGUOUS) == PyBUF_F_CONTIGUOUS) {
if (PyBuffer_IsContiguous(view, 'F') == 0) {
std::memset(view, 0, sizeof(Py_buffer));
set_error(PyExc_BufferError,
"Fortran-contiguous buffer requested for discontiguous storage");
return -1;
}
} else if ((flags & PyBUF_ANY_CONTIGUOUS) == PyBUF_ANY_CONTIGUOUS) {
if (PyBuffer_IsContiguous(view, 'A') == 0) {
std::memset(view, 0, sizeof(Py_buffer));
set_error(PyExc_BufferError, "Contiguous buffer requested for discontiguous storage");
return -1;
}
} else if ((flags & PyBUF_STRIDES) != PyBUF_STRIDES) {
// If no strides are requested, the buffer must be C-contiguous.
// https://docs.python.org/3/c-api/buffer.html#contiguity-requests
if (PyBuffer_IsContiguous(view, 'C') == 0) {
std::memset(view, 0, sizeof(Py_buffer));
set_error(PyExc_BufferError,
"C-contiguous buffer requested for discontiguous storage");
return -1;
}
view->strides = nullptr;
// Since this is a contiguous buffer, it can also pretend to be 1D.
if ((flags & PyBUF_ND) != PyBUF_ND) {
view->shape = nullptr;
view->ndim = 0;
}
}
// Set these after all checks so they don't leak out into the caller, and can be automatically
// cleaned up on error.
view->buf = info->ptr;
view->internal = info.release();
view->obj = obj;
Py_INCREF(view->obj);
return 0;
}
/// buffer_protocol: Release the resources of the buffer.
extern "C" inline void pybind11_releasebuffer(PyObject *, Py_buffer *view) {
delete (buffer_info *) view->internal;
}
/// Give this type a buffer interface.
inline void enable_buffer_protocol(PyHeapTypeObject *heap_type) {
heap_type->ht_type.tp_as_buffer = &heap_type->as_buffer;
heap_type->as_buffer.bf_getbuffer = pybind11_getbuffer;
heap_type->as_buffer.bf_releasebuffer = pybind11_releasebuffer;
}
/** Create a brand new Python type according to the `type_record` specification.
Return value: New reference. */
inline PyObject *make_new_python_type(const type_record &rec) {
auto name = reinterpret_steal<object>(PYBIND11_FROM_STRING(rec.name));
auto qualname = name;
if (rec.scope && !PyModule_Check(rec.scope.ptr()) && hasattr(rec.scope, "__qualname__")) {
qualname = reinterpret_steal<object>(
PyUnicode_FromFormat("%U.%U", rec.scope.attr("__qualname__").ptr(), name.ptr()));
}
object module_ = get_module_name_if_available(rec.scope);
const auto *full_name = c_str(
#if !defined(PYPY_VERSION)
module_ ? str(module_).cast<std::string>() + "." + rec.name :
#endif
rec.name);
char *tp_doc = nullptr;
if (rec.doc && options::show_user_defined_docstrings()) {
/* Allocate memory for docstring (Python will free this later on) */
size_t size = std::strlen(rec.doc) + 1;
#if PY_VERSION_HEX >= 0x030D0000
tp_doc = (char *) PyMem_MALLOC(size);
#else
tp_doc = (char *) PyObject_MALLOC(size);
#endif
std::memcpy((void *) tp_doc, rec.doc, size);
}
auto &internals = get_internals();
auto bases = tuple(rec.bases);
auto *base = (bases.empty()) ? internals.instance_base : bases[0].ptr();
/* Danger zone: from now (and until PyType_Ready), make sure to
issue no Python C API calls which could potentially invoke the
garbage collector (the GC will call type_traverse(), which will in
turn find the newly constructed type in an invalid state) */
auto *metaclass
= rec.metaclass.ptr() ? (PyTypeObject *) rec.metaclass.ptr() : internals.default_metaclass;
auto *heap_type = (PyHeapTypeObject *) metaclass->tp_alloc(metaclass, 0);
if (!heap_type) {
pybind11_fail(std::string(rec.name) + ": Unable to create type object!");
}
heap_type->ht_name = name.release().ptr();
#ifdef PYBIND11_BUILTIN_QUALNAME
heap_type->ht_qualname = qualname.inc_ref().ptr();
#endif
auto *type = &heap_type->ht_type;
type->tp_name = full_name;
type->tp_doc = tp_doc;
type->tp_base = type_incref((PyTypeObject *) base);
type->tp_basicsize = static_cast<ssize_t>(sizeof(instance));
if (!bases.empty()) {
type->tp_bases = bases.release().ptr();
}
/* Don't inherit base __init__ */
type->tp_init = pybind11_object_init;
/* Supported protocols */
type->tp_as_number = &heap_type->as_number;
type->tp_as_sequence = &heap_type->as_sequence;
type->tp_as_mapping = &heap_type->as_mapping;
type->tp_as_async = &heap_type->as_async;
/* Flags */
type->tp_flags |= Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HEAPTYPE;
if (!rec.is_final) {
type->tp_flags |= Py_TPFLAGS_BASETYPE;
}
if (rec.dynamic_attr) {
enable_dynamic_attributes(heap_type);
}
if (rec.buffer_protocol) {
enable_buffer_protocol(heap_type);
}
if (rec.custom_type_setup_callback) {
rec.custom_type_setup_callback(heap_type);
}
if (PyType_Ready(type) < 0) {
pybind11_fail(std::string(rec.name) + ": PyType_Ready failed: " + error_string());
}
assert(!rec.dynamic_attr || PyType_HasFeature(type, Py_TPFLAGS_HAVE_GC));
/* Register type with the parent scope */
if (rec.scope) {
setattr(rec.scope, rec.name, (PyObject *) type);
} else {
Py_INCREF(type); // Keep it alive forever (reference leak)
}
if (module_) { // Needed by pydoc
setattr((PyObject *) type, "__module__", module_);
}
PYBIND11_SET_OLDPY_QUALNAME(type, qualname);
return (PyObject *) type;
}
PYBIND11_NAMESPACE_END(detail)
PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,75 @@
// Copyright (c) 2024 The pybind Community.
#pragma once
#include <pybind11/pytypes.h>
#include "common.h"
#include "internals.h"
#include <typeinfo>
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
PYBIND11_NAMESPACE_BEGIN(detail)
// Forward declaration needed here: Refactoring opportunity.
extern "C" inline PyObject *pybind11_object_new(PyTypeObject *type, PyObject *, PyObject *);
inline bool type_is_managed_by_our_internals(PyTypeObject *type_obj) {
#if defined(PYPY_VERSION)
auto &internals = get_internals();
return bool(internals.registered_types_py.find(type_obj)
!= internals.registered_types_py.end());
#else
return bool(type_obj->tp_new == pybind11_object_new);
#endif
}
inline bool is_instance_method_of_type(PyTypeObject *type_obj, PyObject *attr_name) {
PyObject *descr = _PyType_Lookup(type_obj, attr_name);
return bool((descr != nullptr) && PyInstanceMethod_Check(descr));
}
inline object try_get_cpp_conduit_method(PyObject *obj) {
if (PyType_Check(obj)) {
return object();
}
PyTypeObject *type_obj = Py_TYPE(obj);
str attr_name("_pybind11_conduit_v1_");
bool assumed_to_be_callable = false;
if (type_is_managed_by_our_internals(type_obj)) {
if (!is_instance_method_of_type(type_obj, attr_name.ptr())) {
return object();
}
assumed_to_be_callable = true;
}
PyObject *method = PyObject_GetAttr(obj, attr_name.ptr());
if (method == nullptr) {
PyErr_Clear();
return object();
}
if (!assumed_to_be_callable && PyCallable_Check(method) == 0) {
Py_DECREF(method);
return object();
}
return reinterpret_steal<object>(method);
}
inline void *try_raw_pointer_ephemeral_from_cpp_conduit(handle src,
const std::type_info *cpp_type_info) {
object method = try_get_cpp_conduit_method(src.ptr());
if (method) {
capsule cpp_type_info_capsule(const_cast<void *>(static_cast<const void *>(cpp_type_info)),
typeid(std::type_info).name());
object cpp_conduit = method(bytes(PYBIND11_PLATFORM_ABI_ID),
cpp_type_info_capsule,
bytes("raw_pointer_ephemeral"));
if (isinstance<capsule>(cpp_conduit)) {
return reinterpret_borrow<capsule>(cpp_conduit).get_pointer();
}
}
return nullptr;
}
PYBIND11_NAMESPACE_END(detail)
PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)

View File

@@ -0,0 +1,226 @@
/*
pybind11/detail/descr.h: Helper type for concatenating type signatures at compile time
Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch>
All rights reserved. Use of this source code is governed by a
BSD-style license that can be found in the LICENSE file.
*/
#pragma once
#include "common.h"
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
PYBIND11_NAMESPACE_BEGIN(detail)
#if !defined(_MSC_VER)
# define PYBIND11_DESCR_CONSTEXPR static constexpr
#else
# define PYBIND11_DESCR_CONSTEXPR const
#endif
/* Concatenate type signatures at compile time */
template <size_t N, typename... Ts>
struct descr {
char text[N + 1]{'\0'};
constexpr descr() = default;
// NOLINTNEXTLINE(google-explicit-constructor)
constexpr descr(char const (&s)[N + 1]) : descr(s, make_index_sequence<N>()) {}
template <size_t... Is>
constexpr descr(char const (&s)[N + 1], index_sequence<Is...>) : text{s[Is]..., '\0'} {}
template <typename... Chars>
// NOLINTNEXTLINE(google-explicit-constructor)
constexpr descr(char c, Chars... cs) : text{c, static_cast<char>(cs)..., '\0'} {}
static constexpr std::array<const std::type_info *, sizeof...(Ts) + 1> types() {
return {{&typeid(Ts)..., nullptr}};
}
};
template <size_t N1, size_t N2, typename... Ts1, typename... Ts2, size_t... Is1, size_t... Is2>
constexpr descr<N1 + N2, Ts1..., Ts2...> plus_impl(const descr<N1, Ts1...> &a,
const descr<N2, Ts2...> &b,
index_sequence<Is1...>,
index_sequence<Is2...>) {
PYBIND11_WORKAROUND_INCORRECT_MSVC_C4100(b);
return {a.text[Is1]..., b.text[Is2]...};
}
template <size_t N1, size_t N2, typename... Ts1, typename... Ts2>
constexpr descr<N1 + N2, Ts1..., Ts2...> operator+(const descr<N1, Ts1...> &a,
const descr<N2, Ts2...> &b) {
return plus_impl(a, b, make_index_sequence<N1>(), make_index_sequence<N2>());
}
template <size_t N>
constexpr descr<N - 1> const_name(char const (&text)[N]) {
return descr<N - 1>(text);
}
constexpr descr<0> const_name(char const (&)[1]) { return {}; }
template <size_t Rem, size_t... Digits>
struct int_to_str : int_to_str<Rem / 10, Rem % 10, Digits...> {};
template <size_t... Digits>
struct int_to_str<0, Digits...> {
// WARNING: This only works with C++17 or higher.
static constexpr auto digits = descr<sizeof...(Digits)>(('0' + Digits)...);
};
// Ternary description (like std::conditional)
template <bool B, size_t N1, size_t N2>
constexpr enable_if_t<B, descr<N1 - 1>> const_name(char const (&text1)[N1], char const (&)[N2]) {
return const_name(text1);
}
template <bool B, size_t N1, size_t N2>
constexpr enable_if_t<!B, descr<N2 - 1>> const_name(char const (&)[N1], char const (&text2)[N2]) {
return const_name(text2);
}
template <bool B, typename T1, typename T2>
constexpr enable_if_t<B, T1> const_name(const T1 &d, const T2 &) {
return d;
}
template <bool B, typename T1, typename T2>
constexpr enable_if_t<!B, T2> const_name(const T1 &, const T2 &d) {
return d;
}
template <size_t Size>
auto constexpr const_name() -> remove_cv_t<decltype(int_to_str<Size / 10, Size % 10>::digits)> {
return int_to_str<Size / 10, Size % 10>::digits;
}
template <typename Type>
constexpr descr<1, Type> const_name() {
return {'%'};
}
// Use a different name based on whether the parameter is used as input or output
template <size_t N1, size_t N2>
constexpr descr<N1 + N2 + 1> io_name(char const (&text1)[N1], char const (&text2)[N2]) {
return const_name("@") + const_name(text1) + const_name("@") + const_name(text2)
+ const_name("@");
}
// Ternary description for io_name (like the numeric type_caster)
template <bool B, size_t N1, size_t N2, size_t N3, size_t N4>
constexpr enable_if_t<B, descr<N1 + N2 + 1>>
io_name(char const (&text1)[N1], char const (&text2)[N2], char const (&)[N3], char const (&)[N4]) {
return io_name(text1, text2);
}
template <bool B, size_t N1, size_t N2, size_t N3, size_t N4>
constexpr enable_if_t<!B, descr<N3 + N4 + 1>>
io_name(char const (&)[N1], char const (&)[N2], char const (&text3)[N3], char const (&text4)[N4]) {
return io_name(text3, text4);
}
// If "_" is defined as a macro, py::detail::_ cannot be provided.
// It is therefore best to use py::detail::const_name universally.
// This block is for backward compatibility only.
// (The const_name code is repeated to avoid introducing a "_" #define ourselves.)
#ifndef _
# define PYBIND11_DETAIL_UNDERSCORE_BACKWARD_COMPATIBILITY
template <size_t N>
constexpr descr<N - 1> _(char const (&text)[N]) {
return const_name<N>(text);
}
template <bool B, size_t N1, size_t N2>
constexpr enable_if_t<B, descr<N1 - 1>> _(char const (&text1)[N1], char const (&text2)[N2]) {
return const_name<B, N1, N2>(text1, text2);
}
template <bool B, size_t N1, size_t N2>
constexpr enable_if_t<!B, descr<N2 - 1>> _(char const (&text1)[N1], char const (&text2)[N2]) {
return const_name<B, N1, N2>(text1, text2);
}
template <bool B, typename T1, typename T2>
constexpr enable_if_t<B, T1> _(const T1 &d1, const T2 &d2) {
return const_name<B, T1, T2>(d1, d2);
}
template <bool B, typename T1, typename T2>
constexpr enable_if_t<!B, T2> _(const T1 &d1, const T2 &d2) {
return const_name<B, T1, T2>(d1, d2);
}
template <size_t Size>
auto constexpr _() -> remove_cv_t<decltype(int_to_str<Size / 10, Size % 10>::digits)> {
return const_name<Size>();
}
template <typename Type>
constexpr descr<1, Type> _() {
return const_name<Type>();
}
#endif // #ifndef _
constexpr descr<0> concat() { return {}; }
constexpr descr<0> union_concat() { return {}; }
template <size_t N, typename... Ts>
constexpr descr<N, Ts...> concat(const descr<N, Ts...> &descr) {
return descr;
}
template <size_t N, typename... Ts>
constexpr descr<N, Ts...> union_concat(const descr<N, Ts...> &descr) {
return descr;
}
template <size_t N1, size_t N2, typename... Ts1, typename... Ts2>
constexpr descr<N1 + N2 + 3, Ts1..., Ts2...> operator|(const descr<N1, Ts1...> &a,
const descr<N2, Ts2...> &b) {
return a + const_name(" | ") + b;
}
#ifdef __cpp_fold_expressions
template <size_t N1, size_t N2, typename... Ts1, typename... Ts2>
constexpr descr<N1 + N2 + 2, Ts1..., Ts2...> operator,(const descr<N1, Ts1...> &a,
const descr<N2, Ts2...> &b) {
return a + const_name(", ") + b;
}
template <size_t N, typename... Ts, typename... Args>
constexpr auto concat(const descr<N, Ts...> &d, const Args &...args) {
return (d, ..., args);
}
template <size_t N, typename... Ts, typename... Args>
constexpr auto union_concat(const descr<N, Ts...> &d, const Args &...args) {
return (d | ... | args);
}
#else
template <size_t N, typename... Ts, typename... Args>
constexpr auto concat(const descr<N, Ts...> &d, const Args &...args)
-> decltype(std::declval<descr<N + 2, Ts...>>() + concat(args...)) {
return d + const_name(", ") + concat(args...);
}
template <size_t N, typename... Ts, typename... Args>
constexpr auto union_concat(const descr<N, Ts...> &d, const Args &...args)
-> decltype(std::declval<descr<N + 3, Ts...>>() + union_concat(args...)) {
return d + const_name(" | ") + union_concat(args...);
}
#endif
template <size_t N, typename... Ts>
constexpr descr<N + 2, Ts...> type_descr(const descr<N, Ts...> &descr) {
return const_name("{") + descr + const_name("}");
}
template <size_t N, typename... Ts>
constexpr descr<N + 4, Ts...> arg_descr(const descr<N, Ts...> &descr) {
return const_name("@^") + descr + const_name("@!");
}
template <size_t N, typename... Ts>
constexpr descr<N + 4, Ts...> return_descr(const descr<N, Ts...> &descr) {
return const_name("@$") + descr + const_name("@!");
}
PYBIND11_NAMESPACE_END(detail)
PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)

View File

@@ -0,0 +1,39 @@
// Copyright (c) 2021 The Pybind Development Team.
// All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
#pragma once
#include "common.h"
#include <type_traits>
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
PYBIND11_NAMESPACE_BEGIN(detail)
template <typename To, typename From, typename SFINAE = void>
struct dynamic_raw_ptr_cast_is_possible : std::false_type {};
template <typename To, typename From>
struct dynamic_raw_ptr_cast_is_possible<
To,
From,
detail::enable_if_t<!std::is_same<To, void>::value && std::is_polymorphic<From>::value>>
: std::true_type {};
template <typename To,
typename From,
detail::enable_if_t<!dynamic_raw_ptr_cast_is_possible<To, From>::value, int> = 0>
To *dynamic_raw_ptr_cast_if_possible(From * /*ptr*/) {
return nullptr;
}
template <typename To,
typename From,
detail::enable_if_t<dynamic_raw_ptr_cast_is_possible<To, From>::value, int> = 0>
To *dynamic_raw_ptr_cast_if_possible(From *ptr) {
return dynamic_cast<To *>(ptr);
}
PYBIND11_NAMESPACE_END(detail)
PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)

View File

@@ -0,0 +1,71 @@
/*
pybind11/detail/exception_translation.h: means to translate C++ exceptions to Python exceptions
Copyright (c) 2024 The Pybind Development Team.
All rights reserved. Use of this source code is governed by a
BSD-style license that can be found in the LICENSE file.
*/
#pragma once
#include "common.h"
#include "internals.h"
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
PYBIND11_NAMESPACE_BEGIN(detail)
// Apply all the extensions translators from a list
// Return true if one of the translators completed without raising an exception
// itself. Return of false indicates that if there are other translators
// available, they should be tried.
inline bool apply_exception_translators(std::forward_list<ExceptionTranslator> &translators) {
auto last_exception = std::current_exception();
for (auto &translator : translators) {
try {
translator(last_exception);
return true;
} catch (...) {
last_exception = std::current_exception();
}
}
return false;
}
inline void try_translate_exceptions() {
/* When an exception is caught, give each registered exception
translator a chance to translate it to a Python exception. First
all module-local translators will be tried in reverse order of
registration. If none of the module-locale translators handle
the exception (or there are no module-locale translators) then
the global translators will be tried, also in reverse order of
registration.
A translator may choose to do one of the following:
- catch the exception and call py::set_error()
to set a standard (or custom) Python exception, or
- do nothing and let the exception fall through to the next translator, or
- delegate translation to the next translator by throwing a new type of exception.
*/
bool handled = with_exception_translators(
[&](std::forward_list<ExceptionTranslator> &exception_translators,
std::forward_list<ExceptionTranslator> &local_exception_translators) {
if (detail::apply_exception_translators(local_exception_translators)) {
return true;
}
if (detail::apply_exception_translators(exception_translators)) {
return true;
}
return false;
});
if (!handled) {
set_error(PyExc_SystemError, "Exception escaped from default exception translator!");
}
}
PYBIND11_NAMESPACE_END(detail)
PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)

View File

@@ -0,0 +1,191 @@
// Copyright (c) 2024-2025 The Pybind Development Team.
// All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
// For background see the description of PR google/pybind11clif#30099.
#pragma once
#include <pybind11/attr.h>
#include <pybind11/conduit/pybind11_platform_abi_id.h>
#include <pybind11/pytypes.h>
#include "common.h"
#include <cstring>
#include <utility>
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
PYBIND11_NAMESPACE_BEGIN(detail)
struct function_record_PyObject {
PyObject_HEAD
function_record *cpp_func_rec;
};
PYBIND11_NAMESPACE_BEGIN(function_record_PyTypeObject_methods)
PyObject *tp_new_impl(PyTypeObject *type, PyObject *args, PyObject *kwds);
PyObject *tp_alloc_impl(PyTypeObject *type, Py_ssize_t nitems);
int tp_init_impl(PyObject *self, PyObject *args, PyObject *kwds);
void tp_dealloc_impl(PyObject *self);
void tp_free_impl(void *self);
static PyObject *reduce_ex_impl(PyObject *self, PyObject *, PyObject *);
static PyMethodDef tp_methods_impl[]
= {{"__reduce_ex__",
// reduce_ex_impl is a PyCFunctionWithKeywords, but PyMethodDef
// requires a PyCFunction. The cast through void* is safe and
// idiomatic with METH_KEYWORDS, and it successfully sidesteps
// unhelpful compiler warnings.
// NOLINTNEXTLINE(bugprone-casting-through-void)
reinterpret_cast<PyCFunction>(reinterpret_cast<void *>(reduce_ex_impl)),
METH_VARARGS | METH_KEYWORDS,
nullptr},
{nullptr, nullptr, 0, nullptr}};
// Python 3.12+ emits a DeprecationWarning for heap types whose tp_name does
// not contain a dot ('.') and that lack a __module__ attribute. For pybind11's
// internal function_record type, we do not have an actual module object to
// attach, so we cannot use PyType_FromModuleAndSpec (introduced in Python 3.9)
// to set __module__ automatically.
//
// As a workaround, we define a "qualified" type name that includes a dummy
// module name (PYBIND11_DUMMY_MODULE_NAME). This is nonidiomatic but avoids
// the deprecation warning, and results in reprs like
//
// <class 'pybind11_builtins.pybind11_detail_function_record_...'>
//
// even though no real pybind11_builtins module exists. If pybind11 gains an
// actual module object in the future, this code should switch to
// PyType_FromModuleAndSpec for Python 3.9+ and drop the dummy module
// workaround.
//
// Note that this name is versioned.
#define PYBIND11_DETAIL_FUNCTION_RECORD_TP_PLAINNAME \
"pybind11_detail_function_record_" PYBIND11_DETAIL_FUNCTION_RECORD_ABI_ID \
"_" PYBIND11_PLATFORM_ABI_ID
constexpr char tp_plainname_impl[] = PYBIND11_DETAIL_FUNCTION_RECORD_TP_PLAINNAME;
constexpr char tp_qualname_impl[]
= PYBIND11_DUMMY_MODULE_NAME "." PYBIND11_DETAIL_FUNCTION_RECORD_TP_PLAINNAME;
PYBIND11_NAMESPACE_END(function_record_PyTypeObject_methods)
static PyType_Slot function_record_PyType_Slots[] = {
{Py_tp_dealloc,
reinterpret_cast<void *>(function_record_PyTypeObject_methods::tp_dealloc_impl)},
{Py_tp_methods,
reinterpret_cast<void *>(function_record_PyTypeObject_methods::tp_methods_impl)},
{Py_tp_init, reinterpret_cast<void *>(function_record_PyTypeObject_methods::tp_init_impl)},
{Py_tp_alloc, reinterpret_cast<void *>(function_record_PyTypeObject_methods::tp_alloc_impl)},
{Py_tp_new, reinterpret_cast<void *>(function_record_PyTypeObject_methods::tp_new_impl)},
{Py_tp_free, reinterpret_cast<void *>(function_record_PyTypeObject_methods::tp_free_impl)},
{0, nullptr}};
static PyType_Spec function_record_PyType_Spec
= {function_record_PyTypeObject_methods::tp_qualname_impl,
sizeof(function_record_PyObject),
0,
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HEAPTYPE,
function_record_PyType_Slots};
inline PyTypeObject *get_function_record_PyTypeObject() {
PyTypeObject *&py_type_obj = detail::get_local_internals().function_record_py_type;
if (!py_type_obj) {
PyObject *py_obj = PyType_FromSpec(&function_record_PyType_Spec);
if (py_obj == nullptr) {
throw error_already_set();
}
py_type_obj = reinterpret_cast<PyTypeObject *>(py_obj);
}
return py_type_obj;
}
inline bool is_function_record_PyObject(PyObject *obj) {
if (PyType_Check(obj) != 0) {
return false;
}
PyTypeObject *obj_type = Py_TYPE(obj);
PyTypeObject *frtype = get_function_record_PyTypeObject();
// Fast path (pointer comparison).
if (obj_type == frtype) {
return true;
}
// This works across extension modules. Note that tp_name is versioned.
if (strcmp(obj_type->tp_name, function_record_PyTypeObject_methods::tp_qualname_impl) == 0
|| strcmp(obj_type->tp_name, function_record_PyTypeObject_methods::tp_plainname_impl)
== 0) {
return true;
}
return false;
}
inline function_record *function_record_ptr_from_PyObject(PyObject *obj) {
if (is_function_record_PyObject(obj)) {
return ((detail::function_record_PyObject *) obj)->cpp_func_rec;
}
return nullptr;
}
inline object function_record_PyObject_New() {
auto *py_func_rec = PyObject_New(function_record_PyObject, get_function_record_PyTypeObject());
if (py_func_rec == nullptr) {
throw error_already_set();
}
py_func_rec->cpp_func_rec = nullptr; // For clarity/purity. Redundant in practice.
return reinterpret_steal<object>((PyObject *) py_func_rec);
}
PYBIND11_NAMESPACE_BEGIN(function_record_PyTypeObject_methods)
// Guard against accidents & oversights, in particular when porting to future Python versions.
inline PyObject *tp_new_impl(PyTypeObject *, PyObject *, PyObject *) {
pybind11_fail("UNEXPECTED CALL OF function_record_PyTypeObject_methods::tp_new_impl");
// return nullptr; // Unreachable.
}
inline PyObject *tp_alloc_impl(PyTypeObject *, Py_ssize_t) {
pybind11_fail("UNEXPECTED CALL OF function_record_PyTypeObject_methods::tp_alloc_impl");
// return nullptr; // Unreachable.
}
inline int tp_init_impl(PyObject *, PyObject *, PyObject *) {
pybind11_fail("UNEXPECTED CALL OF function_record_PyTypeObject_methods::tp_init_impl");
// return -1; // Unreachable.
}
inline void tp_free_impl(void *) {
pybind11_fail("UNEXPECTED CALL OF function_record_PyTypeObject_methods::tp_free_impl");
}
inline PyObject *reduce_ex_impl(PyObject *self, PyObject *, PyObject *) {
// Deliberately ignoring the arguments for simplicity (expected is `protocol: int`).
const function_record *rec = function_record_ptr_from_PyObject(self);
if (rec == nullptr) {
pybind11_fail(
"FATAL: function_record_PyTypeObject reduce_ex_impl(): cannot obtain cpp_func_rec.");
}
if (rec->name != nullptr && rec->name[0] != '\0' && rec->scope
&& PyModule_Check(rec->scope.ptr()) != 0) {
object scope_module = get_scope_module(rec->scope);
if (scope_module) {
auto builtins = reinterpret_borrow<dict>(PyEval_GetBuiltins());
auto builtins_eval = builtins["eval"];
auto reconstruct_args = make_tuple(str("__import__('importlib').import_module('")
+ scope_module + str("')"));
return make_tuple(std::move(builtins_eval), std::move(reconstruct_args))
.release()
.ptr();
}
}
set_error(PyExc_RuntimeError, repr(self) + str(" is not pickleable."));
return nullptr;
}
PYBIND11_NAMESPACE_END(function_record_PyTypeObject_methods)
PYBIND11_NAMESPACE_END(detail)
PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)

View File

@@ -0,0 +1,538 @@
/*
pybind11/detail/init.h: init factory function implementation and support code.
Copyright (c) 2017 Jason Rhinelander <jason@imaginary.ca>
All rights reserved. Use of this source code is governed by a
BSD-style license that can be found in the LICENSE file.
*/
#pragma once
#include "class.h"
#include "using_smart_holder.h"
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
PYBIND11_WARNING_DISABLE_MSVC(4127)
PYBIND11_NAMESPACE_BEGIN(detail)
template <>
class type_caster<value_and_holder> {
public:
bool load(handle h, bool) {
value = reinterpret_cast<value_and_holder *>(h.ptr());
return true;
}
template <typename>
using cast_op_type = value_and_holder &;
explicit operator value_and_holder &() { return *value; }
static constexpr auto name = const_name<value_and_holder>();
private:
value_and_holder *value = nullptr;
};
PYBIND11_NAMESPACE_BEGIN(initimpl)
inline void no_nullptr(const void *ptr) {
if (!ptr) {
throw type_error("pybind11::init(): factory function returned nullptr");
}
}
// Implementing functions for all forms of py::init<...> and py::init(...)
template <typename Class>
using Cpp = typename Class::type;
template <typename Class>
using Alias = typename Class::type_alias;
template <typename Class>
using Holder = typename Class::holder_type;
template <typename Class>
using is_alias_constructible = std::is_constructible<Alias<Class>, Cpp<Class> &&>;
// Takes a Cpp pointer and returns true if it actually is a polymorphic Alias instance.
template <typename Class, enable_if_t<Class::has_alias, int> = 0>
bool is_alias(Cpp<Class> *ptr) {
return dynamic_cast<Alias<Class> *>(ptr) != nullptr;
}
// Failing fallback version of the above for a no-alias class (always returns false)
template <typename /*Class*/>
constexpr bool is_alias(const void *) {
return false;
}
// Constructs and returns a new object; if the given arguments don't map to a constructor, we fall
// back to brace aggregate initialization so that for aggregate initialization can be used with
// py::init, e.g. `py::init<int, int>` to initialize a `struct T { int a; int b; }`. For
// non-aggregate types, we need to use an ordinary T(...) constructor (invoking as `T{...}` usually
// works, but will not do the expected thing when `T` has an `initializer_list<T>` constructor).
template <typename Class,
typename... Args,
detail::enable_if_t<std::is_constructible<Class, Args...>::value, int> = 0>
inline Class *construct_or_initialize(Args &&...args) {
return new Class(std::forward<Args>(args)...);
}
template <typename Class,
typename... Args,
detail::enable_if_t<!std::is_constructible<Class, Args...>::value, int> = 0>
inline Class *construct_or_initialize(Args &&...args) {
return new Class{std::forward<Args>(args)...};
}
// Attempts to constructs an alias using a `Alias(Cpp &&)` constructor. This allows types with
// an alias to provide only a single Cpp factory function as long as the Alias can be
// constructed from an rvalue reference of the base Cpp type. This means that Alias classes
// can, when appropriate, simply define a `Alias(Cpp &&)` constructor rather than needing to
// inherit all the base class constructors.
template <typename Class>
void construct_alias_from_cpp(std::true_type /*is_alias_constructible*/,
value_and_holder &v_h,
Cpp<Class> &&base) {
v_h.value_ptr() = new Alias<Class>(std::move(base));
}
template <typename Class>
[[noreturn]] void construct_alias_from_cpp(std::false_type /*!is_alias_constructible*/,
value_and_holder &,
Cpp<Class> &&) {
throw type_error("pybind11::init(): unable to convert returned instance to required "
"alias class: no `Alias<Class>(Class &&)` constructor available");
}
// Error-generating fallback for factories that don't match one of the below construction
// mechanisms.
template <typename Class>
void construct(...) {
static_assert(!std::is_same<Class, Class>::value /* always false */,
"pybind11::init(): init function must return a compatible pointer, "
"holder, or value");
}
// Pointer return v1: the factory function returns a class pointer for a registered class.
// If we don't need an alias (because this class doesn't have one, or because the final type is
// inherited on the Python side) we can simply take over ownership. Otherwise we need to try to
// construct an Alias from the returned base instance.
template <typename Class>
void construct(value_and_holder &v_h, Cpp<Class> *ptr, bool need_alias) {
PYBIND11_WORKAROUND_INCORRECT_MSVC_C4100(need_alias);
no_nullptr(ptr);
if (Class::has_alias && need_alias && !is_alias<Class>(ptr)) {
// We're going to try to construct an alias by moving the cpp type. Whether or not
// that succeeds, we still need to destroy the original cpp pointer (either the
// moved away leftover, if the alias construction works, or the value itself if we
// throw an error), but we can't just call `delete ptr`: it might have a special
// deleter, or might be shared_from_this. So we construct a holder around it as if
// it was a normal instance, then steal the holder away into a local variable; thus
// the holder and destruction happens when we leave the C++ scope, and the holder
// class gets to handle the destruction however it likes.
v_h.value_ptr() = ptr;
v_h.set_instance_registered(true); // Trick to prevent init_instance from registering it
// DANGER ZONE BEGIN: exceptions will leave v_h in an invalid state.
v_h.type->init_instance(v_h.inst, nullptr); // Set up the holder
Holder<Class> temp_holder(std::move(v_h.holder<Holder<Class>>())); // Steal the holder
v_h.type->dealloc(v_h); // Destroys the moved-out holder remains, resets value ptr to null
v_h.set_instance_registered(false);
// DANGER ZONE END.
construct_alias_from_cpp<Class>(is_alias_constructible<Class>{}, v_h, std::move(*ptr));
} else {
// Otherwise the type isn't inherited, so we don't need an Alias
v_h.value_ptr() = ptr;
}
}
// Pointer return v2: a factory that always returns an alias instance ptr. We simply take over
// ownership of the pointer.
template <typename Class, enable_if_t<Class::has_alias, int> = 0>
void construct(value_and_holder &v_h, Alias<Class> *alias_ptr, bool) {
no_nullptr(alias_ptr);
v_h.value_ptr() = static_cast<Cpp<Class> *>(alias_ptr);
}
// Holder return: copy its pointer, and move or copy the returned holder into the new instance's
// holder. This also handles types like std::shared_ptr<T> and std::unique_ptr<T> where T is a
// derived type (through those holder's implicit conversion from derived class holder
// constructors).
template <typename Class, detail::enable_if_t<!is_smart_holder<Holder<Class>>::value, int> = 0>
void construct(value_and_holder &v_h, Holder<Class> holder, bool need_alias) {
PYBIND11_WORKAROUND_INCORRECT_MSVC_C4100(need_alias);
auto *ptr = holder_helper<Holder<Class>>::get(holder);
no_nullptr(ptr);
// If we need an alias, check that the held pointer is actually an alias instance
if (Class::has_alias && need_alias && !is_alias<Class>(ptr)) {
throw type_error("pybind11::init(): construction failed: returned holder-wrapped instance "
"is not an alias instance");
}
// Cast away constness to store in void* storage.
// The value_and_holder storage is fundamentally untyped (void**), so we lose
// const-correctness here by design. The const qualifier will be restored
// when the pointer is later retrieved and cast back to the original type.
// This explicit const_cast makes the const-removal clearly visible.
v_h.value_ptr() = const_cast<void *>(static_cast<const void *>(ptr));
v_h.type->init_instance(v_h.inst, &holder);
}
// return-by-value version 1: returning a cpp class by value. If the class has an alias and an
// alias is required the alias must have an `Alias(Cpp &&)` constructor so that we can construct
// the alias from the base when needed (i.e. because of Python-side inheritance). When we don't
// need it, we simply move-construct the cpp value into a new instance.
template <typename Class>
void construct(value_and_holder &v_h, Cpp<Class> &&result, bool need_alias) {
PYBIND11_WORKAROUND_INCORRECT_MSVC_C4100(need_alias);
static_assert(is_move_constructible<Cpp<Class>>::value,
"pybind11::init() return-by-value factory function requires a movable class");
if (Class::has_alias && need_alias) {
construct_alias_from_cpp<Class>(is_alias_constructible<Class>{}, v_h, std::move(result));
} else {
v_h.value_ptr() = new Cpp<Class>(std::move(result));
}
}
// return-by-value version 2: returning a value of the alias type itself. We move-construct an
// Alias instance (even if no the python-side inheritance is involved). The is intended for
// cases where Alias initialization is always desired.
template <typename Class>
void construct(value_and_holder &v_h, Alias<Class> &&result, bool) {
static_assert(
is_move_constructible<Alias<Class>>::value,
"pybind11::init() return-by-alias-value factory function requires a movable alias class");
v_h.value_ptr() = new Alias<Class>(std::move(result));
}
template <typename T, typename D>
smart_holder init_smart_holder_from_unique_ptr(std::unique_ptr<T, D> &&unq_ptr,
bool void_cast_raw_ptr) {
void *void_ptr = void_cast_raw_ptr ? static_cast<void *>(unq_ptr.get()) : nullptr;
return smart_holder::from_unique_ptr(std::move(unq_ptr), void_ptr);
}
template <typename Class,
typename D = std::default_delete<Cpp<Class>>,
detail::enable_if_t<is_smart_holder<Holder<Class>>::value, int> = 0>
void construct(value_and_holder &v_h, std::unique_ptr<Cpp<Class>, D> &&unq_ptr, bool need_alias) {
PYBIND11_WORKAROUND_INCORRECT_MSVC_C4100(need_alias);
auto *ptr = unq_ptr.get();
no_nullptr(ptr);
if (Class::has_alias && need_alias && !is_alias<Class>(ptr)) {
throw type_error("pybind11::init(): construction failed: returned std::unique_ptr pointee "
"is not an alias instance");
}
// Here and below: if the new object is a trampoline, the shared_from_this mechanism needs
// to be prevented from accessing the smart_holder vptr, because it does not keep the
// trampoline Python object alive. For types that don't inherit from enable_shared_from_this
// it does not matter if void_cast_raw_ptr is true or false, therefore it's not necessary
// to also inspect the type.
auto smhldr = init_smart_holder_from_unique_ptr(
std::move(unq_ptr), /*void_cast_raw_ptr*/ Class::has_alias && is_alias<Class>(ptr));
v_h.value_ptr() = ptr;
v_h.type->init_instance(v_h.inst, &smhldr);
}
template <typename Class,
typename D = std::default_delete<Alias<Class>>,
detail::enable_if_t<is_smart_holder<Holder<Class>>::value, int> = 0>
void construct(value_and_holder &v_h,
std::unique_ptr<Alias<Class>, D> &&unq_ptr,
bool /*need_alias*/) {
auto *ptr = unq_ptr.get();
no_nullptr(ptr);
auto smhldr
= init_smart_holder_from_unique_ptr(std::move(unq_ptr), /*void_cast_raw_ptr*/ true);
v_h.value_ptr() = ptr;
v_h.type->init_instance(v_h.inst, &smhldr);
}
template <typename PtrType, typename Class>
void construct_from_shared_ptr(value_and_holder &v_h,
std::shared_ptr<PtrType> &&shd_ptr,
bool need_alias) {
static_assert(std::is_same<PtrType, Cpp<Class>>::value
|| std::is_same<PtrType, const Cpp<Class>>::value,
"Expected (const) Cpp<Class> as shared_ptr pointee");
auto *ptr = shd_ptr.get();
no_nullptr(ptr);
if (Class::has_alias && need_alias && !is_alias<Class>(ptr)) {
throw type_error("pybind11::init(): construction failed: returned std::shared_ptr pointee "
"is not an alias instance");
}
// Cast to non-const if needed, consistent with internal design
auto smhldr
= smart_holder::from_shared_ptr(std::const_pointer_cast<Cpp<Class>>(std::move(shd_ptr)));
v_h.value_ptr() = const_cast<Cpp<Class> *>(ptr);
v_h.type->init_instance(v_h.inst, &smhldr);
}
template <typename Class, detail::enable_if_t<is_smart_holder<Holder<Class>>::value, int> = 0>
void construct(value_and_holder &v_h, std::shared_ptr<Cpp<Class>> &&shd_ptr, bool need_alias) {
construct_from_shared_ptr<Cpp<Class>, Class>(v_h, std::move(shd_ptr), need_alias);
}
template <typename Class, detail::enable_if_t<is_smart_holder<Holder<Class>>::value, int> = 0>
void construct(value_and_holder &v_h,
std::shared_ptr<const Cpp<Class>> &&shd_ptr,
bool need_alias) {
construct_from_shared_ptr<const Cpp<Class>, Class>(v_h, std::move(shd_ptr), need_alias);
}
template <typename Class, detail::enable_if_t<is_smart_holder<Holder<Class>>::value, int> = 0>
void construct(value_and_holder &v_h,
std::shared_ptr<Alias<Class>> &&shd_ptr,
bool /*need_alias*/) {
auto *ptr = shd_ptr.get();
no_nullptr(ptr);
auto smhldr = smart_holder::from_shared_ptr(shd_ptr);
v_h.value_ptr() = ptr;
v_h.type->init_instance(v_h.inst, &smhldr);
}
// Implementing class for py::init<...>()
template <typename... Args>
struct constructor {
template <typename Class, typename... Extra, enable_if_t<!Class::has_alias, int> = 0>
static void execute(Class &cl, const Extra &...extra) {
cl.def(
"__init__",
[](value_and_holder &v_h,
Args... args) { // NOLINT(performance-unnecessary-value-param)
v_h.value_ptr() = construct_or_initialize<Cpp<Class>>(std::forward<Args>(args)...);
},
is_new_style_constructor(),
extra...);
}
template <
typename Class,
typename... Extra,
enable_if_t<Class::has_alias && std::is_constructible<Cpp<Class>, Args...>::value, int>
= 0>
static void execute(Class &cl, const Extra &...extra) {
cl.def(
"__init__",
[](value_and_holder &v_h, Args... args) {
if (Py_TYPE(v_h.inst) == v_h.type->type) {
v_h.value_ptr()
= construct_or_initialize<Cpp<Class>>(std::forward<Args>(args)...);
} else {
v_h.value_ptr()
= construct_or_initialize<Alias<Class>>(std::forward<Args>(args)...);
}
},
is_new_style_constructor(),
extra...);
}
template <
typename Class,
typename... Extra,
enable_if_t<Class::has_alias && !std::is_constructible<Cpp<Class>, Args...>::value, int>
= 0>
static void execute(Class &cl, const Extra &...extra) {
cl.def(
"__init__",
[](value_and_holder &v_h, Args... args) {
v_h.value_ptr()
= construct_or_initialize<Alias<Class>>(std::forward<Args>(args)...);
},
is_new_style_constructor(),
extra...);
}
};
// Implementing class for py::init_alias<...>()
template <typename... Args>
struct alias_constructor {
template <
typename Class,
typename... Extra,
enable_if_t<Class::has_alias && std::is_constructible<Alias<Class>, Args...>::value, int>
= 0>
static void execute(Class &cl, const Extra &...extra) {
cl.def(
"__init__",
[](value_and_holder &v_h, Args... args) {
v_h.value_ptr()
= construct_or_initialize<Alias<Class>>(std::forward<Args>(args)...);
},
is_new_style_constructor(),
extra...);
}
};
// Implementation class for py::init(Func) and py::init(Func, AliasFunc)
template <typename CFunc,
typename AFunc = void_type (*)(),
typename = function_signature_t<CFunc>,
typename = function_signature_t<AFunc>>
struct factory;
// Specialization for py::init(Func)
template <typename Func, typename Return, typename... Args>
struct factory<Func, void_type (*)(), Return(Args...)> {
remove_reference_t<Func> class_factory;
// NOLINTNEXTLINE(google-explicit-constructor)
factory(Func &&f) : class_factory(std::forward<Func>(f)) {}
// The given class either has no alias or has no separate alias factory;
// this always constructs the class itself. If the class is registered with an alias
// type and an alias instance is needed (i.e. because the final type is a Python class
// inheriting from the C++ type) the returned value needs to either already be an alias
// instance, or the alias needs to be constructible from a `Class &&` argument.
template <typename Class, typename... Extra>
void execute(Class &cl, const Extra &...extra) && {
#if defined(PYBIND11_CPP14)
cl.def(
"__init__",
[func = std::move(class_factory)]
#else
auto &func = class_factory;
cl.def(
"__init__",
[func]
#endif
(value_and_holder &v_h, Args... args) {
construct<Class>(
v_h, func(std::forward<Args>(args)...), Py_TYPE(v_h.inst) != v_h.type->type);
},
is_new_style_constructor(),
extra...);
}
};
// Specialization for py::init(Func, AliasFunc)
template <typename CFunc,
typename AFunc,
typename CReturn,
typename... CArgs,
typename AReturn,
typename... AArgs>
struct factory<CFunc, AFunc, CReturn(CArgs...), AReturn(AArgs...)> {
static_assert(sizeof...(CArgs) == sizeof...(AArgs),
"pybind11::init(class_factory, alias_factory): class and alias factories "
"must have identical argument signatures");
static_assert(all_of<std::is_same<CArgs, AArgs>...>::value,
"pybind11::init(class_factory, alias_factory): class and alias factories "
"must have identical argument signatures");
remove_reference_t<CFunc> class_factory;
remove_reference_t<AFunc> alias_factory;
factory(CFunc &&c, AFunc &&a)
: class_factory(std::forward<CFunc>(c)), alias_factory(std::forward<AFunc>(a)) {}
// The class factory is called when the `self` type passed to `__init__` is the direct
// class (i.e. not inherited), the alias factory when `self` is a Python-side subtype.
template <typename Class, typename... Extra>
void execute(Class &cl, const Extra &...extra) && {
static_assert(Class::has_alias,
"The two-argument version of `py::init()` can "
"only be used if the class has an alias");
#if defined(PYBIND11_CPP14)
cl.def(
"__init__",
[class_func = std::move(class_factory), alias_func = std::move(alias_factory)]
#else
auto &class_func = class_factory;
auto &alias_func = alias_factory;
cl.def(
"__init__",
[class_func, alias_func]
#endif
(value_and_holder &v_h, CArgs... args) {
if (Py_TYPE(v_h.inst) == v_h.type->type) {
// If the instance type equals the registered type we don't have inheritance,
// so don't need the alias and can construct using the class function:
construct<Class>(v_h, class_func(std::forward<CArgs>(args)...), false);
} else {
construct<Class>(v_h, alias_func(std::forward<CArgs>(args)...), true);
}
},
is_new_style_constructor(),
extra...);
}
};
/// Set just the C++ state. Same as `__init__`.
template <typename Class, typename T>
void setstate(value_and_holder &v_h, T &&result, bool need_alias) {
construct<Class>(v_h, std::forward<T>(result), need_alias);
}
/// Set both the C++ and Python states
template <typename Class,
typename T,
typename O,
enable_if_t<std::is_convertible<O, handle>::value, int> = 0>
void setstate(value_and_holder &v_h, std::pair<T, O> &&result, bool need_alias) {
construct<Class>(v_h, std::move(result.first), need_alias);
auto d = handle(result.second);
if (PyDict_Check(d.ptr()) && PyDict_Size(d.ptr()) == 0) {
// Skipping setattr below, to not force use of py::dynamic_attr() for Class unnecessarily.
// See PR #2972 for details.
return;
}
// Our tests never run into an unset dict, but being careful here for now (see #5658)
auto dict = getattr((PyObject *) v_h.inst, "__dict__", none());
if (dict.is_none()) {
setattr((PyObject *) v_h.inst, "__dict__", d);
} else {
// Keep the original object dict and just update it
if (PyDict_Update(dict.ptr(), d.ptr()) < 0) {
throw error_already_set();
}
}
}
/// Implementation for py::pickle(GetState, SetState)
template <typename Get,
typename Set,
typename = function_signature_t<Get>,
typename = function_signature_t<Set>>
struct pickle_factory;
template <typename Get,
typename Set,
typename RetState,
typename Self,
typename NewInstance,
typename ArgState>
struct pickle_factory<Get, Set, RetState(Self), NewInstance(ArgState)> {
static_assert(std::is_same<intrinsic_t<RetState>, intrinsic_t<ArgState>>::value,
"The type returned by `__getstate__` must be the same "
"as the argument accepted by `__setstate__`");
remove_reference_t<Get> get;
remove_reference_t<Set> set;
pickle_factory(Get get, Set set) : get(std::forward<Get>(get)), set(std::forward<Set>(set)) {}
template <typename Class, typename... Extra>
void execute(Class &cl, const Extra &...extra) && {
cl.def("__getstate__", std::move(get), pos_only());
#if defined(PYBIND11_CPP14)
cl.def(
"__setstate__",
[func = std::move(set)]
#else
auto &func = set;
cl.def(
"__setstate__",
[func]
#endif
(value_and_holder &v_h, ArgState state) {
setstate<Class>(
v_h, func(std::forward<ArgState>(state)), Py_TYPE(v_h.inst) != v_h.type->type);
},
is_new_style_constructor(),
extra...);
}
};
PYBIND11_NAMESPACE_END(initimpl)
PYBIND11_NAMESPACE_END(detail)
PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)

View File

@@ -0,0 +1,799 @@
/*
pybind11/detail/internals.h: Internal data structure and related functions
Copyright (c) 2017 Wenzel Jakob <wenzel.jakob@epfl.ch>
All rights reserved. Use of this source code is governed by a
BSD-style license that can be found in the LICENSE file.
*/
#pragma once
#include <pybind11/conduit/pybind11_platform_abi_id.h>
#include <pybind11/gil_simple.h>
#include <pybind11/pytypes.h>
#include <pybind11/trampoline_self_life_support.h>
#include "common.h"
#include "struct_smart_holder.h"
#include <atomic>
#include <cstdint>
#include <exception>
#include <limits>
#include <mutex>
#include <thread>
/// Tracks the `internals` and `type_info` ABI version independent of the main library version.
///
/// Some portions of the code use an ABI that is conditional depending on this
/// version number. That allows ABI-breaking changes to be "pre-implemented".
/// Once the default version number is incremented, the conditional logic that
/// no longer applies can be removed. Additionally, users that need not
/// maintain ABI compatibility can increase the version number in order to take
/// advantage of any functionality/efficiency improvements that depend on the
/// newer ABI.
///
/// WARNING: If you choose to manually increase the ABI version, note that
/// pybind11 may not be tested as thoroughly with a non-default ABI version, and
/// further ABI-incompatible changes may be made before the ABI is officially
/// changed to the new version.
#ifndef PYBIND11_INTERNALS_VERSION
# define PYBIND11_INTERNALS_VERSION 11
#endif
#if PYBIND11_INTERNALS_VERSION < 11
# error "PYBIND11_INTERNALS_VERSION 11 is the minimum for all platforms for pybind11v3."
#endif
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
using ExceptionTranslator = void (*)(std::exception_ptr);
// The old Python Thread Local Storage (TLS) API is deprecated in Python 3.7 in favor of the new
// Thread Specific Storage (TSS) API.
// Avoid unnecessary allocation of `Py_tss_t`, since we cannot use
// `Py_LIMITED_API` anyway.
#define PYBIND11_TLS_KEY_REF Py_tss_t &
#if defined(__clang__)
# define PYBIND11_TLS_KEY_INIT(var) \
_Pragma("clang diagnostic push") /**/ \
_Pragma("clang diagnostic ignored \"-Wmissing-field-initializers\"") /**/ \
Py_tss_t var \
= Py_tss_NEEDS_INIT; \
_Pragma("clang diagnostic pop")
#elif defined(__GNUC__) && !defined(__INTEL_COMPILER)
# define PYBIND11_TLS_KEY_INIT(var) \
_Pragma("GCC diagnostic push") /**/ \
_Pragma("GCC diagnostic ignored \"-Wmissing-field-initializers\"") /**/ \
Py_tss_t var \
= Py_tss_NEEDS_INIT; \
_Pragma("GCC diagnostic pop")
#else
# define PYBIND11_TLS_KEY_INIT(var) Py_tss_t var = Py_tss_NEEDS_INIT;
#endif
#define PYBIND11_TLS_KEY_CREATE(var) (PyThread_tss_create(&(var)) == 0)
#define PYBIND11_TLS_GET_VALUE(key) PyThread_tss_get(&(key))
#define PYBIND11_TLS_REPLACE_VALUE(key, value) PyThread_tss_set(&(key), (value))
#define PYBIND11_TLS_DELETE_VALUE(key) PyThread_tss_set(&(key), nullptr)
#define PYBIND11_TLS_FREE(key) PyThread_tss_delete(&(key))
/// A smart-pointer-like wrapper around a thread-specific value. get/set of the pointer applies to
/// the current thread only.
template <typename T>
class thread_specific_storage {
public:
thread_specific_storage() {
// NOLINTNEXTLINE(bugprone-assignment-in-if-condition)
if (!PYBIND11_TLS_KEY_CREATE(key_)) {
pybind11_fail(
"thread_specific_storage constructor: could not initialize the TSS key!");
}
}
~thread_specific_storage() {
// This destructor is often called *after* Py_Finalize(). That *SHOULD BE* fine on most
// platforms. The following details what happens when PyThread_tss_free is called in
// CPython. PYBIND11_TLS_FREE is PyThread_tss_free on python 3.7+. On older python, it does
// nothing. PyThread_tss_free calls PyThread_tss_delete and PyMem_RawFree.
// PyThread_tss_delete just calls TlsFree (on Windows) or pthread_key_delete (on *NIX).
// Neither of those have anything to do with CPython internals. PyMem_RawFree *requires*
// that the `key` be allocated with the CPython allocator (as it is by
// PyThread_tss_create).
// However, in GraalPy (as of v24.2 or older), TSS is implemented by Java and this call
// requires a living Python interpreter.
#ifdef GRAALVM_PYTHON
if (!Py_IsInitialized() || _Py_IsFinalizing()) {
return;
}
#endif
PYBIND11_TLS_FREE(key_);
}
thread_specific_storage(thread_specific_storage const &) = delete;
thread_specific_storage(thread_specific_storage &&) = delete;
thread_specific_storage &operator=(thread_specific_storage const &) = delete;
thread_specific_storage &operator=(thread_specific_storage &&) = delete;
T *get() const { return reinterpret_cast<T *>(PYBIND11_TLS_GET_VALUE(key_)); }
T &operator*() const { return *get(); }
explicit operator T *() const { return get(); }
explicit operator bool() const { return get() != nullptr; }
void set(T *val) { PYBIND11_TLS_REPLACE_VALUE(key_, reinterpret_cast<void *>(val)); }
void reset(T *p = nullptr) { set(p); }
thread_specific_storage &operator=(T *pval) {
set(pval);
return *this;
}
private:
PYBIND11_TLS_KEY_INIT(mutable key_)
};
PYBIND11_NAMESPACE_BEGIN(detail)
// This does NOT actually exist as a module.
#define PYBIND11_DUMMY_MODULE_NAME "pybind11_builtins"
// Forward declarations
inline PyTypeObject *make_static_property_type();
inline PyTypeObject *make_default_metaclass();
inline PyObject *make_object_base_type(PyTypeObject *metaclass);
inline void translate_exception(std::exception_ptr p);
// Python loads modules by default with dlopen with the RTLD_LOCAL flag; under libc++ and possibly
// other STLs, this means `typeid(A)` from one module won't equal `typeid(A)` from another module
// even when `A` is the same, non-hidden-visibility type (e.g. from a common include). Under
// libstdc++, this doesn't happen: equality and the type_index hash are based on the type name,
// which works. If not under a known-good stl, provide our own name-based hash and equality
// functions that use the type name.
#if !defined(_LIBCPP_VERSION)
inline bool same_type(const std::type_info &lhs, const std::type_info &rhs) { return lhs == rhs; }
using type_hash = std::hash<std::type_index>;
using type_equal_to = std::equal_to<std::type_index>;
#else
inline bool same_type(const std::type_info &lhs, const std::type_info &rhs) {
return lhs.name() == rhs.name() || std::strcmp(lhs.name(), rhs.name()) == 0;
}
struct type_hash {
size_t operator()(const std::type_index &t) const {
size_t hash = 5381;
const char *ptr = t.name();
while (auto c = static_cast<unsigned char>(*ptr++)) {
hash = (hash * 33) ^ c;
}
return hash;
}
};
struct type_equal_to {
bool operator()(const std::type_index &lhs, const std::type_index &rhs) const {
return lhs.name() == rhs.name() || std::strcmp(lhs.name(), rhs.name()) == 0;
}
};
#endif
template <typename value_type>
using type_map = std::unordered_map<std::type_index, value_type, type_hash, type_equal_to>;
struct override_hash {
inline size_t operator()(const std::pair<const PyObject *, const char *> &v) const {
size_t value = std::hash<const void *>()(v.first);
value ^= std::hash<const void *>()(v.second) + 0x9e3779b9 + (value << 6) + (value >> 2);
return value;
}
};
using instance_map = std::unordered_multimap<const void *, instance *>;
#ifdef Py_GIL_DISABLED
// Wrapper around PyMutex to provide BasicLockable semantics
class pymutex {
PyMutex mutex;
public:
pymutex() : mutex({}) {}
void lock() { PyMutex_Lock(&mutex); }
void unlock() { PyMutex_Unlock(&mutex); }
};
// Instance map shards are used to reduce mutex contention in free-threaded Python.
struct instance_map_shard {
instance_map registered_instances;
pymutex mutex;
// alignas(64) would be better, but causes compile errors in macOS before 10.14 (see #5200)
char padding[64 - (sizeof(instance_map) + sizeof(pymutex)) % 64];
};
static_assert(sizeof(instance_map_shard) % 64 == 0,
"instance_map_shard size is not a multiple of 64 bytes");
inline uint64_t round_up_to_next_pow2(uint64_t x) {
// Round-up to the next power of two.
// See https://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2
x--;
x |= (x >> 1);
x |= (x >> 2);
x |= (x >> 4);
x |= (x >> 8);
x |= (x >> 16);
x |= (x >> 32);
x++;
return x;
}
#endif
class loader_life_support;
/// Internal data structure used to track registered instances and types.
/// Whenever binary incompatible changes are made to this structure,
/// `PYBIND11_INTERNALS_VERSION` must be incremented.
struct internals {
#ifdef Py_GIL_DISABLED
pymutex mutex;
pymutex exception_translator_mutex;
#endif
// std::type_index -> pybind11's type information
type_map<type_info *> registered_types_cpp;
// PyTypeObject* -> base type_info(s)
std::unordered_map<PyTypeObject *, std::vector<type_info *>> registered_types_py;
#ifdef Py_GIL_DISABLED
std::unique_ptr<instance_map_shard[]> instance_shards; // void * -> instance*
size_t instance_shards_mask = 0;
#else
instance_map registered_instances; // void * -> instance*
#endif
std::unordered_set<std::pair<const PyObject *, const char *>, override_hash>
inactive_override_cache;
type_map<std::vector<bool (*)(PyObject *, void *&)>> direct_conversions;
std::unordered_map<const PyObject *, std::vector<PyObject *>> patients;
std::forward_list<ExceptionTranslator> registered_exception_translators;
std::unordered_map<std::string, void *> shared_data; // Custom data to be shared across
// extensions
std::forward_list<std::string> static_strings; // Stores the std::strings backing
// detail::c_str()
PyTypeObject *static_property_type = nullptr;
PyTypeObject *default_metaclass = nullptr;
PyObject *instance_base = nullptr;
// Unused if PYBIND11_SIMPLE_GIL_MANAGEMENT is defined:
thread_specific_storage<PyThreadState> tstate;
thread_specific_storage<loader_life_support> loader_life_support_tls;
// Unused if PYBIND11_SIMPLE_GIL_MANAGEMENT is defined:
PyInterpreterState *istate = nullptr;
type_map<PyObject *> native_enum_type_map;
internals()
: static_property_type(make_static_property_type()),
default_metaclass(make_default_metaclass()) {
PyThreadState *cur_tstate = PyThreadState_Get();
tstate = cur_tstate;
istate = cur_tstate->interp;
registered_exception_translators.push_front(&translate_exception);
#ifdef Py_GIL_DISABLED
// Scale proportional to the number of cores. 2x is a heuristic to reduce contention.
// Make sure the number isn't unreasonable by limiting it to 16 bits (65K)
auto num_shards = static_cast<std::uint16_t>(
std::min<std::size_t>(round_up_to_next_pow2(2 * std::thread::hardware_concurrency()),
std::numeric_limits<std::uint16_t>::max()));
if (num_shards == 0) {
num_shards = 1;
}
instance_shards.reset(new instance_map_shard[num_shards]);
instance_shards_mask = num_shards - 1;
#endif
}
internals(const internals &other) = delete;
internals(internals &&other) = delete;
internals &operator=(const internals &other) = delete;
internals &operator=(internals &&other) = delete;
~internals() = default;
};
// the internals struct (above) is shared between all the modules. local_internals are only
// for a single module. Any changes made to internals may require an update to
// PYBIND11_INTERNALS_VERSION, breaking backwards compatibility. local_internals is, by design,
// restricted to a single module. Whether a module has local internals or not should not
// impact any other modules, because the only things accessing the local internals is the
// module that contains them.
struct local_internals {
type_map<type_info *> registered_types_cpp;
std::forward_list<ExceptionTranslator> registered_exception_translators;
PyTypeObject *function_record_py_type = nullptr;
};
enum class holder_enum_t : uint8_t {
undefined,
std_unique_ptr, // Default, lacking interop with std::shared_ptr.
std_shared_ptr, // Lacking interop with std::unique_ptr.
smart_holder, // Full std::unique_ptr / std::shared_ptr interop.
custom_holder,
};
/// Additional type information which does not fit into the PyTypeObject.
/// Changes to this struct also require bumping `PYBIND11_INTERNALS_VERSION`.
struct type_info {
PyTypeObject *type;
const std::type_info *cpptype;
size_t type_size, type_align, holder_size_in_ptrs;
void *(*operator_new)(size_t);
void (*init_instance)(instance *, const void *);
void (*dealloc)(value_and_holder &v_h);
// Cross-DSO-safe function pointers, to sidestep cross-DSO RTTI issues
// on platforms like macOS (see PR #5728 for details):
memory::get_guarded_delete_fn get_memory_guarded_delete = memory::get_guarded_delete;
get_trampoline_self_life_support_fn get_trampoline_self_life_support = nullptr;
std::vector<PyObject *(*) (PyObject *, PyTypeObject *)> implicit_conversions;
std::vector<std::pair<const std::type_info *, void *(*) (void *)>> implicit_casts;
std::vector<bool (*)(PyObject *, void *&)> *direct_conversions;
buffer_info *(*get_buffer)(PyObject *, void *) = nullptr;
void *get_buffer_data = nullptr;
void *(*module_local_load)(PyObject *, const type_info *) = nullptr;
holder_enum_t holder_enum_v = holder_enum_t::undefined;
/* A simple type never occurs as a (direct or indirect) parent
* of a class that makes use of multiple inheritance.
* A type can be simple even if it has non-simple ancestors as long as it has no descendants.
*/
bool simple_type : 1;
/* True if there is no multiple inheritance in this type's inheritance tree */
bool simple_ancestors : 1;
/* true if this is a type registered with py::module_local */
bool module_local : 1;
};
#define PYBIND11_INTERNALS_ID \
"__pybind11_internals_v" PYBIND11_TOSTRING(PYBIND11_INTERNALS_VERSION) \
PYBIND11_COMPILER_TYPE_LEADING_UNDERSCORE PYBIND11_PLATFORM_ABI_ID "__"
#define PYBIND11_MODULE_LOCAL_ID \
"__pybind11_module_local_v" PYBIND11_TOSTRING(PYBIND11_INTERNALS_VERSION) \
PYBIND11_COMPILER_TYPE_LEADING_UNDERSCORE PYBIND11_PLATFORM_ABI_ID "__"
inline PyThreadState *get_thread_state_unchecked() {
#if defined(PYPY_VERSION) || defined(GRAALVM_PYTHON)
return PyThreadState_GET();
#elif PY_VERSION_HEX < 0x030D0000
return _PyThreadState_UncheckedGet();
#else
return PyThreadState_GetUnchecked();
#endif
}
/// We use this counter to figure out if there are or have been multiple subinterpreters active at
/// any point. This must never decrease while any interpreter may be running in any thread!
inline std::atomic<int> &get_num_interpreters_seen() {
static std::atomic<int> counter(0);
return counter;
}
template <class T,
enable_if_t<std::is_same<std::nested_exception, remove_cvref_t<T>>::value, int> = 0>
bool handle_nested_exception(const T &exc, const std::exception_ptr &p) {
std::exception_ptr nested = exc.nested_ptr();
if (nested != nullptr && nested != p) {
translate_exception(nested);
return true;
}
return false;
}
template <class T,
enable_if_t<!std::is_same<std::nested_exception, remove_cvref_t<T>>::value, int> = 0>
bool handle_nested_exception(const T &exc, const std::exception_ptr &p) {
if (const auto *nep = dynamic_cast<const std::nested_exception *>(std::addressof(exc))) {
return handle_nested_exception(*nep, p);
}
return false;
}
inline bool raise_err(PyObject *exc_type, const char *msg) {
if (PyErr_Occurred()) {
raise_from(exc_type, msg);
return true;
}
set_error(exc_type, msg);
return false;
}
inline void translate_exception(std::exception_ptr p) {
if (!p) {
return;
}
try {
std::rethrow_exception(p);
} catch (error_already_set &e) {
handle_nested_exception(e, p);
e.restore();
return;
} catch (const builtin_exception &e) {
// Could not use template since it's an abstract class.
if (const auto *nep = dynamic_cast<const std::nested_exception *>(std::addressof(e))) {
handle_nested_exception(*nep, p);
}
e.set_error();
return;
} catch (const std::bad_alloc &e) {
handle_nested_exception(e, p);
raise_err(PyExc_MemoryError, e.what());
return;
} catch (const std::domain_error &e) {
handle_nested_exception(e, p);
raise_err(PyExc_ValueError, e.what());
return;
} catch (const std::invalid_argument &e) {
handle_nested_exception(e, p);
raise_err(PyExc_ValueError, e.what());
return;
} catch (const std::length_error &e) {
handle_nested_exception(e, p);
raise_err(PyExc_ValueError, e.what());
return;
} catch (const std::out_of_range &e) {
handle_nested_exception(e, p);
raise_err(PyExc_IndexError, e.what());
return;
} catch (const std::range_error &e) {
handle_nested_exception(e, p);
raise_err(PyExc_ValueError, e.what());
return;
} catch (const std::overflow_error &e) {
handle_nested_exception(e, p);
raise_err(PyExc_OverflowError, e.what());
return;
} catch (const std::exception &e) {
handle_nested_exception(e, p);
raise_err(PyExc_RuntimeError, e.what());
return;
} catch (const std::nested_exception &e) {
handle_nested_exception(e, p);
raise_err(PyExc_RuntimeError, "Caught an unknown nested exception!");
return;
} catch (...) {
raise_err(PyExc_RuntimeError, "Caught an unknown exception!");
return;
}
}
#if !defined(__GLIBCXX__)
inline void translate_local_exception(std::exception_ptr p) {
try {
if (p) {
std::rethrow_exception(p);
}
} catch (error_already_set &e) {
e.restore();
return;
} catch (const builtin_exception &e) {
e.set_error();
return;
}
}
#endif
inline object get_python_state_dict() {
object state_dict;
#if defined(PYPY_VERSION) || defined(GRAALVM_PYTHON)
state_dict = reinterpret_borrow<object>(PyEval_GetBuiltins());
#else
# if PY_VERSION_HEX < 0x03090000
PyInterpreterState *istate = _PyInterpreterState_Get();
# else
PyInterpreterState *istate = PyInterpreterState_Get();
# endif
if (istate) {
state_dict = reinterpret_borrow<object>(PyInterpreterState_GetDict(istate));
}
#endif
if (!state_dict) {
raise_from(PyExc_SystemError, "pybind11::detail::get_python_state_dict() FAILED");
throw error_already_set();
}
return state_dict;
}
template <typename InternalsType>
class internals_pp_manager {
public:
using on_fetch_function = void(InternalsType *);
internals_pp_manager(char const *id, on_fetch_function *on_fetch)
: holder_id_(id), on_fetch_(on_fetch) {}
/// Get the current pointer-to-pointer, allocating it if it does not already exist. May
/// acquire the GIL. Will never return nullptr.
std::unique_ptr<InternalsType> *get_pp() {
#ifdef PYBIND11_HAS_SUBINTERPRETER_SUPPORT
if (get_num_interpreters_seen() > 1) {
// Whenever the interpreter changes on the current thread we need to invalidate the
// internals_pp so that it can be pulled from the interpreter's state dict. That is
// slow, so we use the current PyThreadState to check if it is necessary.
auto *tstate = get_thread_state_unchecked();
if (!tstate || tstate->interp != last_istate_.get()) {
gil_scoped_acquire_simple gil;
if (!tstate) {
tstate = get_thread_state_unchecked();
}
last_istate_ = tstate->interp;
internals_tls_p_ = get_or_create_pp_in_state_dict();
}
return internals_tls_p_.get();
}
#endif
if (!internals_singleton_pp_) {
gil_scoped_acquire_simple gil;
internals_singleton_pp_ = get_or_create_pp_in_state_dict();
}
return internals_singleton_pp_;
}
/// Drop all the references we're currently holding.
void unref() {
#ifdef PYBIND11_HAS_SUBINTERPRETER_SUPPORT
if (get_num_interpreters_seen() > 1) {
last_istate_.reset();
internals_tls_p_.reset();
return;
}
#endif
internals_singleton_pp_ = nullptr;
}
void destroy() {
#ifdef PYBIND11_HAS_SUBINTERPRETER_SUPPORT
if (get_num_interpreters_seen() > 1) {
auto *tstate = get_thread_state_unchecked();
// this could be called without an active interpreter, just use what was cached
if (!tstate || tstate->interp == last_istate_.get()) {
auto tpp = internals_tls_p_.get();
if (tpp) {
delete tpp;
}
}
unref();
return;
}
#endif
delete internals_singleton_pp_;
unref();
}
private:
std::unique_ptr<InternalsType> *get_or_create_pp_in_state_dict() {
error_scope err_scope;
dict state_dict = get_python_state_dict();
auto internals_obj
= reinterpret_steal<object>(dict_getitemstringref(state_dict.ptr(), holder_id_));
std::unique_ptr<InternalsType> *pp = nullptr;
if (internals_obj) {
void *raw_ptr = PyCapsule_GetPointer(internals_obj.ptr(), /*name=*/nullptr);
if (!raw_ptr) {
raise_from(PyExc_SystemError,
"pybind11::detail::internals_pp_manager::get_pp_from_dict() FAILED");
throw error_already_set();
}
pp = reinterpret_cast<std::unique_ptr<InternalsType> *>(raw_ptr);
if (on_fetch_ && pp) {
on_fetch_(pp->get());
}
} else {
pp = new std::unique_ptr<InternalsType>;
// NOLINTNEXTLINE(bugprone-casting-through-void)
state_dict[holder_id_] = capsule(reinterpret_cast<void *>(pp));
}
return pp;
}
char const *holder_id_ = nullptr;
on_fetch_function *on_fetch_ = nullptr;
#ifdef PYBIND11_HAS_SUBINTERPRETER_SUPPORT
thread_specific_storage<PyInterpreterState> last_istate_;
thread_specific_storage<std::unique_ptr<InternalsType>> internals_tls_p_;
#endif
std::unique_ptr<InternalsType> *internals_singleton_pp_;
};
// If We loaded the internals through `state_dict`, our `error_already_set`
// and `builtin_exception` may be different local classes than the ones set up in the
// initial exception translator, below, so add another for our local exception classes.
//
// libstdc++ doesn't require this (types there are identified only by name)
// libc++ with CPython doesn't require this (types are explicitly exported)
// libc++ with PyPy still need it, awaiting further investigation
#if !defined(__GLIBCXX__)
inline void check_internals_local_exception_translator(internals *internals_ptr) {
if (internals_ptr) {
for (auto et : internals_ptr->registered_exception_translators) {
if (et == &translate_local_exception) {
return;
}
}
internals_ptr->registered_exception_translators.push_front(&translate_local_exception);
}
}
#endif
inline internals_pp_manager<internals> &get_internals_pp_manager() {
#if defined(__GLIBCXX__)
# define ON_FETCH_FN nullptr
#else
# define ON_FETCH_FN &check_internals_local_exception_translator
#endif
static internals_pp_manager<internals> internals_pp_manager(PYBIND11_INTERNALS_ID,
ON_FETCH_FN);
#undef ON_FETCH_FN
return internals_pp_manager;
}
/// Return a reference to the current `internals` data
PYBIND11_NOINLINE internals &get_internals() {
auto &ppmgr = get_internals_pp_manager();
auto &internals_ptr = *ppmgr.get_pp();
if (!internals_ptr) {
// Slow path, something needs fetched from the state dict or created
gil_scoped_acquire_simple gil;
error_scope err_scope;
internals_ptr.reset(new internals());
if (!internals_ptr->instance_base) {
// This calls get_internals, so cannot be called from within the internals constructor
// called above because internals_ptr must be set before get_internals is called again
internals_ptr->instance_base = make_object_base_type(internals_ptr->default_metaclass);
}
}
return *internals_ptr;
}
inline internals_pp_manager<local_internals> &get_local_internals_pp_manager() {
// Use the address of this static itself as part of the key, so that the value is uniquely tied
// to where the module is loaded in memory
static const std::string this_module_idstr
= PYBIND11_MODULE_LOCAL_ID
+ std::to_string(reinterpret_cast<uintptr_t>(&this_module_idstr));
static internals_pp_manager<local_internals> local_internals_pp_manager(
this_module_idstr.c_str(), nullptr);
return local_internals_pp_manager;
}
/// Works like `get_internals`, but for things which are locally registered.
inline local_internals &get_local_internals() {
auto &ppmgr = get_local_internals_pp_manager();
auto &internals_ptr = *ppmgr.get_pp();
if (!internals_ptr) {
internals_ptr.reset(new local_internals());
}
return *internals_ptr;
}
#ifdef Py_GIL_DISABLED
# define PYBIND11_LOCK_INTERNALS(internals) std::unique_lock<pymutex> lock((internals).mutex)
#else
# define PYBIND11_LOCK_INTERNALS(internals)
#endif
template <typename F>
inline auto with_internals(const F &cb) -> decltype(cb(get_internals())) {
auto &internals = get_internals();
PYBIND11_LOCK_INTERNALS(internals);
return cb(internals);
}
template <typename F>
inline auto with_exception_translators(const F &cb)
-> decltype(cb(get_internals().registered_exception_translators,
get_local_internals().registered_exception_translators)) {
auto &internals = get_internals();
#ifdef Py_GIL_DISABLED
std::unique_lock<pymutex> lock((internals).exception_translator_mutex);
#endif
auto &local_internals = get_local_internals();
return cb(internals.registered_exception_translators,
local_internals.registered_exception_translators);
}
inline std::uint64_t mix64(std::uint64_t z) {
// David Stafford's variant 13 of the MurmurHash3 finalizer popularized
// by the SplitMix PRNG.
// https://zimbry.blogspot.com/2011/09/better-bit-mixing-improving-on.html
z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9;
z = (z ^ (z >> 27)) * 0x94d049bb133111eb;
return z ^ (z >> 31);
}
template <typename F>
inline auto with_instance_map(const void *ptr, const F &cb)
-> decltype(cb(std::declval<instance_map &>())) {
auto &internals = get_internals();
#ifdef Py_GIL_DISABLED
// Hash address to compute shard, but ignore low bits. We'd like allocations
// from the same thread/core to map to the same shard and allocations from
// other threads/cores to map to other shards. Using the high bits is a good
// heuristic because memory allocators often have a per-thread
// arena/superblock/segment from which smaller allocations are served.
auto addr = reinterpret_cast<std::uintptr_t>(ptr);
auto hash = mix64(static_cast<std::uint64_t>(addr >> 20));
auto idx = static_cast<size_t>(hash & internals.instance_shards_mask);
auto &shard = internals.instance_shards[idx];
std::unique_lock<pymutex> lock(shard.mutex);
return cb(shard.registered_instances);
#else
(void) ptr;
return cb(internals.registered_instances);
#endif
}
// Returns the number of registered instances for testing purposes. The result may not be
// consistent if other threads are registering or unregistering instances concurrently.
inline size_t num_registered_instances() {
auto &internals = get_internals();
#ifdef Py_GIL_DISABLED
size_t count = 0;
for (size_t i = 0; i <= internals.instance_shards_mask; ++i) {
auto &shard = internals.instance_shards[i];
std::unique_lock<pymutex> lock(shard.mutex);
count += shard.registered_instances.size();
}
return count;
#else
return internals.registered_instances.size();
#endif
}
/// Constructs a std::string with the given arguments, stores it in `internals`, and returns its
/// `c_str()`. Such strings objects have a long storage duration -- the internal strings are only
/// cleared when the program exits or after interpreter shutdown (when embedding), and so are
/// suitable for c-style strings needed by Python internals (such as PyTypeObject's tp_name).
template <typename... Args>
const char *c_str(Args &&...args) {
// GCC 4.8 doesn't like parameter unpack within lambda capture, so use
// PYBIND11_LOCK_INTERNALS.
auto &internals = get_internals();
PYBIND11_LOCK_INTERNALS(internals);
auto &strings = internals.static_strings;
strings.emplace_front(std::forward<Args>(args)...);
return strings.front().c_str();
}
PYBIND11_NAMESPACE_END(detail)
/// Returns a named pointer that is shared among all extension modules (using the same
/// pybind11 version) running in the current interpreter. Names starting with underscores
/// are reserved for internal usage. Returns `nullptr` if no matching entry was found.
PYBIND11_NOINLINE void *get_shared_data(const std::string &name) {
return detail::with_internals([&](detail::internals &internals) {
auto it = internals.shared_data.find(name);
return it != internals.shared_data.end() ? it->second : nullptr;
});
}
/// Set the shared data that can be later recovered by `get_shared_data()`.
PYBIND11_NOINLINE void *set_shared_data(const std::string &name, void *data) {
return detail::with_internals([&](detail::internals &internals) {
internals.shared_data[name] = data;
return data;
});
}
/// Returns a typed reference to a shared data entry (by using `get_shared_data()`) if
/// such entry exists. Otherwise, a new object of default-constructible type `T` is
/// added to the shared data under the given name and a reference to it is returned.
template <typename T>
T &get_or_create_shared_data(const std::string &name) {
return *detail::with_internals([&](detail::internals &internals) {
auto it = internals.shared_data.find(name);
T *ptr = (T *) (it != internals.shared_data.end() ? it->second : nullptr);
if (!ptr) {
ptr = new T();
internals.shared_data[name] = ptr;
}
return ptr;
});
}
PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)

View File

@@ -0,0 +1,209 @@
// Copyright (c) 2022-2025 The pybind Community.
// All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
#pragma once
#include "../pytypes.h"
#include "common.h"
#include "internals.h"
#include <cassert>
#include <sstream>
#include <string>
#include <typeindex>
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
PYBIND11_NAMESPACE_BEGIN(detail)
// This is a separate function only to enable easy unit testing.
inline std::string
native_enum_missing_finalize_error_message(const std::string &enum_name_encoded) {
return "pybind11::native_enum<...>(\"" + enum_name_encoded + "\", ...): MISSING .finalize()";
}
class native_enum_data {
public:
native_enum_data(const object &parent_scope,
const char *enum_name,
const char *native_type_name,
const char *class_doc,
const std::type_index &enum_type_index)
: enum_name_encoded{enum_name}, native_type_name_encoded{native_type_name},
enum_type_index{enum_type_index}, parent_scope(parent_scope), enum_name{enum_name},
native_type_name{native_type_name}, class_doc(class_doc), export_values_flag{false},
finalize_needed{false} {}
void finalize();
native_enum_data(const native_enum_data &) = delete;
native_enum_data &operator=(const native_enum_data &) = delete;
#if !defined(NDEBUG)
// This dtor cannot easily be unit tested because it terminates the process.
~native_enum_data() {
if (finalize_needed) {
pybind11_fail(native_enum_missing_finalize_error_message(enum_name_encoded));
}
}
#endif
protected:
void disarm_finalize_check(const char *error_context) {
if (!finalize_needed) {
pybind11_fail("pybind11::native_enum<...>(\"" + enum_name_encoded
+ "\"): " + error_context);
}
finalize_needed = false;
}
void arm_finalize_check() {
assert(!finalize_needed); // Catch redundant calls.
finalize_needed = true;
}
std::string enum_name_encoded;
std::string native_type_name_encoded;
std::type_index enum_type_index;
private:
object parent_scope;
str enum_name;
str native_type_name;
std::string class_doc;
protected:
list members;
list member_docs;
bool export_values_flag : 1; // Attention: It is best to keep the bools together.
private:
bool finalize_needed : 1;
};
inline void global_internals_native_enum_type_map_set_item(const std::type_index &enum_type_index,
PyObject *py_enum) {
with_internals(
[&](internals &internals) { internals.native_enum_type_map[enum_type_index] = py_enum; });
}
inline handle
global_internals_native_enum_type_map_get_item(const std::type_index &enum_type_index) {
return with_internals([&](internals &internals) {
auto found = internals.native_enum_type_map.find(enum_type_index);
if (found != internals.native_enum_type_map.end()) {
return handle(found->second);
}
return handle();
});
}
inline bool
global_internals_native_enum_type_map_contains(const std::type_index &enum_type_index) {
return with_internals([&](internals &internals) {
return internals.native_enum_type_map.count(enum_type_index) != 0;
});
}
inline object import_or_getattr(const std::string &fully_qualified_name,
const std::string &append_to_exception_message) {
std::istringstream stream(fully_qualified_name);
std::string part;
if (!std::getline(stream, part, '.') || part.empty()) {
std::string msg = "Invalid fully-qualified name `";
msg += fully_qualified_name;
msg += "`";
msg += append_to_exception_message;
throw value_error(msg);
}
auto curr_scope = reinterpret_steal<object>(PyImport_ImportModule(part.c_str()));
if (!curr_scope) {
std::string msg = "Failed to import top-level module `";
msg += part;
msg += "`";
msg += append_to_exception_message;
raise_from(PyExc_ImportError, msg.c_str());
throw error_already_set();
}
// Now recursively getattr or import remaining parts
std::string curr_path = part;
while (std::getline(stream, part, '.')) {
if (part.empty()) {
std::string msg = "Invalid fully-qualified name `";
msg += fully_qualified_name;
msg += "`";
msg += append_to_exception_message;
throw value_error(msg);
}
std::string next_path = curr_path;
next_path += ".";
next_path += part;
auto next_scope
= reinterpret_steal<object>(PyObject_GetAttrString(curr_scope.ptr(), part.c_str()));
if (!next_scope) {
error_fetch_and_normalize stored_getattr_error("getattr");
// Try importing the next level
next_scope = reinterpret_steal<object>(PyImport_ImportModule(next_path.c_str()));
if (!next_scope) {
error_fetch_and_normalize stored_import_error("import");
std::string msg = "Failed to import or getattr `";
msg += part;
msg += "` from `";
msg += curr_path;
msg += "`";
msg += append_to_exception_message;
msg += "\n-------- getattr exception --------\n";
msg += stored_getattr_error.error_string();
msg += "\n-------- import exception --------\n";
msg += stored_import_error.error_string();
throw import_error(msg.c_str());
}
}
curr_scope = next_scope;
curr_path = next_path;
}
return curr_scope;
}
inline void native_enum_data::finalize() {
disarm_finalize_check("DOUBLE finalize");
if (hasattr(parent_scope, enum_name)) {
pybind11_fail("pybind11::native_enum<...>(\"" + enum_name_encoded
+ "\"): an object with that name is already defined");
}
auto py_enum_type = import_or_getattr(native_type_name, " (native_type_name)");
auto py_enum = py_enum_type(enum_name, members);
object module_name = get_module_name_if_available(parent_scope);
if (module_name) {
py_enum.attr("__module__") = module_name;
}
if (hasattr(parent_scope, "__qualname__")) {
const auto parent_qualname = parent_scope.attr("__qualname__").cast<std::string>();
py_enum.attr("__qualname__") = str(parent_qualname + "." + enum_name.cast<std::string>());
}
parent_scope.attr(enum_name) = py_enum;
if (export_values_flag) {
for (auto member : members) {
auto member_name = member[int_(0)];
if (hasattr(parent_scope, member_name)) {
pybind11_fail("pybind11::native_enum<...>(\"" + enum_name_encoded + "\").value(\""
+ member_name.cast<std::string>()
+ "\"): an object with that name is already defined");
}
parent_scope.attr(member_name) = py_enum[member_name];
}
}
if (!class_doc.empty()) {
py_enum.attr("__doc__") = class_doc.c_str();
}
for (auto doc : member_docs) {
py_enum[doc[int_(0)]].attr("__doc__") = doc[int_(1)];
}
global_internals_native_enum_type_map_set_item(enum_type_index, py_enum.release().ptr());
}
PYBIND11_NAMESPACE_END(detail)
PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)

View File

@@ -0,0 +1,82 @@
// Copyright (c) 2016-2025 The Pybind Development Team.
// All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
#pragma once
// PLEASE DO NOT ADD ANY INCLUDES HERE
// Define some generic pybind11 helper macros for warning management.
//
// Note that compiler-specific push/pop pairs are baked into the
// PYBIND11_NAMESPACE_BEGIN/PYBIND11_NAMESPACE_END pair of macros. Therefore manual
// PYBIND11_WARNING_PUSH/PYBIND11_WARNING_POP are usually only needed in `#include` sections.
//
// If you find you need to suppress a warning, please try to make the suppression as local as
// possible using these macros. Please also be sure to push/pop with the pybind11 macros. Please
// only use compiler specifics if you need to check specific versions, e.g. Apple Clang vs. vanilla
// Clang.
#if defined(_MSC_VER)
# define PYBIND11_COMPILER_MSVC
# define PYBIND11_PRAGMA(...) __pragma(__VA_ARGS__)
# define PYBIND11_WARNING_PUSH PYBIND11_PRAGMA(warning(push))
# define PYBIND11_WARNING_POP PYBIND11_PRAGMA(warning(pop))
#elif defined(__INTEL_COMPILER)
# define PYBIND11_COMPILER_INTEL
# define PYBIND11_PRAGMA(...) _Pragma(#__VA_ARGS__)
# define PYBIND11_WARNING_PUSH PYBIND11_PRAGMA(warning push)
# define PYBIND11_WARNING_POP PYBIND11_PRAGMA(warning pop)
#elif defined(__clang__)
# define PYBIND11_COMPILER_CLANG
# define PYBIND11_PRAGMA(...) _Pragma(#__VA_ARGS__)
# define PYBIND11_WARNING_PUSH PYBIND11_PRAGMA(clang diagnostic push)
# define PYBIND11_WARNING_POP PYBIND11_PRAGMA(clang diagnostic pop)
#elif defined(__GNUC__)
# define PYBIND11_COMPILER_GCC
# define PYBIND11_PRAGMA(...) _Pragma(#__VA_ARGS__)
# define PYBIND11_WARNING_PUSH PYBIND11_PRAGMA(GCC diagnostic push)
# define PYBIND11_WARNING_POP PYBIND11_PRAGMA(GCC diagnostic pop)
#endif
#ifdef PYBIND11_COMPILER_MSVC
# define PYBIND11_WARNING_DISABLE_MSVC(name) PYBIND11_PRAGMA(warning(disable : name))
#else
# define PYBIND11_WARNING_DISABLE_MSVC(name)
#endif
#ifdef PYBIND11_COMPILER_CLANG
# define PYBIND11_WARNING_DISABLE_CLANG(name) PYBIND11_PRAGMA(clang diagnostic ignored name)
#else
# define PYBIND11_WARNING_DISABLE_CLANG(name)
#endif
#ifdef PYBIND11_COMPILER_GCC
# define PYBIND11_WARNING_DISABLE_GCC(name) PYBIND11_PRAGMA(GCC diagnostic ignored name)
#else
# define PYBIND11_WARNING_DISABLE_GCC(name)
#endif
#ifdef PYBIND11_COMPILER_INTEL
# define PYBIND11_WARNING_DISABLE_INTEL(name) PYBIND11_PRAGMA(warning disable name)
#else
# define PYBIND11_WARNING_DISABLE_INTEL(name)
#endif
#define PYBIND11_NAMESPACE_BEGIN(name) \
namespace name { \
PYBIND11_WARNING_PUSH
#define PYBIND11_NAMESPACE_END(name) \
PYBIND11_WARNING_POP \
}
// Robust support for some features and loading modules compiled against different pybind versions
// requires forcing hidden visibility on pybind code, so we enforce this by setting the attribute
// on the main `pybind11` namespace.
#if !defined(PYBIND11_NAMESPACE)
# if defined(__GNUG__) && !defined(_WIN32)
# define PYBIND11_NAMESPACE pybind11 __attribute__((visibility("hidden")))
# else
# define PYBIND11_NAMESPACE pybind11
# endif
#endif

View File

@@ -0,0 +1,378 @@
// Copyright (c) 2020-2024 The Pybind Development Team.
// All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
/* Proof-of-Concept for smart pointer interoperability.
High-level aspects:
* Support all `unique_ptr`, `shared_ptr` interops that are feasible.
* Cleanly and clearly report all interops that are infeasible.
* Meant to fit into a `PyObject`, as a holder for C++ objects.
* Support a system design that makes it impossible to trigger
C++ Undefined Behavior, especially from Python.
* Support a system design with clean runtime inheritance casting. From this
it follows that the `smart_holder` needs to be type-erased (`void*`).
* Handling of RTTI for the type-erased held pointer is NOT implemented here.
It is the responsibility of the caller to ensure that `static_cast<T *>`
is well-formed when calling `as_*` member functions. Inheritance casting
needs to be handled in a different layer (similar to the code organization
in boost/python/object/inheritance.hpp).
Details:
* The "root holder" chosen here is a `shared_ptr<void>` (named `vptr` in this
implementation). This choice is practically inevitable because `shared_ptr`
has only very limited support for inspecting and accessing its deleter.
* If created from a raw pointer, or a `unique_ptr` without a custom deleter,
`vptr` always uses a custom deleter, to support `unique_ptr`-like disowning.
The custom deleters could be extended to included life-time management for
external objects (e.g. `PyObject`).
* If created from an external `shared_ptr`, or a `unique_ptr` with a custom
deleter, including life-time management for external objects is infeasible.
* By choice, the smart_holder is movable but not copyable, to keep the design
simple, and to guard against accidental copying overhead.
* The `void_cast_raw_ptr` option is needed to make the `smart_holder` `vptr`
member invisible to the `shared_from_this` mechanism, in case the lifetime
of a `PyObject` is tied to the pointee.
*/
#pragma once
#include "pybind11_namespace_macros.h"
#include <cstring>
#include <functional>
#include <memory>
#include <stdexcept>
#include <string>
#include <type_traits>
#include <typeinfo>
#include <utility>
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
PYBIND11_NAMESPACE_BEGIN(memory)
// Default fallback.
static constexpr bool type_has_shared_from_this(...) { return false; }
// This overload uses SFINAE to skip enable_shared_from_this checks when the
// base is inaccessible (e.g. private inheritance).
template <typename T>
static auto type_has_shared_from_this(const T *ptr)
-> decltype(static_cast<const std::enable_shared_from_this<T> *>(ptr), true) {
return true;
}
// Inaccessible base → substitution failure → fallback overload selected
template <typename T>
static constexpr bool type_has_shared_from_this(const void *) {
return false;
}
struct guarded_delete {
// NOTE: PYBIND11_INTERNALS_VERSION needs to be bumped if changes are made to this struct.
std::weak_ptr<void> released_ptr; // Trick to keep the smart_holder memory footprint small.
std::function<void(void *)> del_fun; // Rare case.
void (*del_ptr)(void *); // Common case.
bool use_del_fun;
bool armed_flag;
guarded_delete(std::function<void(void *)> &&del_fun, bool armed_flag)
: del_fun{std::move(del_fun)}, del_ptr{nullptr}, use_del_fun{true},
armed_flag{armed_flag} {}
guarded_delete(void (*del_ptr)(void *), bool armed_flag)
: del_ptr{del_ptr}, use_del_fun{false}, armed_flag{armed_flag} {}
void operator()(void *raw_ptr) const {
if (armed_flag) {
if (use_del_fun) {
del_fun(raw_ptr);
} else {
del_ptr(raw_ptr);
}
}
}
};
inline guarded_delete *get_guarded_delete(const std::shared_ptr<void> &ptr) {
return std::get_deleter<guarded_delete>(ptr);
}
using get_guarded_delete_fn = guarded_delete *(*) (const std::shared_ptr<void> &);
template <typename T, typename std::enable_if<std::is_destructible<T>::value, int>::type = 0>
inline void std_default_delete_if_destructible(void *raw_ptr) {
std::default_delete<T>{}(static_cast<T *>(raw_ptr));
}
template <typename T, typename std::enable_if<!std::is_destructible<T>::value, int>::type = 0>
inline void std_default_delete_if_destructible(void *) {
// This noop operator is needed to avoid a compilation error (for `delete raw_ptr;`), but
// throwing an exception from a destructor will std::terminate the process. Therefore the
// runtime check for lifetime-management correctness is implemented elsewhere (in
// ensure_pointee_is_destructible()).
}
template <typename T>
guarded_delete make_guarded_std_default_delete(bool armed_flag) {
return guarded_delete(std_default_delete_if_destructible<T>, armed_flag);
}
template <typename T, typename D>
struct custom_deleter {
// NOTE: PYBIND11_INTERNALS_VERSION needs to be bumped if changes are made to this struct.
D deleter;
explicit custom_deleter(D &&deleter) : deleter{std::forward<D>(deleter)} {}
void operator()(void *raw_ptr) { deleter(static_cast<T *>(raw_ptr)); }
};
template <typename T, typename D>
guarded_delete make_guarded_custom_deleter(D &&uqp_del, bool armed_flag) {
return guarded_delete(
std::function<void(void *)>(custom_deleter<T, D>(std::forward<D>(uqp_del))), armed_flag);
}
template <typename T, typename D>
constexpr bool uqp_del_is_std_default_delete() {
return std::is_same<D, std::default_delete<T>>::value
|| std::is_same<D, std::default_delete<T const>>::value;
}
inline bool type_info_equal_across_dso_boundaries(const std::type_info &a,
const std::type_info &b) {
// RTTI pointer comparison may fail across DSOs (e.g., macOS libc++).
// Fallback to name comparison, which is generally safe and ABI-stable enough for our use.
return a == b || std::strcmp(a.name(), b.name()) == 0;
}
struct smart_holder {
// NOTE: PYBIND11_INTERNALS_VERSION needs to be bumped if changes are made to this struct.
const std::type_info *rtti_uqp_del = nullptr;
std::shared_ptr<void> vptr;
bool vptr_is_using_noop_deleter : 1;
bool vptr_is_using_std_default_delete : 1;
bool vptr_is_external_shared_ptr : 1;
bool is_populated : 1;
bool is_disowned : 1;
// Design choice: smart_holder is movable but not copyable.
smart_holder(smart_holder &&) = default;
smart_holder(const smart_holder &) = delete;
smart_holder &operator=(smart_holder &&) = delete;
smart_holder &operator=(const smart_holder &) = delete;
smart_holder()
: vptr_is_using_noop_deleter{false}, vptr_is_using_std_default_delete{false},
vptr_is_external_shared_ptr{false}, is_populated{false}, is_disowned{false} {}
bool has_pointee() const { return vptr != nullptr; }
template <typename T>
static void ensure_pointee_is_destructible(const char *context) {
if (!std::is_destructible<T>::value) {
throw std::invalid_argument(std::string("Pointee is not destructible (") + context
+ ").");
}
}
void ensure_is_populated(const char *context) const {
if (!is_populated) {
throw std::runtime_error(std::string("Unpopulated holder (") + context + ").");
}
}
void ensure_is_not_disowned(const char *context) const {
if (is_disowned) {
throw std::runtime_error(std::string("Holder was disowned already (") + context
+ ").");
}
}
void ensure_vptr_is_using_std_default_delete(const char *context) const {
if (vptr_is_external_shared_ptr) {
throw std::invalid_argument(std::string("Cannot disown external shared_ptr (")
+ context + ").");
}
if (vptr_is_using_noop_deleter) {
throw std::invalid_argument(std::string("Cannot disown non-owning holder (") + context
+ ").");
}
if (!vptr_is_using_std_default_delete) {
throw std::invalid_argument(std::string("Cannot disown custom deleter (") + context
+ ").");
}
}
template <typename T, typename D>
void ensure_compatible_uqp_del(const char *context) const {
if (!rtti_uqp_del) {
if (!uqp_del_is_std_default_delete<T, D>()) {
throw std::invalid_argument(std::string("Missing unique_ptr deleter (") + context
+ ").");
}
ensure_vptr_is_using_std_default_delete(context);
return;
}
if (uqp_del_is_std_default_delete<T, D>() && vptr_is_using_std_default_delete) {
return;
}
if (!type_info_equal_across_dso_boundaries(typeid(D), *rtti_uqp_del)) {
throw std::invalid_argument(std::string("Incompatible unique_ptr deleter (") + context
+ ").");
}
}
void ensure_has_pointee(const char *context) const {
if (!has_pointee()) {
throw std::invalid_argument(std::string("Disowned holder (") + context + ").");
}
}
void ensure_use_count_1(const char *context) const {
if (vptr == nullptr) {
throw std::invalid_argument(std::string("Cannot disown nullptr (") + context + ").");
}
// In multithreaded environments accessing use_count can lead to
// race conditions, but in the context of Python it is a bug (elsewhere)
// if the Global Interpreter Lock (GIL) is not being held when this code
// is reached.
// PYBIND11:REMINDER: This may need to be protected by a mutex in free-threaded Python.
if (vptr.use_count() != 1) {
throw std::invalid_argument(std::string("Cannot disown use_count != 1 (") + context
+ ").");
}
}
void reset_vptr_deleter_armed_flag(const get_guarded_delete_fn ggd_fn, bool armed_flag) const {
auto *gd = ggd_fn(vptr);
if (gd == nullptr) {
throw std::runtime_error(
"smart_holder::reset_vptr_deleter_armed_flag() called in an invalid context.");
}
gd->armed_flag = armed_flag;
}
// Caller is responsible for precondition: ensure_compatible_uqp_del<T, D>() must succeed.
template <typename T, typename D>
std::unique_ptr<D> extract_deleter(const char *context,
const get_guarded_delete_fn ggd_fn) const {
auto *gd = ggd_fn(vptr);
if (gd && gd->use_del_fun) {
const auto &custom_deleter_ptr = gd->del_fun.template target<custom_deleter<T, D>>();
if (custom_deleter_ptr == nullptr) {
throw std::runtime_error(
std::string("smart_holder::extract_deleter() precondition failure (") + context
+ ").");
}
static_assert(std::is_copy_constructible<D>::value,
"Required for compatibility with smart_holder functionality.");
return std::unique_ptr<D>(new D(custom_deleter_ptr->deleter));
}
return nullptr;
}
static smart_holder from_raw_ptr_unowned(void *raw_ptr) {
smart_holder hld;
hld.vptr.reset(raw_ptr, [](void *) {});
hld.vptr_is_using_noop_deleter = true;
hld.is_populated = true;
return hld;
}
template <typename T>
T *as_raw_ptr_unowned() const {
return static_cast<T *>(vptr.get());
}
template <typename T>
static smart_holder from_raw_ptr_take_ownership(T *raw_ptr, bool void_cast_raw_ptr = false) {
ensure_pointee_is_destructible<T>("from_raw_ptr_take_ownership");
smart_holder hld;
auto gd = make_guarded_std_default_delete<T>(true);
if (void_cast_raw_ptr) {
hld.vptr.reset(static_cast<void *>(raw_ptr), std::move(gd));
} else {
hld.vptr.reset(raw_ptr, std::move(gd));
}
hld.vptr_is_using_std_default_delete = true;
hld.is_populated = true;
return hld;
}
// Caller is responsible for ensuring the complex preconditions
// (see `smart_holder_type_caster_support::load_helper`).
void disown(const get_guarded_delete_fn ggd_fn) {
reset_vptr_deleter_armed_flag(ggd_fn, false);
is_disowned = true;
}
// Caller is responsible for ensuring the complex preconditions
// (see `smart_holder_type_caster_support::load_helper`).
void reclaim_disowned(const get_guarded_delete_fn ggd_fn) {
reset_vptr_deleter_armed_flag(ggd_fn, true);
is_disowned = false;
}
// Caller is responsible for ensuring the complex preconditions
// (see `smart_holder_type_caster_support::load_helper`).
void release_disowned() { vptr.reset(); }
void ensure_can_release_ownership(const char *context = "ensure_can_release_ownership") const {
ensure_is_not_disowned(context);
ensure_vptr_is_using_std_default_delete(context);
ensure_use_count_1(context);
}
// Caller is responsible for ensuring the complex preconditions
// (see `smart_holder_type_caster_support::load_helper`).
void release_ownership(const get_guarded_delete_fn ggd_fn) {
reset_vptr_deleter_armed_flag(ggd_fn, false);
release_disowned();
}
template <typename T, typename D>
static smart_holder from_unique_ptr(std::unique_ptr<T, D> &&unq_ptr,
void *void_ptr = nullptr) {
smart_holder hld;
hld.rtti_uqp_del = &typeid(D);
hld.vptr_is_using_std_default_delete = uqp_del_is_std_default_delete<T, D>();
guarded_delete gd{nullptr, false};
if (hld.vptr_is_using_std_default_delete) {
gd = make_guarded_std_default_delete<T>(true);
} else {
gd = make_guarded_custom_deleter<T, D>(std::move(unq_ptr.get_deleter()), true);
}
if (void_ptr != nullptr) {
hld.vptr.reset(void_ptr, std::move(gd));
} else {
hld.vptr.reset(unq_ptr.get(), std::move(gd));
}
(void) unq_ptr.release();
hld.is_populated = true;
return hld;
}
template <typename T>
static smart_holder from_shared_ptr(const std::shared_ptr<T> &shd_ptr) {
smart_holder hld;
hld.vptr = std::static_pointer_cast<void>(shd_ptr);
hld.vptr_is_external_shared_ptr = true;
hld.is_populated = true;
return hld;
}
template <typename T>
std::shared_ptr<T> as_shared_ptr() const {
return std::static_pointer_cast<T>(vptr);
}
};
PYBIND11_NAMESPACE_END(memory)
PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,65 @@
/*
pybind11/detail/typeid.h: Compiler-independent access to type identifiers
Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch>
All rights reserved. Use of this source code is governed by a
BSD-style license that can be found in the LICENSE file.
*/
#pragma once
#include <cstdio>
#include <cstdlib>
#if defined(__GNUG__)
# include <cxxabi.h>
#endif
#include "common.h"
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
PYBIND11_NAMESPACE_BEGIN(detail)
/// Erase all occurrences of a substring
inline void erase_all(std::string &string, const std::string &search) {
for (size_t pos = 0;;) {
pos = string.find(search, pos);
if (pos == std::string::npos) {
break;
}
string.erase(pos, search.length());
}
}
PYBIND11_NOINLINE void clean_type_id(std::string &name) {
#if defined(__GNUG__)
int status = 0;
std::unique_ptr<char, void (*)(void *)> res{
abi::__cxa_demangle(name.c_str(), nullptr, nullptr, &status), std::free};
if (status == 0) {
name = res.get();
}
#else
detail::erase_all(name, "class ");
detail::erase_all(name, "struct ");
detail::erase_all(name, "enum ");
#endif
detail::erase_all(name, "pybind11::");
}
inline std::string clean_type_id(const char *typeid_name) {
std::string name(typeid_name);
detail::clean_type_id(name);
return name;
}
PYBIND11_NAMESPACE_END(detail)
/// Return a string representation of a C++ type
template <typename T>
static std::string type_id() {
return detail::clean_type_id(typeid(T).name());
}
PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)

View File

@@ -0,0 +1,22 @@
// Copyright (c) 2024 The Pybind Development Team.
// All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
#pragma once
#include "common.h"
#include "struct_smart_holder.h"
#include <type_traits>
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
using pybind11::memory::smart_holder;
PYBIND11_NAMESPACE_BEGIN(detail)
template <typename H>
using is_smart_holder = std::is_same<H, smart_holder>;
PYBIND11_NAMESPACE_END(detail)
PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)

View File

@@ -0,0 +1,90 @@
// Copyright (c) 2016-2024 The Pybind Development Team.
// All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
#pragma once
#include "common.h"
#include <cstddef>
#include <cstdint>
#include <typeinfo>
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
PYBIND11_NAMESPACE_BEGIN(detail)
struct value_and_holder {
instance *inst = nullptr;
size_t index = 0u;
const detail::type_info *type = nullptr;
void **vh = nullptr;
// Main constructor for a found value/holder:
value_and_holder(instance *i, const detail::type_info *type, size_t vpos, size_t index)
: inst{i}, index{index}, type{type},
vh{inst->simple_layout ? inst->simple_value_holder
: &inst->nonsimple.values_and_holders[vpos]} {}
// Default constructor (used to signal a value-and-holder not found by get_value_and_holder())
value_and_holder() = default;
// Used for past-the-end iterator
explicit value_and_holder(size_t index) : index{index} {}
template <typename V = void>
V *&value_ptr() const {
return reinterpret_cast<V *&>(vh[0]);
}
// True if this `value_and_holder` has a non-null value pointer
explicit operator bool() const { return value_ptr() != nullptr; }
template <typename H>
H &holder() const {
return reinterpret_cast<H &>(vh[1]);
}
bool holder_constructed() const {
return inst->simple_layout
? inst->simple_holder_constructed
: (inst->nonsimple.status[index] & instance::status_holder_constructed) != 0u;
}
// NOLINTNEXTLINE(readability-make-member-function-const)
void set_holder_constructed(bool v = true) {
if (inst->simple_layout) {
inst->simple_holder_constructed = v;
} else if (v) {
inst->nonsimple.status[index] |= instance::status_holder_constructed;
} else {
inst->nonsimple.status[index] &= (std::uint8_t) ~instance::status_holder_constructed;
}
}
bool instance_registered() const {
return inst->simple_layout
? inst->simple_instance_registered
: ((inst->nonsimple.status[index] & instance::status_instance_registered) != 0);
}
// NOLINTNEXTLINE(readability-make-member-function-const)
void set_instance_registered(bool v = true) {
if (inst->simple_layout) {
inst->simple_instance_registered = v;
} else if (v) {
inst->nonsimple.status[index] |= instance::status_instance_registered;
} else {
inst->nonsimple.status[index] &= (std::uint8_t) ~instance::status_instance_registered;
}
}
};
// This is a semi-public API to check if the corresponding instance has been constructed with a
// holder. That is, if the instance has been constructed with a holder, the `__init__` method is
// called and the C++ object is valid. Otherwise, the C++ object might only be allocated, but not
// initialized. This will lead to **SEGMENTATION FAULTS** if the C++ object is used in any way.
// Example usage: https://pybind11.readthedocs.io/en/stable/advanced/classes.html#custom-type-setup
// for `tp_traverse` and `tp_clear` implementations.
// WARNING: The caller is responsible for ensuring that the `reinterpret_cast` is valid.
inline bool is_holder_constructed(PyObject *obj) {
auto *const instance = reinterpret_cast<pybind11::detail::instance *>(obj);
return instance->get_value_and_holder().holder_constructed();
}
PYBIND11_NAMESPACE_END(detail)
PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)

View File

@@ -0,0 +1,12 @@
/*
pybind11/eigen.h: Transparent conversion for dense and sparse Eigen matrices
Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch>
All rights reserved. Use of this source code is governed by a
BSD-style license that can be found in the LICENSE file.
*/
#pragma once
#include "eigen/matrix.h"

View File

@@ -0,0 +1,9 @@
// Copyright (c) 2023 The pybind Community.
#pragma once
// Common message for `static_assert()`s, which are useful to easily
// preempt much less obvious errors.
#define PYBIND11_EIGEN_MESSAGE_POINTER_TYPES_ARE_NOT_SUPPORTED \
"Pointer types (in particular `PyObject *`) are not supported as scalar types for Eigen " \
"types."

View File

@@ -0,0 +1,723 @@
/*
pybind11/eigen/matrix.h: Transparent conversion for dense and sparse Eigen matrices
Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch>
All rights reserved. Use of this source code is governed by a
BSD-style license that can be found in the LICENSE file.
*/
#pragma once
#include <pybind11/numpy.h>
#include "common.h"
/* HINT: To suppress warnings originating from the Eigen headers, use -isystem.
See also:
https://stackoverflow.com/questions/2579576/i-dir-vs-isystem-dir
https://stackoverflow.com/questions/1741816/isystem-for-ms-visual-studio-c-compiler
*/
PYBIND11_WARNING_PUSH
PYBIND11_WARNING_DISABLE_MSVC(5054) // https://github.com/pybind/pybind11/pull/3741
// C5054: operator '&': deprecated between enumerations of different types
#if defined(__MINGW32__)
PYBIND11_WARNING_DISABLE_GCC("-Wmaybe-uninitialized")
#endif
#include <Eigen/Core>
#include <Eigen/SparseCore>
PYBIND11_WARNING_POP
// Eigen prior to 3.2.7 doesn't have proper move constructors--but worse, some classes get implicit
// move constructors that break things. We could detect this an explicitly copy, but an extra copy
// of matrices seems highly undesirable.
static_assert(EIGEN_VERSION_AT_LEAST(3, 2, 7),
"Eigen matrix support in pybind11 requires Eigen >= 3.2.7");
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
PYBIND11_WARNING_DISABLE_MSVC(4127)
// Provide a convenience alias for easier pass-by-ref usage with fully dynamic strides:
using EigenDStride = Eigen::Stride<Eigen::Dynamic, Eigen::Dynamic>;
template <typename MatrixType>
using EigenDRef = Eigen::Ref<MatrixType, 0, EigenDStride>;
template <typename MatrixType>
using EigenDMap = Eigen::Map<MatrixType, 0, EigenDStride>;
PYBIND11_NAMESPACE_BEGIN(detail)
#if EIGEN_VERSION_AT_LEAST(3, 3, 0)
using EigenIndex = Eigen::Index;
template <typename Scalar, int Flags, typename StorageIndex>
using EigenMapSparseMatrix = Eigen::Map<Eigen::SparseMatrix<Scalar, Flags, StorageIndex>>;
#else
using EigenIndex = EIGEN_DEFAULT_DENSE_INDEX_TYPE;
template <typename Scalar, int Flags, typename StorageIndex>
using EigenMapSparseMatrix = Eigen::MappedSparseMatrix<Scalar, Flags, StorageIndex>;
#endif
// Matches Eigen::Map, Eigen::Ref, blocks, etc:
template <typename T>
using is_eigen_dense_map = all_of<is_template_base_of<Eigen::DenseBase, T>,
std::is_base_of<Eigen::MapBase<T, Eigen::ReadOnlyAccessors>, T>>;
template <typename T>
using is_eigen_mutable_map = std::is_base_of<Eigen::MapBase<T, Eigen::WriteAccessors>, T>;
template <typename T>
using is_eigen_dense_plain
= all_of<negation<is_eigen_dense_map<T>>, is_template_base_of<Eigen::PlainObjectBase, T>>;
template <typename T>
using is_eigen_sparse = is_template_base_of<Eigen::SparseMatrixBase, T>;
// Test for objects inheriting from EigenBase<Derived> that aren't captured by the above. This
// basically covers anything that can be assigned to a dense matrix but that don't have a typical
// matrix data layout that can be copied from their .data(). For example, DiagonalMatrix and
// SelfAdjointView fall into this category.
template <typename T>
using is_eigen_other
= all_of<is_template_base_of<Eigen::EigenBase, T>,
negation<any_of<is_eigen_dense_map<T>, is_eigen_dense_plain<T>, is_eigen_sparse<T>>>>;
// Captures numpy/eigen conformability status (returned by EigenProps::conformable()):
template <bool EigenRowMajor>
struct EigenConformable {
bool conformable = false;
EigenIndex rows = 0, cols = 0;
EigenDStride stride{0, 0}; // Only valid if negativestrides is false!
bool negativestrides = false; // If true, do not use stride!
// NOLINTNEXTLINE(google-explicit-constructor)
EigenConformable(bool fits = false) : conformable{fits} {}
// Matrix type:
EigenConformable(EigenIndex r, EigenIndex c, EigenIndex rstride, EigenIndex cstride)
: conformable{true}, rows{r}, cols{c},
// TODO: when Eigen bug #747 is fixed, remove the tests for non-negativity.
// http://eigen.tuxfamily.org/bz/show_bug.cgi?id=747
stride{EigenRowMajor ? (rstride > 0 ? rstride : 0)
: (cstride > 0 ? cstride : 0) /* outer stride */,
EigenRowMajor ? (cstride > 0 ? cstride : 0)
: (rstride > 0 ? rstride : 0) /* inner stride */},
negativestrides{rstride < 0 || cstride < 0} {}
// Vector type:
EigenConformable(EigenIndex r, EigenIndex c, EigenIndex stride)
: EigenConformable(r, c, r == 1 ? c * stride : stride, c == 1 ? r : r * stride) {}
template <typename props>
bool stride_compatible() const {
// To have compatible strides, we need (on both dimensions) one of fully dynamic strides,
// matching strides, or a dimension size of 1 (in which case the stride value is
// irrelevant). Alternatively, if any dimension size is 0, the strides are not relevant
// (and numpy ≥ 1.23 sets the strides to 0 in that case, so we need to check explicitly).
if (negativestrides) {
return false;
}
if (rows == 0 || cols == 0) {
return true;
}
return (props::inner_stride == Eigen::Dynamic || props::inner_stride == stride.inner()
|| (EigenRowMajor ? cols : rows) == 1)
&& (props::outer_stride == Eigen::Dynamic || props::outer_stride == stride.outer()
|| (EigenRowMajor ? rows : cols) == 1);
}
// NOLINTNEXTLINE(google-explicit-constructor)
operator bool() const { return conformable; }
};
template <typename Type>
struct eigen_extract_stride {
using type = Type;
};
template <typename PlainObjectType, int MapOptions, typename StrideType>
struct eigen_extract_stride<Eigen::Map<PlainObjectType, MapOptions, StrideType>> {
using type = StrideType;
};
template <typename PlainObjectType, int Options, typename StrideType>
struct eigen_extract_stride<Eigen::Ref<PlainObjectType, Options, StrideType>> {
using type = StrideType;
};
// Helper struct for extracting information from an Eigen type
template <typename Type_>
struct EigenProps {
using Type = Type_;
using Scalar = typename Type::Scalar;
using StrideType = typename eigen_extract_stride<Type>::type;
static constexpr EigenIndex rows = Type::RowsAtCompileTime, cols = Type::ColsAtCompileTime,
size = Type::SizeAtCompileTime;
static constexpr bool row_major = Type::IsRowMajor,
vector
= Type::IsVectorAtCompileTime, // At least one dimension has fixed size 1
fixed_rows = rows != Eigen::Dynamic, fixed_cols = cols != Eigen::Dynamic,
fixed = size != Eigen::Dynamic, // Fully-fixed size
dynamic = !fixed_rows && !fixed_cols; // Fully-dynamic size
template <EigenIndex i, EigenIndex ifzero>
using if_zero = std::integral_constant<EigenIndex, i == 0 ? ifzero : i>;
static constexpr EigenIndex inner_stride
= if_zero<StrideType::InnerStrideAtCompileTime, 1>::value,
outer_stride = if_zero < StrideType::OuterStrideAtCompileTime,
vector ? size
: row_major ? cols
: rows > ::value;
static constexpr bool dynamic_stride
= inner_stride == Eigen::Dynamic && outer_stride == Eigen::Dynamic;
static constexpr bool requires_row_major
= !dynamic_stride && !vector && (row_major ? inner_stride : outer_stride) == 1;
static constexpr bool requires_col_major
= !dynamic_stride && !vector && (row_major ? outer_stride : inner_stride) == 1;
// Takes an input array and determines whether we can make it fit into the Eigen type. If
// the array is a vector, we attempt to fit it into either an Eigen 1xN or Nx1 vector
// (preferring the latter if it will fit in either, i.e. for a fully dynamic matrix type).
static EigenConformable<row_major> conformable(const array &a) {
const auto dims = a.ndim();
if (dims < 1 || dims > 2) {
return false;
}
if (dims == 2) { // Matrix type: require exact match (or dynamic)
EigenIndex np_rows = a.shape(0), np_cols = a.shape(1),
np_rstride = a.strides(0) / static_cast<ssize_t>(sizeof(Scalar)),
np_cstride = a.strides(1) / static_cast<ssize_t>(sizeof(Scalar));
if ((fixed_rows && np_rows != rows) || (fixed_cols && np_cols != cols)) {
return false;
}
return {np_rows, np_cols, np_rstride, np_cstride};
}
// Otherwise we're storing an n-vector. Only one of the strides will be used, but
// whichever is used, we want the (single) numpy stride value.
const EigenIndex n = a.shape(0),
stride = a.strides(0) / static_cast<ssize_t>(sizeof(Scalar));
if (vector) { // Eigen type is a compile-time vector
if (fixed && size != n) {
return false; // Vector size mismatch
}
return {rows == 1 ? 1 : n, cols == 1 ? 1 : n, stride};
}
if (fixed) {
// The type has a fixed size, but is not a vector: abort
return false;
}
if (fixed_cols) {
// Since this isn't a vector, cols must be != 1. We allow this only if it exactly
// equals the number of elements (rows is Dynamic, and so 1 row is allowed).
if (cols != n) {
return false;
}
return {1, n, stride};
} // Otherwise it's either fully dynamic, or column dynamic; both become a column vector
if (fixed_rows && rows != n) {
return false;
}
return {n, 1, stride};
}
static constexpr bool show_writeable
= is_eigen_dense_map<Type>::value && is_eigen_mutable_map<Type>::value;
static constexpr bool show_order = is_eigen_dense_map<Type>::value;
static constexpr bool show_c_contiguous = show_order && requires_row_major;
static constexpr bool show_f_contiguous
= !show_c_contiguous && show_order && requires_col_major;
static constexpr auto descriptor
= const_name("typing.Annotated[")
+ io_name("numpy.typing.ArrayLike, ", "numpy.typing.NDArray[")
+ npy_format_descriptor<Scalar>::name + io_name("", "]") + const_name(", \"[")
+ const_name<fixed_rows>(const_name<(size_t) rows>(), const_name("m")) + const_name(", ")
+ const_name<fixed_cols>(const_name<(size_t) cols>(), const_name("n"))
+ const_name("]\"")
// For a reference type (e.g. Ref<MatrixXd>) we have other constraints that might need to
// be satisfied: writeable=True (for a mutable reference), and, depending on the map's
// stride options, possibly f_contiguous or c_contiguous. We include them in the
// descriptor output to provide some hint as to why a TypeError is occurring (otherwise
// it can be confusing to see that a function accepts a
// 'typing.Annotated[numpy.typing.NDArray[numpy.float64], "[3,2]"]' and an error message
// that you *gave* a numpy.ndarray of the right type and dimensions.
+ const_name<show_writeable>(", \"flags.writeable\"", "")
+ const_name<show_c_contiguous>(", \"flags.c_contiguous\"", "")
+ const_name<show_f_contiguous>(", \"flags.f_contiguous\"", "") + const_name("]");
};
// Casts an Eigen type to numpy array. If given a base, the numpy array references the src data,
// otherwise it'll make a copy. writeable lets you turn off the writeable flag for the array.
template <typename props>
handle
eigen_array_cast(typename props::Type const &src, handle base = handle(), bool writeable = true) {
constexpr ssize_t elem_size = sizeof(typename props::Scalar);
array a;
if (props::vector) {
a = array({src.size()}, {elem_size * src.innerStride()}, src.data(), base);
} else {
a = array({src.rows(), src.cols()},
{elem_size * src.rowStride(), elem_size * src.colStride()},
src.data(),
base);
}
if (!writeable) {
array_proxy(a.ptr())->flags &= ~detail::npy_api::NPY_ARRAY_WRITEABLE_;
}
return a.release();
}
// Takes an lvalue ref to some Eigen type and a (python) base object, creating a numpy array that
// reference the Eigen object's data with `base` as the python-registered base class (if omitted,
// the base will be set to None, and lifetime management is up to the caller). The numpy array is
// non-writeable if the given type is const.
template <typename props, typename Type>
handle eigen_ref_array(Type &src, handle parent = none()) {
// none here is to get past array's should-we-copy detection, which currently always
// copies when there is no base. Setting the base to None should be harmless.
return eigen_array_cast<props>(src, parent, !std::is_const<Type>::value);
}
// Takes a pointer to some dense, plain Eigen type, builds a capsule around it, then returns a
// numpy array that references the encapsulated data with a python-side reference to the capsule to
// tie its destruction to that of any dependent python objects. Const-ness is determined by
// whether or not the Type of the pointer given is const.
template <typename props, typename Type, typename = enable_if_t<is_eigen_dense_plain<Type>::value>>
handle eigen_encapsulate(Type *src) {
capsule base(src, [](void *o) { delete static_cast<Type *>(o); });
return eigen_ref_array<props>(*src, base);
}
// Type caster for regular, dense matrix types (e.g. MatrixXd), but not maps/refs/etc. of dense
// types.
template <typename Type>
struct type_caster<Type, enable_if_t<is_eigen_dense_plain<Type>::value>> {
using Scalar = typename Type::Scalar;
static_assert(!std::is_pointer<Scalar>::value,
PYBIND11_EIGEN_MESSAGE_POINTER_TYPES_ARE_NOT_SUPPORTED);
using props = EigenProps<Type>;
bool load(handle src, bool convert) {
// If we're in no-convert mode, only load if given an array of the correct type
if (!convert && !isinstance<array_t<Scalar>>(src)) {
return false;
}
// Coerce into an array, but don't do type conversion yet; the copy below handles it.
auto buf = array::ensure(src);
if (!buf) {
return false;
}
auto dims = buf.ndim();
if (dims < 1 || dims > 2) {
return false;
}
auto fits = props::conformable(buf);
if (!fits) {
return false;
}
PYBIND11_WARNING_PUSH
PYBIND11_WARNING_DISABLE_GCC("-Wmaybe-uninitialized") // See PR #5516
// Allocate the new type, then build a numpy reference into it
value = Type(fits.rows, fits.cols);
PYBIND11_WARNING_POP
auto ref = reinterpret_steal<array>(eigen_ref_array<props>(value));
if (dims == 1) {
ref = ref.squeeze();
} else if (ref.ndim() == 1) {
buf = buf.squeeze();
}
int result = detail::npy_api::get().PyArray_CopyInto_(ref.ptr(), buf.ptr());
if (result < 0) { // Copy failed!
PyErr_Clear();
return false;
}
return true;
}
private:
// Cast implementation
template <typename CType>
static handle cast_impl(CType *src, return_value_policy policy, handle parent) {
switch (policy) {
case return_value_policy::take_ownership:
case return_value_policy::automatic:
return eigen_encapsulate<props>(src);
case return_value_policy::move:
return eigen_encapsulate<props>(new CType(std::move(*src)));
case return_value_policy::copy:
return eigen_array_cast<props>(*src);
case return_value_policy::reference:
case return_value_policy::automatic_reference:
return eigen_ref_array<props>(*src);
case return_value_policy::reference_internal:
return eigen_ref_array<props>(*src, parent);
default:
throw cast_error("unhandled return_value_policy: should not happen!");
};
}
public:
// Normal returned non-reference, non-const value:
static handle cast(Type &&src, return_value_policy /* policy */, handle parent) {
return cast_impl(&src, return_value_policy::move, parent);
}
// If you return a non-reference const, we mark the numpy array readonly:
static handle cast(const Type &&src, return_value_policy /* policy */, handle parent) {
return cast_impl(&src, return_value_policy::move, parent);
}
// lvalue reference return; default (automatic) becomes copy
static handle cast(Type &src, return_value_policy policy, handle parent) {
if (policy == return_value_policy::automatic
|| policy == return_value_policy::automatic_reference) {
policy = return_value_policy::copy;
}
return cast_impl(&src, policy, parent);
}
// const lvalue reference return; default (automatic) becomes copy
static handle cast(const Type &src, return_value_policy policy, handle parent) {
if (policy == return_value_policy::automatic
|| policy == return_value_policy::automatic_reference) {
policy = return_value_policy::copy;
}
return cast(&src, policy, parent);
}
// non-const pointer return
static handle cast(Type *src, return_value_policy policy, handle parent) {
return cast_impl(src, policy, parent);
}
// const pointer return
static handle cast(const Type *src, return_value_policy policy, handle parent) {
return cast_impl(src, policy, parent);
}
static constexpr auto name = props::descriptor;
// NOLINTNEXTLINE(google-explicit-constructor)
operator Type *() { return &value; }
// NOLINTNEXTLINE(google-explicit-constructor)
operator Type &() { return value; }
// NOLINTNEXTLINE(google-explicit-constructor)
operator Type &&() && { return std::move(value); }
template <typename T>
using cast_op_type = movable_cast_op_type<T>;
private:
Type value;
};
// Base class for casting reference/map/block/etc. objects back to python.
template <typename MapType>
struct eigen_map_caster {
static_assert(!std::is_pointer<typename MapType::Scalar>::value,
PYBIND11_EIGEN_MESSAGE_POINTER_TYPES_ARE_NOT_SUPPORTED);
private:
using props = EigenProps<MapType>;
public:
// Directly referencing a ref/map's data is a bit dangerous (whatever the map/ref points to has
// to stay around), but we'll allow it under the assumption that you know what you're doing
// (and have an appropriate keep_alive in place). We return a numpy array pointing directly at
// the ref's data (The numpy array ends up read-only if the ref was to a const matrix type.)
// Note that this means you need to ensure you don't destroy the object in some other way (e.g.
// with an appropriate keep_alive, or with a reference to a statically allocated matrix).
static handle cast(const MapType &src, return_value_policy policy, handle parent) {
switch (policy) {
case return_value_policy::copy:
return eigen_array_cast<props>(src);
case return_value_policy::reference_internal:
return eigen_array_cast<props>(src, parent, is_eigen_mutable_map<MapType>::value);
case return_value_policy::reference:
case return_value_policy::automatic:
case return_value_policy::automatic_reference:
return eigen_array_cast<props>(src, none(), is_eigen_mutable_map<MapType>::value);
default:
// move, take_ownership don't make any sense for a ref/map:
pybind11_fail("Invalid return_value_policy for Eigen Map/Ref/Block type");
}
}
// return_descr forces the use of NDArray instead of ArrayLike in args
// since Ref<...> args can only accept arrays.
static constexpr auto name = return_descr(props::descriptor);
// Explicitly delete these: support python -> C++ conversion on these (i.e. these can be return
// types but not bound arguments). We still provide them (with an explicitly delete) so that
// you end up here if you try anyway.
bool load(handle, bool) = delete;
operator MapType() = delete;
template <typename>
using cast_op_type = MapType;
};
// We can return any map-like object (but can only load Refs, specialized next):
template <typename Type>
struct type_caster<Type, enable_if_t<is_eigen_dense_map<Type>::value>> : eigen_map_caster<Type> {};
// Loader for Ref<...> arguments. See the documentation for info on how to make this work without
// copying (it requires some extra effort in many cases).
template <typename PlainObjectType, typename StrideType>
struct type_caster<
Eigen::Ref<PlainObjectType, 0, StrideType>,
enable_if_t<is_eigen_dense_map<Eigen::Ref<PlainObjectType, 0, StrideType>>::value>>
: public eigen_map_caster<Eigen::Ref<PlainObjectType, 0, StrideType>> {
private:
using Type = Eigen::Ref<PlainObjectType, 0, StrideType>;
using props = EigenProps<Type>;
using Scalar = typename props::Scalar;
static_assert(!std::is_pointer<Scalar>::value,
PYBIND11_EIGEN_MESSAGE_POINTER_TYPES_ARE_NOT_SUPPORTED);
using MapType = Eigen::Map<PlainObjectType, 0, StrideType>;
using Array
= array_t<Scalar,
array::forcecast
| ((props::row_major ? props::inner_stride : props::outer_stride) == 1
? array::c_style
: (props::row_major ? props::outer_stride : props::inner_stride) == 1
? array::f_style
: 0)>;
static constexpr bool need_writeable = is_eigen_mutable_map<Type>::value;
// Delay construction (these have no default constructor)
std::unique_ptr<MapType> map;
std::unique_ptr<Type> ref;
// Our array. When possible, this is just a numpy array pointing to the source data, but
// sometimes we can't avoid copying (e.g. input is not a numpy array at all, has an
// incompatible layout, or is an array of a type that needs to be converted). Using a numpy
// temporary (rather than an Eigen temporary) saves an extra copy when we need both type
// conversion and storage order conversion. (Note that we refuse to use this temporary copy
// when loading an argument for a Ref<M> with M non-const, i.e. a read-write reference).
Array copy_or_ref;
public:
bool load(handle src, bool convert) {
// First check whether what we have is already an array of the right type. If not, we
// can't avoid a copy (because the copy is also going to do type conversion).
bool need_copy = !isinstance<Array>(src);
EigenConformable<props::row_major> fits;
if (!need_copy) {
// We don't need a converting copy, but we also need to check whether the strides are
// compatible with the Ref's stride requirements
auto aref = reinterpret_borrow<Array>(src);
if (aref && (!need_writeable || aref.writeable())) {
fits = props::conformable(aref);
if (!fits) {
return false; // Incompatible dimensions
}
if (!fits.template stride_compatible<props>()) {
need_copy = true;
} else {
copy_or_ref = std::move(aref);
}
} else {
need_copy = true;
}
}
if (need_copy) {
// We need to copy: If we need a mutable reference, or we're not supposed to convert
// (either because we're in the no-convert overload pass, or because we're explicitly
// instructed not to copy (via `py::arg().noconvert()`) we have to fail loading.
if (!convert || need_writeable) {
return false;
}
Array copy = Array::ensure(src);
if (!copy) {
return false;
}
fits = props::conformable(copy);
if (!fits || !fits.template stride_compatible<props>()) {
return false;
}
copy_or_ref = std::move(copy);
loader_life_support::add_patient(copy_or_ref);
}
ref.reset();
map.reset(new MapType(data(copy_or_ref),
fits.rows,
fits.cols,
make_stride(fits.stride.outer(), fits.stride.inner())));
ref.reset(new Type(*map));
return true;
}
// NOLINTNEXTLINE(google-explicit-constructor)
operator Type *() { return ref.get(); }
// NOLINTNEXTLINE(google-explicit-constructor)
operator Type &() { return *ref; }
template <typename _T>
using cast_op_type = pybind11::detail::cast_op_type<_T>;
private:
template <typename T = Type, enable_if_t<is_eigen_mutable_map<T>::value, int> = 0>
Scalar *data(Array &a) {
return a.mutable_data();
}
template <typename T = Type, enable_if_t<!is_eigen_mutable_map<T>::value, int> = 0>
const Scalar *data(Array &a) {
return a.data();
}
// Attempt to figure out a constructor of `Stride` that will work.
// If both strides are fixed, use a default constructor:
template <typename S>
using stride_ctor_default = bool_constant<S::InnerStrideAtCompileTime != Eigen::Dynamic
&& S::OuterStrideAtCompileTime != Eigen::Dynamic
&& std::is_default_constructible<S>::value>;
// Otherwise, if there is a two-index constructor, assume it is (outer,inner) like
// Eigen::Stride, and use it:
template <typename S>
using stride_ctor_dual
= bool_constant<!stride_ctor_default<S>::value
&& std::is_constructible<S, EigenIndex, EigenIndex>::value>;
// Otherwise, if there is a one-index constructor, and just one of the strides is dynamic, use
// it (passing whichever stride is dynamic).
template <typename S>
using stride_ctor_outer
= bool_constant<!any_of<stride_ctor_default<S>, stride_ctor_dual<S>>::value
&& S::OuterStrideAtCompileTime == Eigen::Dynamic
&& S::InnerStrideAtCompileTime != Eigen::Dynamic
&& std::is_constructible<S, EigenIndex>::value>;
template <typename S>
using stride_ctor_inner
= bool_constant<!any_of<stride_ctor_default<S>, stride_ctor_dual<S>>::value
&& S::InnerStrideAtCompileTime == Eigen::Dynamic
&& S::OuterStrideAtCompileTime != Eigen::Dynamic
&& std::is_constructible<S, EigenIndex>::value>;
template <typename S = StrideType, enable_if_t<stride_ctor_default<S>::value, int> = 0>
static S make_stride(EigenIndex, EigenIndex) {
return S();
}
template <typename S = StrideType, enable_if_t<stride_ctor_dual<S>::value, int> = 0>
static S make_stride(EigenIndex outer, EigenIndex inner) {
return S(outer, inner);
}
template <typename S = StrideType, enable_if_t<stride_ctor_outer<S>::value, int> = 0>
static S make_stride(EigenIndex outer, EigenIndex) {
return S(outer);
}
template <typename S = StrideType, enable_if_t<stride_ctor_inner<S>::value, int> = 0>
static S make_stride(EigenIndex, EigenIndex inner) {
return S(inner);
}
};
// type_caster for special matrix types (e.g. DiagonalMatrix), which are EigenBase, but not
// EigenDense (i.e. they don't have a data(), at least not with the usual matrix layout).
// load() is not supported, but we can cast them into the python domain by first copying to a
// regular Eigen::Matrix, then casting that.
template <typename Type>
struct type_caster<Type, enable_if_t<is_eigen_other<Type>::value>> {
static_assert(!std::is_pointer<typename Type::Scalar>::value,
PYBIND11_EIGEN_MESSAGE_POINTER_TYPES_ARE_NOT_SUPPORTED);
protected:
using Matrix
= Eigen::Matrix<typename Type::Scalar, Type::RowsAtCompileTime, Type::ColsAtCompileTime>;
using props = EigenProps<Matrix>;
public:
static handle cast(const Type &src, return_value_policy /* policy */, handle /* parent */) {
handle h = eigen_encapsulate<props>(new Matrix(src));
return h;
}
static handle cast(const Type *src, return_value_policy policy, handle parent) {
return cast(*src, policy, parent);
}
static constexpr auto name = props::descriptor;
// Explicitly delete these: support python -> C++ conversion on these (i.e. these can be return
// types but not bound arguments). We still provide them (with an explicitly delete) so that
// you end up here if you try anyway.
bool load(handle, bool) = delete;
operator Type() = delete;
template <typename>
using cast_op_type = Type;
};
template <typename Type>
struct type_caster<Type, enable_if_t<is_eigen_sparse<Type>::value>> {
using Scalar = typename Type::Scalar;
static_assert(!std::is_pointer<Scalar>::value,
PYBIND11_EIGEN_MESSAGE_POINTER_TYPES_ARE_NOT_SUPPORTED);
using StorageIndex = remove_reference_t<decltype(*std::declval<Type>().outerIndexPtr())>;
using Index = typename Type::Index;
static constexpr bool rowMajor = Type::IsRowMajor;
bool load(handle src, bool) {
if (!src) {
return false;
}
auto obj = reinterpret_borrow<object>(src);
object sparse_module = module_::import("scipy.sparse");
object matrix_type = sparse_module.attr(rowMajor ? "csr_matrix" : "csc_matrix");
if (!type::handle_of(obj).is(matrix_type)) {
try {
obj = matrix_type(obj);
} catch (const error_already_set &) {
return false;
}
}
auto values = array_t<Scalar>((object) obj.attr("data"));
auto innerIndices = array_t<StorageIndex>((object) obj.attr("indices"));
auto outerIndices = array_t<StorageIndex>((object) obj.attr("indptr"));
auto shape = pybind11::tuple((pybind11::object) obj.attr("shape"));
auto nnz = obj.attr("nnz").cast<Index>();
if (!values || !innerIndices || !outerIndices) {
return false;
}
value = EigenMapSparseMatrix<Scalar,
Type::Flags &(Eigen::RowMajor | Eigen::ColMajor),
StorageIndex>(shape[0].cast<Index>(),
shape[1].cast<Index>(),
std::move(nnz),
outerIndices.mutable_data(),
innerIndices.mutable_data(),
values.mutable_data());
return true;
}
static handle cast(const Type &src, return_value_policy /* policy */, handle /* parent */) {
const_cast<Type &>(src).makeCompressed();
object matrix_type
= module_::import("scipy.sparse").attr(rowMajor ? "csr_matrix" : "csc_matrix");
array data(src.nonZeros(), src.valuePtr());
array outerIndices((rowMajor ? src.rows() : src.cols()) + 1, src.outerIndexPtr());
array innerIndices(src.nonZeros(), src.innerIndexPtr());
return matrix_type(pybind11::make_tuple(
std::move(data), std::move(innerIndices), std::move(outerIndices)),
pybind11::make_tuple(src.rows(), src.cols()))
.release();
}
PYBIND11_TYPE_CASTER(Type,
const_name<(Type::IsRowMajor) != 0>("scipy.sparse.csr_matrix[",
"scipy.sparse.csc_matrix[")
+ npy_format_descriptor<Scalar>::name + const_name("]"));
};
PYBIND11_NAMESPACE_END(detail)
PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)

View File

@@ -0,0 +1,521 @@
/*
pybind11/eigen/tensor.h: Transparent conversion for Eigen tensors
All rights reserved. Use of this source code is governed by a
BSD-style license that can be found in the LICENSE file.
*/
#pragma once
#include <pybind11/numpy.h>
#include "common.h"
#if defined(__GNUC__) && !defined(__clang__) && !defined(__INTEL_COMPILER)
static_assert(__GNUC__ > 5, "Eigen Tensor support in pybind11 requires GCC > 5.0");
#endif
// Disable warnings for Eigen
PYBIND11_WARNING_PUSH
PYBIND11_WARNING_DISABLE_MSVC(4554)
PYBIND11_WARNING_DISABLE_MSVC(4127)
#if defined(__MINGW32__)
PYBIND11_WARNING_DISABLE_GCC("-Wmaybe-uninitialized")
#endif
#include <unsupported/Eigen/CXX11/Tensor>
PYBIND11_WARNING_POP
static_assert(EIGEN_VERSION_AT_LEAST(3, 3, 0),
"Eigen Tensor support in pybind11 requires Eigen >= 3.3.0");
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
PYBIND11_WARNING_DISABLE_MSVC(4127)
PYBIND11_NAMESPACE_BEGIN(detail)
inline bool is_tensor_aligned(const void *data) {
return (reinterpret_cast<std::size_t>(data) % EIGEN_DEFAULT_ALIGN_BYTES) == 0;
}
template <typename T>
constexpr int compute_array_flag_from_tensor() {
static_assert((static_cast<int>(T::Layout) == static_cast<int>(Eigen::RowMajor))
|| (static_cast<int>(T::Layout) == static_cast<int>(Eigen::ColMajor)),
"Layout must be row or column major");
return (static_cast<int>(T::Layout) == static_cast<int>(Eigen::RowMajor)) ? array::c_style
: array::f_style;
}
template <typename T>
struct eigen_tensor_helper {};
template <typename Scalar_, int NumIndices_, int Options_, typename IndexType>
struct eigen_tensor_helper<Eigen::Tensor<Scalar_, NumIndices_, Options_, IndexType>> {
using Type = Eigen::Tensor<Scalar_, NumIndices_, Options_, IndexType>;
using ValidType = void;
static Eigen::DSizes<typename Type::Index, Type::NumIndices> get_shape(const Type &f) {
return f.dimensions();
}
static constexpr bool
is_correct_shape(const Eigen::DSizes<typename Type::Index, Type::NumIndices> & /*shape*/) {
return true;
}
template <typename T>
struct helper {};
template <size_t... Is>
struct helper<index_sequence<Is...>> {
static constexpr auto value = ::pybind11::detail::concat(const_name(((void) Is, "?"))...);
};
static constexpr auto dimensions_descriptor
= helper<decltype(make_index_sequence<Type::NumIndices>())>::value;
template <typename... Args>
static Type *alloc(Args &&...args) {
return new Type(std::forward<Args>(args)...);
}
static void free(Type *tensor) { delete tensor; }
};
template <typename Scalar_, typename std::ptrdiff_t... Indices, int Options_, typename IndexType>
struct eigen_tensor_helper<
Eigen::TensorFixedSize<Scalar_, Eigen::Sizes<Indices...>, Options_, IndexType>> {
using Type = Eigen::TensorFixedSize<Scalar_, Eigen::Sizes<Indices...>, Options_, IndexType>;
using ValidType = void;
static constexpr Eigen::DSizes<typename Type::Index, Type::NumIndices>
get_shape(const Type & /*f*/) {
return get_shape();
}
static constexpr Eigen::DSizes<typename Type::Index, Type::NumIndices> get_shape() {
return Eigen::DSizes<typename Type::Index, Type::NumIndices>(Indices...);
}
static bool
is_correct_shape(const Eigen::DSizes<typename Type::Index, Type::NumIndices> &shape) {
return get_shape() == shape;
}
static constexpr auto dimensions_descriptor
= ::pybind11::detail::concat(const_name<Indices>()...);
template <typename... Args>
static Type *alloc(Args &&...args) {
Eigen::aligned_allocator<Type> allocator;
return ::new (allocator.allocate(1)) Type(std::forward<Args>(args)...);
}
static void free(Type *tensor) {
Eigen::aligned_allocator<Type> allocator;
tensor->~Type();
allocator.deallocate(tensor, 1);
}
};
template <typename Type, bool ShowDetails, bool NeedsWriteable = false>
struct get_tensor_descriptor {
static constexpr auto details
= const_name<NeedsWriteable>(", \"flags.writeable\"", "") + const_name
< static_cast<int>(Type::Layout)
== static_cast<int>(Eigen::RowMajor)
> (", \"flags.c_contiguous\"", ", \"flags.f_contiguous\"");
static constexpr auto value
= const_name("typing.Annotated[")
+ io_name("numpy.typing.ArrayLike, ", "numpy.typing.NDArray[")
+ npy_format_descriptor<typename Type::Scalar>::name + io_name("", "]")
+ const_name(", \"[") + eigen_tensor_helper<remove_cv_t<Type>>::dimensions_descriptor
+ const_name("]\"") + const_name<ShowDetails>(details, const_name("")) + const_name("]");
};
// When EIGEN_AVOID_STL_ARRAY is defined, Eigen::DSizes<T, 0> does not have the begin() member
// function. Falling back to a simple loop works around this issue.
//
// We need to disable the type-limits warning for the inner loop when size = 0.
PYBIND11_WARNING_PUSH
PYBIND11_WARNING_DISABLE_GCC("-Wtype-limits")
template <typename T, int size>
std::vector<T> convert_dsizes_to_vector(const Eigen::DSizes<T, size> &arr) {
std::vector<T> result(size);
for (size_t i = 0; i < size; i++) {
result[i] = arr[i];
}
return result;
}
template <typename T, int size>
Eigen::DSizes<T, size> get_shape_for_array(const array &arr) {
Eigen::DSizes<T, size> result;
const T *shape = arr.shape();
for (size_t i = 0; i < size; i++) {
result[i] = shape[i];
}
return result;
}
PYBIND11_WARNING_POP
template <typename Type>
struct type_caster<Type, typename eigen_tensor_helper<Type>::ValidType> {
static_assert(!std::is_pointer<typename Type::Scalar>::value,
PYBIND11_EIGEN_MESSAGE_POINTER_TYPES_ARE_NOT_SUPPORTED);
using Helper = eigen_tensor_helper<Type>;
static constexpr auto temp_name = get_tensor_descriptor<Type, false>::value;
PYBIND11_TYPE_CASTER(Type, temp_name);
bool load(handle src, bool convert) {
if (!convert) {
if (!isinstance<array>(src)) {
return false;
}
array temp = array::ensure(src);
if (!temp) {
return false;
}
if (!temp.dtype().is(dtype::of<typename Type::Scalar>())) {
return false;
}
}
array_t<typename Type::Scalar, compute_array_flag_from_tensor<Type>()> arr(
reinterpret_borrow<object>(src));
if (arr.ndim() != Type::NumIndices) {
return false;
}
auto shape = get_shape_for_array<typename Type::Index, Type::NumIndices>(arr);
if (!Helper::is_correct_shape(shape)) {
return false;
}
#if EIGEN_VERSION_AT_LEAST(3, 4, 0)
auto data_pointer = arr.data();
#else
// Handle Eigen bug
auto data_pointer = const_cast<typename Type::Scalar *>(arr.data());
#endif
if (is_tensor_aligned(arr.data())) {
value = Eigen::TensorMap<const Type, Eigen::Aligned>(data_pointer, shape);
} else {
value = Eigen::TensorMap<const Type>(data_pointer, shape);
}
return true;
}
static handle cast(Type &&src, return_value_policy policy, handle parent) {
if (policy == return_value_policy::reference
|| policy == return_value_policy::reference_internal) {
pybind11_fail("Cannot use a reference return value policy for an rvalue");
}
return cast_impl(&src, return_value_policy::move, parent);
}
static handle cast(const Type &&src, return_value_policy policy, handle parent) {
if (policy == return_value_policy::reference
|| policy == return_value_policy::reference_internal) {
pybind11_fail("Cannot use a reference return value policy for an rvalue");
}
return cast_impl(&src, return_value_policy::move, parent);
}
static handle cast(Type &src, return_value_policy policy, handle parent) {
if (policy == return_value_policy::automatic
|| policy == return_value_policy::automatic_reference) {
policy = return_value_policy::copy;
}
return cast_impl(&src, policy, parent);
}
static handle cast(const Type &src, return_value_policy policy, handle parent) {
if (policy == return_value_policy::automatic
|| policy == return_value_policy::automatic_reference) {
policy = return_value_policy::copy;
}
return cast(&src, policy, parent);
}
static handle cast(Type *src, return_value_policy policy, handle parent) {
if (policy == return_value_policy::automatic) {
policy = return_value_policy::take_ownership;
} else if (policy == return_value_policy::automatic_reference) {
policy = return_value_policy::reference;
}
return cast_impl(src, policy, parent);
}
static handle cast(const Type *src, return_value_policy policy, handle parent) {
if (policy == return_value_policy::automatic) {
policy = return_value_policy::take_ownership;
} else if (policy == return_value_policy::automatic_reference) {
policy = return_value_policy::reference;
}
return cast_impl(src, policy, parent);
}
template <typename C>
static handle cast_impl(C *src, return_value_policy policy, handle parent) {
object parent_object;
bool writeable = false;
switch (policy) {
case return_value_policy::move:
if (std::is_const<C>::value) {
pybind11_fail("Cannot move from a constant reference");
}
src = Helper::alloc(std::move(*src));
parent_object
= capsule(src, [](void *ptr) { Helper::free(reinterpret_cast<Type *>(ptr)); });
writeable = true;
break;
case return_value_policy::take_ownership:
if (std::is_const<C>::value) {
// This cast is ugly, and might be UB in some cases, but we don't have an
// alternative here as we must free that memory
Helper::free(const_cast<Type *>(src));
pybind11_fail("Cannot take ownership of a const reference");
}
parent_object
= capsule(src, [](void *ptr) { Helper::free(reinterpret_cast<Type *>(ptr)); });
writeable = true;
break;
case return_value_policy::copy:
writeable = true;
break;
case return_value_policy::reference:
parent_object = none();
writeable = !std::is_const<C>::value;
break;
case return_value_policy::reference_internal:
// Default should do the right thing
if (!parent) {
pybind11_fail("Cannot use reference internal when there is no parent");
}
parent_object = reinterpret_borrow<object>(parent);
writeable = !std::is_const<C>::value;
break;
default:
pybind11_fail("pybind11 bug in eigen.h, please file a bug report");
}
auto result = array_t<typename Type::Scalar, compute_array_flag_from_tensor<Type>()>(
convert_dsizes_to_vector(Helper::get_shape(*src)), src->data(), parent_object);
if (!writeable) {
array_proxy(result.ptr())->flags &= ~detail::npy_api::NPY_ARRAY_WRITEABLE_;
}
return result.release();
}
};
template <typename StoragePointerType,
bool needs_writeable,
enable_if_t<!needs_writeable, bool> = true>
StoragePointerType get_array_data_for_type(array &arr) {
#if EIGEN_VERSION_AT_LEAST(3, 4, 0)
return reinterpret_cast<StoragePointerType>(arr.data());
#else
// Handle Eigen bug
return reinterpret_cast<StoragePointerType>(const_cast<void *>(arr.data()));
#endif
}
template <typename StoragePointerType,
bool needs_writeable,
enable_if_t<needs_writeable, bool> = true>
StoragePointerType get_array_data_for_type(array &arr) {
return reinterpret_cast<StoragePointerType>(arr.mutable_data());
}
template <typename T, typename = void>
struct get_storage_pointer_type;
template <typename MapType>
struct get_storage_pointer_type<MapType, void_t<typename MapType::StoragePointerType>> {
using SPT = typename MapType::StoragePointerType;
};
template <typename MapType>
struct get_storage_pointer_type<MapType, void_t<typename MapType::PointerArgType>> {
using SPT = typename MapType::PointerArgType;
};
template <typename Type, int Options>
struct type_caster<Eigen::TensorMap<Type, Options>,
typename eigen_tensor_helper<remove_cv_t<Type>>::ValidType> {
static_assert(!std::is_pointer<typename Type::Scalar>::value,
PYBIND11_EIGEN_MESSAGE_POINTER_TYPES_ARE_NOT_SUPPORTED);
using MapType = Eigen::TensorMap<Type, Options>;
using Helper = eigen_tensor_helper<remove_cv_t<Type>>;
bool load(handle src, bool /*convert*/) {
// Note that we have a lot more checks here as we want to make sure to avoid copies
if (!isinstance<array>(src)) {
return false;
}
auto arr = reinterpret_borrow<array>(src);
if ((arr.flags() & compute_array_flag_from_tensor<Type>()) == 0) {
return false;
}
if (!arr.dtype().is(dtype::of<typename Type::Scalar>())) {
return false;
}
if (arr.ndim() != Type::NumIndices) {
return false;
}
constexpr bool is_aligned = (Options & Eigen::Aligned) != 0;
if (is_aligned && !is_tensor_aligned(arr.data())) {
return false;
}
auto shape = get_shape_for_array<typename Type::Index, Type::NumIndices>(arr);
if (!Helper::is_correct_shape(shape)) {
return false;
}
if (needs_writeable && !arr.writeable()) {
return false;
}
auto result = get_array_data_for_type<typename get_storage_pointer_type<MapType>::SPT,
needs_writeable>(arr);
value.reset(new MapType(std::move(result), std::move(shape)));
return true;
}
static handle cast(MapType &&src, return_value_policy policy, handle parent) {
return cast_impl(&src, policy, parent);
}
static handle cast(const MapType &&src, return_value_policy policy, handle parent) {
return cast_impl(&src, policy, parent);
}
static handle cast(MapType &src, return_value_policy policy, handle parent) {
if (policy == return_value_policy::automatic
|| policy == return_value_policy::automatic_reference) {
policy = return_value_policy::copy;
}
return cast_impl(&src, policy, parent);
}
static handle cast(const MapType &src, return_value_policy policy, handle parent) {
if (policy == return_value_policy::automatic
|| policy == return_value_policy::automatic_reference) {
policy = return_value_policy::copy;
}
return cast(&src, policy, parent);
}
static handle cast(MapType *src, return_value_policy policy, handle parent) {
if (policy == return_value_policy::automatic) {
policy = return_value_policy::take_ownership;
} else if (policy == return_value_policy::automatic_reference) {
policy = return_value_policy::reference;
}
return cast_impl(src, policy, parent);
}
static handle cast(const MapType *src, return_value_policy policy, handle parent) {
if (policy == return_value_policy::automatic) {
policy = return_value_policy::take_ownership;
} else if (policy == return_value_policy::automatic_reference) {
policy = return_value_policy::reference;
}
return cast_impl(src, policy, parent);
}
template <typename C>
static handle cast_impl(C *src, return_value_policy policy, handle parent) {
object parent_object;
constexpr bool writeable = !std::is_const<C>::value;
switch (policy) {
case return_value_policy::reference:
parent_object = none();
break;
case return_value_policy::reference_internal:
// Default should do the right thing
if (!parent) {
pybind11_fail("Cannot use reference internal when there is no parent");
}
parent_object = reinterpret_borrow<object>(parent);
break;
default:
// move, take_ownership don't make any sense for a ref/map:
pybind11_fail("Invalid return_value_policy for Eigen Map type, must be either "
"reference or reference_internal");
}
auto result = array_t<typename Type::Scalar, compute_array_flag_from_tensor<Type>()>(
convert_dsizes_to_vector(Helper::get_shape(*src)),
src->data(),
std::move(parent_object));
if (!writeable) {
array_proxy(result.ptr())->flags &= ~detail::npy_api::NPY_ARRAY_WRITEABLE_;
}
return result.release();
}
#if EIGEN_VERSION_AT_LEAST(3, 4, 0)
static constexpr bool needs_writeable = !std::is_const<typename std::remove_pointer<
typename get_storage_pointer_type<MapType>::SPT>::type>::value;
#else
// Handle Eigen bug
static constexpr bool needs_writeable = !std::is_const<Type>::value;
#endif
protected:
// TODO: Move to std::optional once std::optional has more support
std::unique_ptr<MapType> value;
public:
// return_descr forces the use of NDArray instead of ArrayLike since refs can only reference
// arrays
static constexpr auto name
= return_descr(get_tensor_descriptor<Type, true, needs_writeable>::value);
explicit operator MapType *() { return value.get(); }
explicit operator MapType &() { return *value; }
explicit operator MapType &&() && { return std::move(*value); }
template <typename T_>
using cast_op_type = ::pybind11::detail::movable_cast_op_type<T_>;
};
PYBIND11_NAMESPACE_END(detail)
PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)

View File

@@ -0,0 +1,320 @@
/*
pybind11/embed.h: Support for embedding the interpreter
Copyright (c) 2017 Wenzel Jakob <wenzel.jakob@epfl.ch>
All rights reserved. Use of this source code is governed by a
BSD-style license that can be found in the LICENSE file.
*/
#pragma once
#include "pybind11.h"
#include "eval.h"
#include <memory>
#include <vector>
#if defined(PYPY_VERSION)
# error Embedding the interpreter is not supported with PyPy
#endif
#define PYBIND11_EMBEDDED_MODULE_IMPL(name) \
extern "C" PyObject *pybind11_init_impl_##name(); \
extern "C" PyObject *pybind11_init_impl_##name() { return pybind11_init_wrapper_##name(); }
/** \rst
Add a new module to the table of builtins for the interpreter. Must be
defined in global scope. The first macro parameter is the name of the
module (without quotes). The second parameter is the variable which will
be used as the interface to add functions and classes to the module.
.. code-block:: cpp
PYBIND11_EMBEDDED_MODULE(example, m) {
// ... initialize functions and classes here
m.def("foo", []() {
return "Hello, World!";
});
}
The third and subsequent macro arguments are optional, and can be used to
mark the module as supporting various Python features.
- ``mod_gil_not_used()``
- ``multiple_interpreters::per_interpreter_gil()``
- ``multiple_interpreters::shared_gil()``
- ``multiple_interpreters::not_supported()``
.. code-block:: cpp
PYBIND11_EMBEDDED_MODULE(example, m, py::mod_gil_not_used()) {
m.def("foo", []() {
return "Hello, Free-threaded World!";
});
}
\endrst */
PYBIND11_WARNING_PUSH
PYBIND11_WARNING_DISABLE_CLANG("-Wgnu-zero-variadic-macro-arguments")
#define PYBIND11_EMBEDDED_MODULE(name, variable, ...) \
PYBIND11_MODULE_PYINIT(name, {}, ##__VA_ARGS__) \
::pybind11::detail::embedded_module PYBIND11_CONCAT(pybind11_module_, name)( \
PYBIND11_TOSTRING(name), PYBIND11_CONCAT(PyInit_, name)); \
PYBIND11_MODULE_EXEC(name, variable)
PYBIND11_WARNING_POP
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
PYBIND11_NAMESPACE_BEGIN(detail)
/// Python 2.7/3.x compatible version of `PyImport_AppendInittab` and error checks.
struct embedded_module {
using init_t = PyObject *(*) ();
embedded_module(const char *name, init_t init) {
if (Py_IsInitialized() != 0) {
pybind11_fail("Can't add new modules after the interpreter has been initialized");
}
auto result = PyImport_AppendInittab(name, init);
if (result == -1) {
pybind11_fail("Insufficient memory to add a new module");
}
}
};
struct wide_char_arg_deleter {
void operator()(wchar_t *ptr) const {
// API docs: https://docs.python.org/3/c-api/sys.html#c.Py_DecodeLocale
PyMem_RawFree(ptr);
}
};
inline wchar_t *widen_chars(const char *safe_arg) {
wchar_t *widened_arg = Py_DecodeLocale(safe_arg, nullptr);
return widened_arg;
}
inline void precheck_interpreter() {
if (Py_IsInitialized() != 0) {
pybind11_fail("The interpreter is already running");
}
}
#if !defined(PYBIND11_PYCONFIG_SUPPORT_PY_VERSION_HEX)
# define PYBIND11_PYCONFIG_SUPPORT_PY_VERSION_HEX (0x03080000)
#endif
#if PY_VERSION_HEX < PYBIND11_PYCONFIG_SUPPORT_PY_VERSION_HEX
inline void initialize_interpreter_pre_pyconfig(bool init_signal_handlers,
int argc,
const char *const *argv,
bool add_program_dir_to_path) {
detail::precheck_interpreter();
Py_InitializeEx(init_signal_handlers ? 1 : 0);
auto argv_size = static_cast<size_t>(argc);
// SetArgv* on python 3 takes wchar_t, so we have to convert.
std::unique_ptr<wchar_t *[]> widened_argv(new wchar_t *[argv_size]);
std::vector<std::unique_ptr<wchar_t[], detail::wide_char_arg_deleter>> widened_argv_entries;
widened_argv_entries.reserve(argv_size);
for (size_t ii = 0; ii < argv_size; ++ii) {
widened_argv_entries.emplace_back(detail::widen_chars(argv[ii]));
if (!widened_argv_entries.back()) {
// A null here indicates a character-encoding failure or the python
// interpreter out of memory. Give up.
return;
}
widened_argv[ii] = widened_argv_entries.back().get();
}
auto *pysys_argv = widened_argv.get();
PySys_SetArgvEx(argc, pysys_argv, static_cast<int>(add_program_dir_to_path));
}
#endif
PYBIND11_NAMESPACE_END(detail)
#if PY_VERSION_HEX >= PYBIND11_PYCONFIG_SUPPORT_PY_VERSION_HEX
inline void initialize_interpreter(PyConfig *config,
int argc = 0,
const char *const *argv = nullptr,
bool add_program_dir_to_path = true) {
detail::precheck_interpreter();
PyStatus status = PyConfig_SetBytesArgv(config, argc, const_cast<char *const *>(argv));
if (PyStatus_Exception(status) != 0) {
// A failure here indicates a character-encoding failure or the python
// interpreter out of memory. Give up.
PyConfig_Clear(config);
throw std::runtime_error(PyStatus_IsError(status) != 0 ? status.err_msg
: "Failed to prepare CPython");
}
status = Py_InitializeFromConfig(config);
if (PyStatus_Exception(status) != 0) {
PyConfig_Clear(config);
throw std::runtime_error(PyStatus_IsError(status) != 0 ? status.err_msg
: "Failed to init CPython");
}
if (add_program_dir_to_path) {
PyRun_SimpleString("import sys, os.path; "
"sys.path.insert(0, "
"os.path.abspath(os.path.dirname(sys.argv[0])) "
"if sys.argv and os.path.exists(sys.argv[0]) else '')");
}
PyConfig_Clear(config);
}
#endif
/** \rst
Initialize the Python interpreter. No other pybind11 or CPython API functions can be
called before this is done; with the exception of `PYBIND11_EMBEDDED_MODULE`. The
optional `init_signal_handlers` parameter can be used to skip the registration of
signal handlers (see the `Python documentation`_ for details). Calling this function
again after the interpreter has already been initialized is a fatal error.
If initializing the Python interpreter fails, then the program is terminated. (This
is controlled by the CPython runtime and is an exception to pybind11's normal behavior
of throwing exceptions on errors.)
The remaining optional parameters, `argc`, `argv`, and `add_program_dir_to_path` are
used to populate ``sys.argv`` and ``sys.path``.
See the |PySys_SetArgvEx documentation|_ for details.
.. _Python documentation: https://docs.python.org/3/c-api/init.html#c.Py_InitializeEx
.. |PySys_SetArgvEx documentation| replace:: ``PySys_SetArgvEx`` documentation
.. _PySys_SetArgvEx documentation: https://docs.python.org/3/c-api/init.html#c.PySys_SetArgvEx
\endrst */
inline void initialize_interpreter(bool init_signal_handlers = true,
int argc = 0,
const char *const *argv = nullptr,
bool add_program_dir_to_path = true) {
#if PY_VERSION_HEX < PYBIND11_PYCONFIG_SUPPORT_PY_VERSION_HEX
detail::initialize_interpreter_pre_pyconfig(
init_signal_handlers, argc, argv, add_program_dir_to_path);
#else
PyConfig config;
PyConfig_InitPythonConfig(&config);
// See PR #4473 for background
config.parse_argv = 0;
config.install_signal_handlers = init_signal_handlers ? 1 : 0;
initialize_interpreter(&config, argc, argv, add_program_dir_to_path);
#endif
// There is exactly one interpreter alive currently.
detail::get_num_interpreters_seen() = 1;
}
/** \rst
Shut down the Python interpreter. No pybind11 or CPython API functions can be called
after this. In addition, pybind11 objects must not outlive the interpreter:
.. code-block:: cpp
{ // BAD
py::initialize_interpreter();
auto hello = py::str("Hello, World!");
py::finalize_interpreter();
} // <-- BOOM, hello's destructor is called after interpreter shutdown
{ // GOOD
py::initialize_interpreter();
{ // scoped
auto hello = py::str("Hello, World!");
} // <-- OK, hello is cleaned up properly
py::finalize_interpreter();
}
{ // BETTER
py::scoped_interpreter guard{};
auto hello = py::str("Hello, World!");
}
.. warning::
The interpreter can be restarted by calling `initialize_interpreter` again.
Modules created using pybind11 can be safely re-initialized. However, Python
itself cannot completely unload binary extension modules and there are several
caveats with regard to interpreter restarting. All the details can be found
in the CPython documentation. In short, not all interpreter memory may be
freed, either due to reference cycles or user-created global data.
\endrst */
inline void finalize_interpreter() {
// get rid of any thread-local interpreter cache that currently exists
if (detail::get_num_interpreters_seen() > 1) {
detail::get_internals_pp_manager().unref();
detail::get_local_internals_pp_manager().unref();
// We know there can be no other interpreter alive now, so we can lower the count
detail::get_num_interpreters_seen() = 1;
}
// Re-fetch the internals pointer-to-pointer (but not the internals itself, which might not
// exist). It's possible for the internals to be created during Py_Finalize() (e.g. if a
// py::capsule calls `get_internals()` during destruction), so we get the pointer-pointer here
// and check it after Py_Finalize().
detail::get_internals_pp_manager().get_pp();
detail::get_local_internals_pp_manager().get_pp();
Py_Finalize();
detail::get_internals_pp_manager().destroy();
// Local internals contains data managed by the current interpreter, so we must clear them to
// avoid undefined behaviors when initializing another interpreter
detail::get_local_internals_pp_manager().destroy();
// We know there is no interpreter alive now, so we can reset the count
detail::get_num_interpreters_seen() = 0;
}
/** \rst
Scope guard version of `initialize_interpreter` and `finalize_interpreter`.
This a move-only guard and only a single instance can exist.
See `initialize_interpreter` for a discussion of its constructor arguments.
.. code-block:: cpp
#include <pybind11/embed.h>
int main() {
py::scoped_interpreter guard{};
py::print(Hello, World!);
} // <-- interpreter shutdown
\endrst */
class scoped_interpreter {
public:
explicit scoped_interpreter(bool init_signal_handlers = true,
int argc = 0,
const char *const *argv = nullptr,
bool add_program_dir_to_path = true) {
initialize_interpreter(init_signal_handlers, argc, argv, add_program_dir_to_path);
}
#if PY_VERSION_HEX >= PYBIND11_PYCONFIG_SUPPORT_PY_VERSION_HEX
explicit scoped_interpreter(PyConfig *config,
int argc = 0,
const char *const *argv = nullptr,
bool add_program_dir_to_path = true) {
initialize_interpreter(config, argc, argv, add_program_dir_to_path);
}
#endif
scoped_interpreter(const scoped_interpreter &) = delete;
scoped_interpreter(scoped_interpreter &&other) noexcept { other.is_valid = false; }
scoped_interpreter &operator=(const scoped_interpreter &) = delete;
scoped_interpreter &operator=(scoped_interpreter &&) = delete;
~scoped_interpreter() {
if (is_valid) {
finalize_interpreter();
}
}
private:
bool is_valid = true;
};
PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)

View File

@@ -0,0 +1,161 @@
/*
pybind11/eval.h: Support for evaluating Python expressions and statements
from strings and files
Copyright (c) 2016 Klemens Morgenstern <klemens.morgenstern@ed-chemnitz.de> and
Wenzel Jakob <wenzel.jakob@epfl.ch>
All rights reserved. Use of this source code is governed by a
BSD-style license that can be found in the LICENSE file.
*/
#pragma once
#include "pybind11.h"
#include <utility>
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
PYBIND11_NAMESPACE_BEGIN(detail)
inline void ensure_builtins_in_globals(object &global) {
#if defined(PYPY_VERSION)
// Running exec and eval adds `builtins` module under `__builtins__` key to
// globals if not yet present. Python 3.8 made PyRun_String behave
// similarly. Let's also do that for older versions, for consistency. This
// was missing from PyPy3.8 7.3.7.
if (!global.contains("__builtins__"))
global["__builtins__"] = module_::import(PYBIND11_BUILTINS_MODULE);
#else
(void) global;
#endif
}
PYBIND11_NAMESPACE_END(detail)
enum eval_mode {
/// Evaluate a string containing an isolated expression
eval_expr,
/// Evaluate a string containing a single statement. Returns \c none
eval_single_statement,
/// Evaluate a string containing a sequence of statement. Returns \c none
eval_statements
};
template <eval_mode mode = eval_expr>
object eval(const str &expr, object global = globals(), object local = object()) {
if (!local) {
local = global;
}
detail::ensure_builtins_in_globals(global);
/* PyRun_String does not accept a PyObject / encoding specifier,
this seems to be the only alternative */
std::string buffer = "# -*- coding: utf-8 -*-\n" + (std::string) expr;
int start = 0;
switch (mode) {
case eval_expr:
start = Py_eval_input;
break;
case eval_single_statement:
start = Py_single_input;
break;
case eval_statements:
start = Py_file_input;
break;
default:
pybind11_fail("invalid evaluation mode");
}
PyObject *result = PyRun_String(buffer.c_str(), start, global.ptr(), local.ptr());
if (!result) {
throw error_already_set();
}
return reinterpret_steal<object>(result);
}
template <eval_mode mode = eval_expr, size_t N>
object eval(const char (&s)[N], object global = globals(), object local = object()) {
/* Support raw string literals by removing common leading whitespace */
auto expr = (s[0] == '\n') ? str(module_::import("textwrap").attr("dedent")(s)) : str(s);
return eval<mode>(expr, std::move(global), std::move(local));
}
inline void exec(const str &expr, object global = globals(), object local = object()) {
eval<eval_statements>(expr, std::move(global), std::move(local));
}
template <size_t N>
void exec(const char (&s)[N], object global = globals(), object local = object()) {
eval<eval_statements>(s, std::move(global), std::move(local));
}
#if defined(PYPY_VERSION) || defined(GRAALVM_PYTHON)
template <eval_mode mode = eval_statements>
object eval_file(str, object, object) {
pybind11_fail("eval_file not supported in this interpreter. Use eval");
}
template <eval_mode mode = eval_statements>
object eval_file(str, object) {
pybind11_fail("eval_file not supported in this interpreter. Use eval");
}
template <eval_mode mode = eval_statements>
object eval_file(str) {
pybind11_fail("eval_file not supported in this interpreter. Use eval");
}
#else
template <eval_mode mode = eval_statements>
object eval_file(str fname, object global = globals(), object local = object()) {
if (!local) {
local = global;
}
detail::ensure_builtins_in_globals(global);
int start = 0;
switch (mode) {
case eval_expr:
start = Py_eval_input;
break;
case eval_single_statement:
start = Py_single_input;
break;
case eval_statements:
start = Py_file_input;
break;
default:
pybind11_fail("invalid evaluation mode");
}
int closeFile = 1;
std::string fname_str = (std::string) fname;
FILE *f =
# if PY_VERSION_HEX >= 0x030E0000
Py_fopen(fname.ptr(), "r");
# else
_Py_fopen_obj(fname.ptr(), "r");
# endif
if (!f) {
PyErr_Clear();
pybind11_fail("File \"" + fname_str + "\" could not be opened!");
}
if (!global.contains("__file__")) {
global["__file__"] = std::move(fname);
}
PyObject *result
= PyRun_FileEx(f, fname_str.c_str(), start, global.ptr(), local.ptr(), closeFile);
if (!result) {
throw error_already_set();
}
return reinterpret_steal<object>(result);
}
#endif
PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)

View File

@@ -0,0 +1,147 @@
/*
pybind11/functional.h: std::function<> support
Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch>
All rights reserved. Use of this source code is governed by a
BSD-style license that can be found in the LICENSE file.
*/
#pragma once
#include "pybind11.h"
#include <functional>
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
PYBIND11_NAMESPACE_BEGIN(detail)
PYBIND11_NAMESPACE_BEGIN(type_caster_std_function_specializations)
// ensure GIL is held during functor destruction
struct func_handle {
function f;
#if !(defined(_MSC_VER) && _MSC_VER == 1916 && defined(PYBIND11_CPP17))
// This triggers a syntax error under very special conditions (very weird indeed).
explicit
#endif
func_handle(function &&f_) noexcept
: f(std::move(f_)) {
}
func_handle(const func_handle &f_) { operator=(f_); }
func_handle &operator=(const func_handle &f_) {
gil_scoped_acquire acq;
f = f_.f;
return *this;
}
~func_handle() {
gil_scoped_acquire acq;
function kill_f(std::move(f));
}
};
// to emulate 'move initialization capture' in C++11
struct func_wrapper_base {
func_handle hfunc;
explicit func_wrapper_base(func_handle &&hf) noexcept : hfunc(hf) {}
};
template <typename Return, typename... Args>
struct func_wrapper : func_wrapper_base {
using func_wrapper_base::func_wrapper_base;
Return operator()(Args... args) const { // NOLINT(performance-unnecessary-value-param)
gil_scoped_acquire acq;
// casts the returned object as a rvalue to the return type
return hfunc.f(std::forward<Args>(args)...).template cast<Return>();
}
};
PYBIND11_NAMESPACE_END(type_caster_std_function_specializations)
template <typename Return, typename... Args>
struct type_caster<std::function<Return(Args...)>> {
using type = std::function<Return(Args...)>;
using retval_type = conditional_t<std::is_same<Return, void>::value, void_type, Return>;
using function_type = Return (*)(Args...);
public:
bool load(handle src, bool convert) {
if (src.is_none()) {
// Defer accepting None to other overloads (if we aren't in convert mode):
if (!convert) {
return false;
}
return true;
}
if (!isinstance<function>(src)) {
return false;
}
auto func = reinterpret_borrow<function>(src);
/*
When passing a C++ function as an argument to another C++
function via Python, every function call would normally involve
a full C++ -> Python -> C++ roundtrip, which can be prohibitive.
Here, we try to at least detect the case where the function is
stateless (i.e. function pointer or lambda function without
captured variables), in which case the roundtrip can be avoided.
*/
if (auto cfunc = func.cpp_function()) {
auto *cfunc_self = PyCFunction_GET_SELF(cfunc.ptr());
if (cfunc_self == nullptr) {
PyErr_Clear();
} else {
function_record *rec = function_record_ptr_from_PyObject(cfunc_self);
while (rec != nullptr) {
if (rec->is_stateless
&& same_type(typeid(function_type),
*reinterpret_cast<const std::type_info *>(rec->data[1]))) {
struct capture {
function_type f;
static capture *from_data(void **data) {
return PYBIND11_STD_LAUNDER(reinterpret_cast<capture *>(data));
}
};
PYBIND11_ENSURE_PRECONDITION_FOR_FUNCTIONAL_H_PERFORMANCE_OPTIMIZATIONS(
std::is_standard_layout<capture>::value);
value = capture::from_data(rec->data)->f;
return true;
}
rec = rec->next;
}
}
// PYPY segfaults here when passing builtin function like sum.
// Raising an fail exception here works to prevent the segfault, but only on gcc.
// See PR #1413 for full details
}
value = type_caster_std_function_specializations::func_wrapper<Return, Args...>(
type_caster_std_function_specializations::func_handle(std::move(func)));
return true;
}
template <typename Func>
static handle cast(Func &&f_, return_value_policy policy, handle /* parent */) {
if (!f_) {
return none().release();
}
auto result = f_.template target<function_type>();
if (result) {
return cpp_function(*result, policy).release();
}
return cpp_function(std::forward<Func>(f_), policy).release();
}
PYBIND11_TYPE_CASTER(
type,
const_name("collections.abc.Callable[[")
+ ::pybind11::detail::concat(::pybind11::detail::arg_descr(make_caster<Args>::name)...)
+ const_name("], ") + ::pybind11::detail::return_descr(make_caster<retval_type>::name)
+ const_name("]"));
};
PYBIND11_NAMESPACE_END(detail)
PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)

View File

@@ -0,0 +1,199 @@
/*
pybind11/gil.h: RAII helpers for managing the GIL
Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch>
All rights reserved. Use of this source code is governed by a
BSD-style license that can be found in the LICENSE file.
*/
#pragma once
#if defined(PYBIND11_SIMPLE_GIL_MANAGEMENT)
# include "detail/common.h"
# include "gil_simple.h"
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
using gil_scoped_acquire = gil_scoped_acquire_simple;
using gil_scoped_release = gil_scoped_release_simple;
PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)
#else
# include "detail/common.h"
# include "detail/internals.h"
# include <cassert>
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
PYBIND11_NAMESPACE_BEGIN(detail)
PYBIND11_WARNING_PUSH
PYBIND11_WARNING_DISABLE_GCC("-Wredundant-decls")
// forward declarations
PyThreadState *get_thread_state_unchecked();
PYBIND11_WARNING_POP
PYBIND11_NAMESPACE_END(detail)
/* The functions below essentially reproduce the PyGILState_* API using a RAII
* pattern, but there are a few important differences:
*
* 1. When acquiring the GIL from an non-main thread during the finalization
* phase, the GILState API blindly terminates the calling thread, which
* is often not what is wanted. This API does not do this.
*
* 2. The gil_scoped_release function can optionally cut the relationship
* of a PyThreadState and its associated thread, which allows moving it to
* another thread (this is a fairly rare/advanced use case).
*
* 3. The reference count of an acquired thread state can be controlled. This
* can be handy to prevent cases where callbacks issued from an external
* thread would otherwise constantly construct and destroy thread state data
* structures.
*
* See the Python bindings of NanoGUI (http://github.com/wjakob/nanogui) for an
* example which uses features 2 and 3 to migrate the Python thread of
* execution to another thread (to run the event loop on the original thread,
* in this case).
*/
class gil_scoped_acquire {
public:
PYBIND11_NOINLINE gil_scoped_acquire() {
auto &internals = detail::get_internals();
tstate = internals.tstate.get();
if (!tstate) {
/* Check if the GIL was acquired using the PyGILState_* API instead (e.g. if
calling from a Python thread). Since we use a different key, this ensures
we don't create a new thread state and deadlock in PyEval_AcquireThread
below. Note we don't save this state with internals.tstate, since we don't
create it we would fail to clear it (its reference count should be > 0). */
tstate = PyGILState_GetThisThreadState();
}
if (!tstate) {
tstate = PyThreadState_New(internals.istate);
# if defined(PYBIND11_DETAILED_ERROR_MESSAGES)
if (!tstate) {
pybind11_fail("scoped_acquire: could not create thread state!");
}
# endif
tstate->gilstate_counter = 0;
internals.tstate = tstate;
} else {
release = detail::get_thread_state_unchecked() != tstate;
}
if (release) {
PyEval_AcquireThread(tstate);
}
inc_ref();
}
gil_scoped_acquire(const gil_scoped_acquire &) = delete;
gil_scoped_acquire &operator=(const gil_scoped_acquire &) = delete;
void inc_ref() { ++tstate->gilstate_counter; }
PYBIND11_NOINLINE void dec_ref() {
--tstate->gilstate_counter;
# if defined(PYBIND11_DETAILED_ERROR_MESSAGES)
if (detail::get_thread_state_unchecked() != tstate) {
pybind11_fail("scoped_acquire::dec_ref(): thread state must be current!");
}
if (tstate->gilstate_counter < 0) {
pybind11_fail("scoped_acquire::dec_ref(): reference count underflow!");
}
# endif
if (tstate->gilstate_counter == 0) {
# if defined(PYBIND11_DETAILED_ERROR_MESSAGES)
if (!release) {
pybind11_fail("scoped_acquire::dec_ref(): internal error!");
}
# endif
PyThreadState_Clear(tstate);
if (active) {
PyThreadState_DeleteCurrent();
}
detail::get_internals().tstate.reset();
release = false;
}
}
/// This method will disable the PyThreadState_DeleteCurrent call and the
/// GIL won't be released. This method should be used if the interpreter
/// could be shutting down when this is called, as thread deletion is not
/// allowed during shutdown. Check _Py_IsFinalizing() on Python 3.7+, and
/// protect subsequent code.
PYBIND11_NOINLINE void disarm() { active = false; }
PYBIND11_NOINLINE ~gil_scoped_acquire() {
dec_ref();
if (release) {
PyEval_SaveThread();
}
}
private:
PyThreadState *tstate = nullptr;
bool release = true;
bool active = true;
};
class gil_scoped_release {
public:
// PRECONDITION: The GIL must be held when this constructor is called.
explicit gil_scoped_release(bool disassoc = false) : disassoc(disassoc) {
assert(PyGILState_Check());
// `get_internals()` must be called here unconditionally in order to initialize
// `internals.tstate` for subsequent `gil_scoped_acquire` calls. Otherwise, an
// initialization race could occur as multiple threads try `gil_scoped_acquire`.
auto &internals = detail::get_internals();
// NOLINTNEXTLINE(cppcoreguidelines-prefer-member-initializer)
tstate = PyEval_SaveThread();
if (disassoc) {
internals.tstate.reset();
}
}
gil_scoped_release(const gil_scoped_release &) = delete;
gil_scoped_release &operator=(const gil_scoped_release &) = delete;
/// This method will disable the PyThreadState_DeleteCurrent call and the
/// GIL won't be acquired. This method should be used if the interpreter
/// could be shutting down when this is called, as thread deletion is not
/// allowed during shutdown. Check _Py_IsFinalizing() on Python 3.7+, and
/// protect subsequent code.
PYBIND11_NOINLINE void disarm() { active = false; }
~gil_scoped_release() {
if (!tstate) {
return;
}
// `PyEval_RestoreThread()` should not be called if runtime is finalizing
if (active) {
PyEval_RestoreThread(tstate);
}
if (disassoc) {
detail::get_internals().tstate = tstate;
}
}
private:
PyThreadState *tstate;
bool disassoc;
bool active = true;
};
PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)
#endif // !PYBIND11_SIMPLE_GIL_MANAGEMENT

View File

@@ -0,0 +1,102 @@
// Copyright (c) 2023 The pybind Community.
#pragma once
#include "detail/common.h"
#include "gil.h"
#include <cassert>
#include <mutex>
#ifdef Py_GIL_DISABLED
# include <atomic>
#endif
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
// Use the `gil_safe_call_once_and_store` class below instead of the naive
//
// static auto imported_obj = py::module_::import("module_name"); // BAD, DO NOT USE!
//
// which has two serious issues:
//
// 1. Py_DECREF() calls potentially after the Python interpreter was finalized already, and
// 2. deadlocks in multi-threaded processes (because of missing lock ordering).
//
// The following alternative avoids both problems:
//
// PYBIND11_CONSTINIT static py::gil_safe_call_once_and_store<py::object> storage;
// auto &imported_obj = storage // Do NOT make this `static`!
// .call_once_and_store_result([]() {
// return py::module_::import("module_name");
// })
// .get_stored();
//
// The parameter of `call_once_and_store_result()` must be callable. It can make
// CPython API calls, and in particular, it can temporarily release the GIL.
//
// `T` can be any C++ type, it does not have to involve CPython API types.
//
// The behavior with regard to signals, e.g. `SIGINT` (`KeyboardInterrupt`),
// is not ideal. If the main thread is the one to actually run the `Callable`,
// then a `KeyboardInterrupt` will interrupt it if it is running normal Python
// code. The situation is different if a non-main thread runs the
// `Callable`, and then the main thread starts waiting for it to complete:
// a `KeyboardInterrupt` will not interrupt the non-main thread, but it will
// get processed only when it is the main thread's turn again and it is running
// normal Python code. However, this will be unnoticeable for quick call-once
// functions, which is usually the case.
//
// For in-depth background, see docs/advanced/deadlock.md
template <typename T>
class gil_safe_call_once_and_store {
public:
// PRECONDITION: The GIL must be held when `call_once_and_store_result()` is called.
template <typename Callable>
gil_safe_call_once_and_store &call_once_and_store_result(Callable &&fn) {
if (!is_initialized_) { // This read is guarded by the GIL.
// Multiple threads may enter here, because the GIL is released in the next line and
// CPython API calls in the `fn()` call below may release and reacquire the GIL.
gil_scoped_release gil_rel; // Needed to establish lock ordering.
std::call_once(once_flag_, [&] {
// Only one thread will ever enter here.
gil_scoped_acquire gil_acq;
::new (storage_) T(fn()); // fn may release, but will reacquire, the GIL.
is_initialized_ = true; // This write is guarded by the GIL.
});
// All threads will observe `is_initialized_` as true here.
}
// Intentionally not returning `T &` to ensure the calling code is self-documenting.
return *this;
}
// This must only be called after `call_once_and_store_result()` was called.
T &get_stored() {
assert(is_initialized_);
PYBIND11_WARNING_PUSH
#if !defined(__clang__) && defined(__GNUC__) && __GNUC__ < 5
// Needed for gcc 4.8.5
PYBIND11_WARNING_DISABLE_GCC("-Wstrict-aliasing")
#endif
return *reinterpret_cast<T *>(storage_);
PYBIND11_WARNING_POP
}
constexpr gil_safe_call_once_and_store() = default;
PYBIND11_DTOR_CONSTEXPR ~gil_safe_call_once_and_store() = default;
private:
alignas(T) char storage_[sizeof(T)] = {};
std::once_flag once_flag_ = {};
#ifdef Py_GIL_DISABLED
std::atomic_bool
#else
bool
#endif
is_initialized_{false};
// The `is_initialized_`-`storage_` pair is very similar to `std::optional`,
// but the latter does not have the triviality properties of former,
// therefore `std::optional` is not a viable alternative here.
};
PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)

View File

@@ -0,0 +1,37 @@
// Copyright (c) 2016-2025 The Pybind Development Team.
// All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
#pragma once
#include "detail/common.h"
#include <cassert>
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
class gil_scoped_acquire_simple {
PyGILState_STATE state;
public:
gil_scoped_acquire_simple() : state{PyGILState_Ensure()} {}
gil_scoped_acquire_simple(const gil_scoped_acquire_simple &) = delete;
gil_scoped_acquire_simple &operator=(const gil_scoped_acquire_simple &) = delete;
~gil_scoped_acquire_simple() { PyGILState_Release(state); }
};
class gil_scoped_release_simple {
PyThreadState *state;
public:
// PRECONDITION: The GIL must be held when this constructor is called.
gil_scoped_release_simple() {
assert(PyGILState_Check());
state = PyEval_SaveThread();
}
gil_scoped_release_simple(const gil_scoped_release_simple &) = delete;
gil_scoped_release_simple &operator=(const gil_scoped_release_simple &) = delete;
~gil_scoped_release_simple() { PyEval_RestoreThread(state); }
};
PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)

View File

@@ -0,0 +1,265 @@
/*
pybind11/iostream.h -- Tools to assist with redirecting cout and cerr to Python
Copyright (c) 2017 Henry F. Schreiner
All rights reserved. Use of this source code is governed by a
BSD-style license that can be found in the LICENSE file.
WARNING: The implementation in this file is NOT thread safe. Multiple
threads writing to a redirected ostream concurrently cause data races
and potentially buffer overflows. Therefore it is currently a requirement
that all (possibly) concurrent redirected ostream writes are protected by
a mutex.
#HelpAppreciated: Work on iostream.h thread safety.
For more background see the discussions under
https://github.com/pybind/pybind11/pull/2982 and
https://github.com/pybind/pybind11/pull/2995.
*/
#pragma once
#include "pybind11.h"
#include <algorithm>
#include <cstring>
#include <iostream>
#include <iterator>
#include <memory>
#include <ostream>
#include <streambuf>
#include <string>
#include <utility>
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
PYBIND11_NAMESPACE_BEGIN(detail)
// Buffer that writes to Python instead of C++
class pythonbuf : public std::streambuf {
private:
using traits_type = std::streambuf::traits_type;
const size_t buf_size;
std::unique_ptr<char[]> d_buffer;
object pywrite;
object pyflush;
int overflow(int c) override {
if (!traits_type::eq_int_type(c, traits_type::eof())) {
*pptr() = traits_type::to_char_type(c);
pbump(1);
}
return sync() == 0 ? traits_type::not_eof(c) : traits_type::eof();
}
// Computes how many bytes at the end of the buffer are part of an
// incomplete sequence of UTF-8 bytes.
// Precondition: pbase() < pptr()
size_t utf8_remainder() const {
const auto rbase = std::reverse_iterator<char *>(pbase());
const auto rpptr = std::reverse_iterator<char *>(pptr());
auto is_ascii = [](char c) { return (static_cast<unsigned char>(c) & 0x80) == 0x00; };
auto is_leading = [](char c) { return (static_cast<unsigned char>(c) & 0xC0) == 0xC0; };
auto is_leading_2b = [](char c) { return static_cast<unsigned char>(c) <= 0xDF; };
auto is_leading_3b = [](char c) { return static_cast<unsigned char>(c) <= 0xEF; };
// If the last character is ASCII, there are no incomplete code points
if (is_ascii(*rpptr)) {
return 0;
}
// Otherwise, work back from the end of the buffer and find the first
// UTF-8 leading byte
const auto rpend = rbase - rpptr >= 3 ? rpptr + 3 : rbase;
const auto leading = std::find_if(rpptr, rpend, is_leading);
if (leading == rbase) {
return 0;
}
const auto dist = static_cast<size_t>(leading - rpptr);
size_t remainder = 0;
if (dist == 0) {
remainder = 1; // 1-byte code point is impossible
} else if (dist == 1) {
remainder = is_leading_2b(*leading) ? 0 : dist + 1;
} else if (dist == 2) {
remainder = is_leading_3b(*leading) ? 0 : dist + 1;
}
// else if (dist >= 3), at least 4 bytes before encountering an UTF-8
// leading byte, either no remainder or invalid UTF-8.
// Invalid UTF-8 will cause an exception later when converting
// to a Python string, so that's not handled here.
return remainder;
}
// This function must be non-virtual to be called in a destructor.
int _sync() {
if (pbase() != pptr()) { // If buffer is not empty
gil_scoped_acquire tmp;
// This subtraction cannot be negative, so dropping the sign.
auto size = static_cast<size_t>(pptr() - pbase());
size_t remainder = utf8_remainder();
if (size > remainder) {
str line(pbase(), size - remainder);
pywrite(std::move(line));
pyflush();
}
// Copy the remainder at the end of the buffer to the beginning:
if (remainder > 0) {
std::memmove(pbase(), pptr() - remainder, remainder);
}
setp(pbase(), epptr());
pbump(static_cast<int>(remainder));
}
return 0;
}
int sync() override { return _sync(); }
public:
explicit pythonbuf(const object &pyostream, size_t buffer_size = 1024)
: buf_size(buffer_size), d_buffer(new char[buf_size]), pywrite(pyostream.attr("write")),
pyflush(pyostream.attr("flush")) {
setp(d_buffer.get(), d_buffer.get() + buf_size - 1);
}
pythonbuf(pythonbuf &&) = default;
/// Sync before destroy
~pythonbuf() override { _sync(); }
};
PYBIND11_NAMESPACE_END(detail)
/** \rst
This a move-only guard that redirects output.
.. code-block:: cpp
#include <pybind11/iostream.h>
...
{
py::scoped_ostream_redirect output;
std::cout << "Hello, World!"; // Python stdout
} // <-- return std::cout to normal
You can explicitly pass the c++ stream and the python object,
for example to guard stderr instead.
.. code-block:: cpp
{
py::scoped_ostream_redirect output{
std::cerr, py::module::import("sys").attr("stderr")};
std::cout << "Hello, World!";
}
\endrst */
class scoped_ostream_redirect {
protected:
std::streambuf *old;
std::ostream &costream;
detail::pythonbuf buffer;
public:
explicit scoped_ostream_redirect(std::ostream &costream = std::cout,
const object &pyostream
= module_::import("sys").attr("stdout"))
: costream(costream), buffer(pyostream) {
old = costream.rdbuf(&buffer);
}
~scoped_ostream_redirect() { costream.rdbuf(old); }
scoped_ostream_redirect(const scoped_ostream_redirect &) = delete;
scoped_ostream_redirect(scoped_ostream_redirect &&other) = default;
scoped_ostream_redirect &operator=(const scoped_ostream_redirect &) = delete;
scoped_ostream_redirect &operator=(scoped_ostream_redirect &&) = delete;
};
/** \rst
Like `scoped_ostream_redirect`, but redirects cerr by default. This class
is provided primary to make ``py::call_guard`` easier to make.
.. code-block:: cpp
m.def("noisy_func", &noisy_func,
py::call_guard<scoped_ostream_redirect,
scoped_estream_redirect>());
\endrst */
class scoped_estream_redirect : public scoped_ostream_redirect {
public:
explicit scoped_estream_redirect(std::ostream &costream = std::cerr,
const object &pyostream
= module_::import("sys").attr("stderr"))
: scoped_ostream_redirect(costream, pyostream) {}
};
PYBIND11_NAMESPACE_BEGIN(detail)
// Class to redirect output as a context manager. C++ backend.
class OstreamRedirect {
bool do_stdout_;
bool do_stderr_;
std::unique_ptr<scoped_ostream_redirect> redirect_stdout;
std::unique_ptr<scoped_estream_redirect> redirect_stderr;
public:
explicit OstreamRedirect(bool do_stdout = true, bool do_stderr = true)
: do_stdout_(do_stdout), do_stderr_(do_stderr) {}
void enter() {
if (do_stdout_) {
redirect_stdout.reset(new scoped_ostream_redirect());
}
if (do_stderr_) {
redirect_stderr.reset(new scoped_estream_redirect());
}
}
void exit() {
redirect_stdout.reset();
redirect_stderr.reset();
}
};
PYBIND11_NAMESPACE_END(detail)
/** \rst
This is a helper function to add a C++ redirect context manager to Python
instead of using a C++ guard. To use it, add the following to your binding code:
.. code-block:: cpp
#include <pybind11/iostream.h>
...
py::add_ostream_redirect(m, "ostream_redirect");
You now have a Python context manager that redirects your output:
.. code-block:: python
with m.ostream_redirect():
m.print_to_cout_function()
This manager can optionally be told which streams to operate on:
.. code-block:: python
with m.ostream_redirect(stdout=true, stderr=true):
m.noisy_function_with_error_printing()
\endrst */
inline class_<detail::OstreamRedirect>
add_ostream_redirect(module_ m, const std::string &name = "ostream_redirect") {
return class_<detail::OstreamRedirect>(std::move(m), name.c_str(), module_local())
.def(init<bool, bool>(), arg("stdout") = true, arg("stderr") = true)
.def("__enter__", &detail::OstreamRedirect::enter)
.def("__exit__", [](detail::OstreamRedirect &self_, const args &) { self_.exit(); });
}
PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)

View File

@@ -0,0 +1,67 @@
// Copyright (c) 2022-2025 The pybind Community.
// All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
#pragma once
#include "detail/common.h"
#include "detail/native_enum_data.h"
#include "detail/type_caster_base.h"
#include "cast.h"
#include <cassert>
#include <limits>
#include <type_traits>
#include <typeindex>
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
/// Conversions between Python's native (stdlib) enum types and C++ enums.
template <typename EnumType>
class native_enum : public detail::native_enum_data {
public:
using Underlying = typename std::underlying_type<EnumType>::type;
native_enum(const object &parent_scope,
const char *name,
const char *native_type_name,
const char *class_doc = "")
: detail::native_enum_data(
parent_scope, name, native_type_name, class_doc, std::type_index(typeid(EnumType))) {
if (detail::get_local_type_info(typeid(EnumType)) != nullptr
|| detail::get_global_type_info(typeid(EnumType)) != nullptr) {
pybind11_fail(
"pybind11::native_enum<...>(\"" + enum_name_encoded
+ "\") is already registered as a `pybind11::enum_` or `pybind11::class_`!");
}
if (detail::global_internals_native_enum_type_map_contains(enum_type_index)) {
pybind11_fail("pybind11::native_enum<...>(\"" + enum_name_encoded
+ "\") is already registered!");
}
arm_finalize_check();
}
/// Export enumeration entries into the parent scope
native_enum &export_values() {
assert(!export_values_flag); // Catch redundant calls.
export_values_flag = true;
return *this;
}
/// Add an enumeration entry
native_enum &value(char const *name, EnumType value, const char *doc = nullptr) {
// Disarm for the case that the native_enum_data dtor runs during exception unwinding.
disarm_finalize_check("value after finalize");
members.append(make_tuple(name, static_cast<Underlying>(value)));
if (doc) {
member_docs.append(make_tuple(name, doc));
}
arm_finalize_check(); // There was no exception.
return *this;
}
native_enum(const native_enum &) = delete;
native_enum &operator=(const native_enum &) = delete;
};
PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,202 @@
/*
pybind11/operator.h: Metatemplates for operator overloading
Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch>
All rights reserved. Use of this source code is governed by a
BSD-style license that can be found in the LICENSE file.
*/
#pragma once
#include "pybind11.h"
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
PYBIND11_NAMESPACE_BEGIN(detail)
/// Enumeration with all supported operator types
enum op_id : int {
op_add,
op_sub,
op_mul,
op_div,
op_mod,
op_divmod,
op_pow,
op_lshift,
op_rshift,
op_and,
op_xor,
op_or,
op_neg,
op_pos,
op_abs,
op_invert,
op_int,
op_long,
op_float,
op_str,
op_cmp,
op_gt,
op_ge,
op_lt,
op_le,
op_eq,
op_ne,
op_iadd,
op_isub,
op_imul,
op_idiv,
op_imod,
op_ilshift,
op_irshift,
op_iand,
op_ixor,
op_ior,
op_complex,
op_bool,
op_nonzero,
op_repr,
op_truediv,
op_itruediv,
op_hash
};
enum op_type : int {
op_l, /* base type on left */
op_r, /* base type on right */
op_u /* unary operator */
};
struct self_t {};
static const self_t self = self_t();
/// Type for an unused type slot
struct undefined_t {};
/// Don't warn about an unused variable
inline self_t __self() { return self; }
/// base template of operator implementations
template <op_id, op_type, typename B, typename L, typename R>
struct op_impl {};
/// Operator implementation generator
template <op_id id, op_type ot, typename L, typename R>
struct op_ {
static constexpr bool op_enable_if_hook = true;
template <typename Class, typename... Extra>
void execute(Class &cl, const Extra &...extra) const {
using Base = typename Class::type;
using L_type = conditional_t<std::is_same<L, self_t>::value, Base, L>;
using R_type = conditional_t<std::is_same<R, self_t>::value, Base, R>;
using op = op_impl<id, ot, Base, L_type, R_type>;
cl.def(op::name(), &op::execute, is_operator(), extra...);
}
template <typename Class, typename... Extra>
void execute_cast(Class &cl, const Extra &...extra) const {
using Base = typename Class::type;
using L_type = conditional_t<std::is_same<L, self_t>::value, Base, L>;
using R_type = conditional_t<std::is_same<R, self_t>::value, Base, R>;
using op = op_impl<id, ot, Base, L_type, R_type>;
cl.def(op::name(), &op::execute_cast, is_operator(), extra...);
}
};
#define PYBIND11_BINARY_OPERATOR(id, rid, op, expr) \
template <typename B, typename L, typename R> \
struct op_impl<op_##id, op_l, B, L, R> { \
static char const *name() { return "__" #id "__"; } \
static auto execute(const L &l, const R &r) -> decltype(expr) { return (expr); } \
static B execute_cast(const L &l, const R &r) { return B(expr); } \
}; \
template <typename B, typename L, typename R> \
struct op_impl<op_##id, op_r, B, L, R> { \
static char const *name() { return "__" #rid "__"; } \
static auto execute(const R &r, const L &l) -> decltype(expr) { return (expr); } \
static B execute_cast(const R &r, const L &l) { return B(expr); } \
}; \
inline op_<op_##id, op_l, self_t, self_t> op(const self_t &, const self_t &) { \
return op_<op_##id, op_l, self_t, self_t>(); \
} \
template <typename T> \
op_<op_##id, op_l, self_t, T> op(const self_t &, const T &) { \
return op_<op_##id, op_l, self_t, T>(); \
} \
template <typename T> \
op_<op_##id, op_r, T, self_t> op(const T &, const self_t &) { \
return op_<op_##id, op_r, T, self_t>(); \
}
#define PYBIND11_INPLACE_OPERATOR(id, op, expr) \
template <typename B, typename L, typename R> \
struct op_impl<op_##id, op_l, B, L, R> { \
static char const *name() { return "__" #id "__"; } \
static auto execute(L &l, const R &r) -> decltype(expr) { return expr; } \
static B execute_cast(L &l, const R &r) { return B(expr); } \
}; \
template <typename T> \
op_<op_##id, op_l, self_t, T> op(const self_t &, const T &) { \
return op_<op_##id, op_l, self_t, T>(); \
}
#define PYBIND11_UNARY_OPERATOR(id, op, expr) \
template <typename B, typename L> \
struct op_impl<op_##id, op_u, B, L, undefined_t> { \
static char const *name() { return "__" #id "__"; } \
static auto execute(const L &l) -> decltype(expr) { return expr; } \
static B execute_cast(const L &l) { return B(expr); } \
}; \
inline op_<op_##id, op_u, self_t, undefined_t> op(const self_t &) { \
return op_<op_##id, op_u, self_t, undefined_t>(); \
}
PYBIND11_BINARY_OPERATOR(sub, rsub, operator-, l - r)
PYBIND11_BINARY_OPERATOR(add, radd, operator+, l + r)
PYBIND11_BINARY_OPERATOR(mul, rmul, operator*, l *r)
PYBIND11_BINARY_OPERATOR(truediv, rtruediv, operator/, l / r)
PYBIND11_BINARY_OPERATOR(mod, rmod, operator%, l % r)
PYBIND11_BINARY_OPERATOR(lshift, rlshift, operator<<, l << r)
PYBIND11_BINARY_OPERATOR(rshift, rrshift, operator>>, l >> r)
PYBIND11_BINARY_OPERATOR(and, rand, operator&, l &r)
PYBIND11_BINARY_OPERATOR(xor, rxor, operator^, l ^ r)
PYBIND11_BINARY_OPERATOR(eq, eq, operator==, l == r)
PYBIND11_BINARY_OPERATOR(ne, ne, operator!=, l != r)
PYBIND11_BINARY_OPERATOR(or, ror, operator|, l | r)
PYBIND11_BINARY_OPERATOR(gt, lt, operator>, l > r)
PYBIND11_BINARY_OPERATOR(ge, le, operator>=, l >= r)
PYBIND11_BINARY_OPERATOR(lt, gt, operator<, l < r)
PYBIND11_BINARY_OPERATOR(le, ge, operator<=, l <= r)
// PYBIND11_BINARY_OPERATOR(pow, rpow, pow, std::pow(l, r))
PYBIND11_INPLACE_OPERATOR(iadd, operator+=, l += r)
PYBIND11_INPLACE_OPERATOR(isub, operator-=, l -= r)
PYBIND11_INPLACE_OPERATOR(imul, operator*=, l *= r)
PYBIND11_INPLACE_OPERATOR(itruediv, operator/=, l /= r)
PYBIND11_INPLACE_OPERATOR(imod, operator%=, l %= r)
PYBIND11_INPLACE_OPERATOR(ilshift, operator<<=, l <<= r)
PYBIND11_INPLACE_OPERATOR(irshift, operator>>=, l >>= r)
PYBIND11_INPLACE_OPERATOR(iand, operator&=, l &= r)
PYBIND11_INPLACE_OPERATOR(ixor, operator^=, l ^= r)
PYBIND11_INPLACE_OPERATOR(ior, operator|=, l |= r)
PYBIND11_UNARY_OPERATOR(neg, operator-, -l)
PYBIND11_UNARY_OPERATOR(pos, operator+, +l)
// WARNING: This usage of `abs` should only be done for existing STL overloads.
// Adding overloads directly in to the `std::` namespace is advised against:
// https://en.cppreference.com/w/cpp/language/extending_std
PYBIND11_UNARY_OPERATOR(abs, abs, std::abs(l))
PYBIND11_UNARY_OPERATOR(hash, hash, std::hash<L>()(l))
PYBIND11_UNARY_OPERATOR(invert, operator~, (~l))
PYBIND11_UNARY_OPERATOR(bool, operator!, !!l)
PYBIND11_UNARY_OPERATOR(int, int_, (int) l)
PYBIND11_UNARY_OPERATOR(float, float_, (double) l)
#undef PYBIND11_BINARY_OPERATOR
#undef PYBIND11_INPLACE_OPERATOR
#undef PYBIND11_UNARY_OPERATOR
PYBIND11_NAMESPACE_END(detail)
using detail::self;
// Add named operators so that they are accessible via `py::`.
using detail::hash;
PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)

View File

@@ -0,0 +1,92 @@
/*
pybind11/options.h: global settings that are configurable at runtime.
Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch>
All rights reserved. Use of this source code is governed by a
BSD-style license that can be found in the LICENSE file.
*/
#pragma once
#include "detail/common.h"
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
class options {
public:
// Default RAII constructor, which leaves settings as they currently are.
options() : previous_state(global_state()) {}
// Class is non-copyable.
options(const options &) = delete;
options &operator=(const options &) = delete;
// Destructor, which restores settings that were in effect before.
~options() { global_state() = previous_state; }
// Setter methods (affect the global state):
options &disable_user_defined_docstrings() & {
global_state().show_user_defined_docstrings = false;
return *this;
}
options &enable_user_defined_docstrings() & {
global_state().show_user_defined_docstrings = true;
return *this;
}
options &disable_function_signatures() & {
global_state().show_function_signatures = false;
return *this;
}
options &enable_function_signatures() & {
global_state().show_function_signatures = true;
return *this;
}
options &disable_enum_members_docstring() & {
global_state().show_enum_members_docstring = false;
return *this;
}
options &enable_enum_members_docstring() & {
global_state().show_enum_members_docstring = true;
return *this;
}
// Getter methods (return the global state):
static bool show_user_defined_docstrings() {
return global_state().show_user_defined_docstrings;
}
static bool show_function_signatures() { return global_state().show_function_signatures; }
static bool show_enum_members_docstring() {
return global_state().show_enum_members_docstring;
}
// This type is not meant to be allocated on the heap.
void *operator new(size_t) = delete;
private:
struct state {
bool show_user_defined_docstrings = true; //< Include user-supplied texts in docstrings.
bool show_function_signatures = true; //< Include auto-generated function signatures
// in docstrings.
bool show_enum_members_docstring = true; //< Include auto-generated member list in enum
// docstrings.
};
static state &global_state() {
static state instance;
return instance;
}
state previous_state;
};
PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,666 @@
/*
pybind11/stl.h: Transparent conversion for STL data types
Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch>
All rights reserved. Use of this source code is governed by a
BSD-style license that can be found in the LICENSE file.
*/
#pragma once
#include "pybind11.h"
#include "detail/common.h"
#include "detail/descr.h"
#include "detail/type_caster_base.h"
#include <deque>
#include <initializer_list>
#include <list>
#include <map>
#include <memory>
#include <ostream>
#include <set>
#include <unordered_map>
#include <unordered_set>
#include <valarray>
// See `detail/common.h` for implementation of these guards.
#if defined(PYBIND11_HAS_OPTIONAL)
# include <optional>
#elif defined(PYBIND11_HAS_EXP_OPTIONAL)
# include <experimental/optional>
#endif
#if defined(PYBIND11_HAS_VARIANT)
# include <variant>
#endif
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
PYBIND11_NAMESPACE_BEGIN(detail)
//
// Begin: Equivalent of
// https://github.com/google/clif/blob/ae4eee1de07cdf115c0c9bf9fec9ff28efce6f6c/clif/python/runtime.cc#L388-L438
/*
The three `object_is_convertible_to_*()` functions below are
the result of converging the behaviors of pybind11 and PyCLIF
(http://github.com/google/clif).
Originally PyCLIF was extremely far on the permissive side of the spectrum,
while pybind11 was very far on the strict side. Originally PyCLIF accepted any
Python iterable as input for a C++ `vector`/`set`/`map` argument, as long as
the elements were convertible. The obvious (in hindsight) problem was that
any empty Python iterable could be passed to any of these C++ types, e.g. `{}`
was accepted for C++ `vector`/`set` arguments, or `[]` for C++ `map` arguments.
The functions below strike a practical permissive-vs-strict compromise,
informed by tens of thousands of use cases in the wild. A main objective is
to prevent accidents and improve readability:
- Python literals must match the C++ types.
- For C++ `set`: The potentially reducing conversion from a Python sequence
(e.g. Python `list` or `tuple`) to a C++ `set` must be explicit, by going
through a Python `set`.
- However, a Python `set` can still be passed to a C++ `vector`. The rationale
is that this conversion is not reducing. Implicit conversions of this kind
are also fairly commonly used, therefore enforcing explicit conversions
would have an unfavorable cost : benefit ratio; more sloppily speaking,
such an enforcement would be more annoying than helpful.
Additional checks have been added to allow types derived from `collections.abc.Set` and
`collections.abc.Mapping` (`collections.abc.Sequence` is already allowed by `PySequence_Check`).
*/
inline bool object_is_instance_with_one_of_tp_names(PyObject *obj,
std::initializer_list<const char *> tp_names) {
if (PyType_Check(obj)) {
return false;
}
const char *obj_tp_name = Py_TYPE(obj)->tp_name;
for (const auto *tp_name : tp_names) {
if (std::strcmp(obj_tp_name, tp_name) == 0) {
return true;
}
}
return false;
}
inline bool object_is_convertible_to_std_vector(const handle &src) {
// Allow sequence-like objects, but not (byte-)string-like objects.
if (PySequence_Check(src.ptr()) != 0) {
return !PyUnicode_Check(src.ptr()) && !PyBytes_Check(src.ptr());
}
// Allow generators, set/frozenset and several common iterable types.
return (PyGen_Check(src.ptr()) != 0) || (PyAnySet_Check(src.ptr()) != 0)
|| object_is_instance_with_one_of_tp_names(
src.ptr(), {"dict_keys", "dict_values", "dict_items", "map", "zip"});
}
inline bool object_is_convertible_to_std_set(const handle &src, bool convert) {
// Allow set/frozenset and dict keys.
// In convert mode: also allow types derived from collections.abc.Set.
return ((PyAnySet_Check(src.ptr()) != 0)
|| object_is_instance_with_one_of_tp_names(src.ptr(), {"dict_keys"}))
|| (convert && isinstance(src, module_::import("collections.abc").attr("Set")));
}
inline bool object_is_convertible_to_std_map(const handle &src, bool convert) {
// Allow dict.
if (PyDict_Check(src.ptr())) {
return true;
}
// Allow types conforming to Mapping Protocol.
// According to https://docs.python.org/3/c-api/mapping.html, `PyMappingCheck()` checks for
// `__getitem__()` without checking the type of keys. In order to restrict the allowed types
// closer to actual Mapping-like types, we also check for the `items()` method.
if (PyMapping_Check(src.ptr()) != 0) {
PyObject *items = PyObject_GetAttrString(src.ptr(), "items");
if (items != nullptr) {
bool is_convertible = (PyCallable_Check(items) != 0);
Py_DECREF(items);
if (is_convertible) {
return true;
}
} else {
PyErr_Clear();
}
}
// In convert mode: Allow types derived from collections.abc.Mapping
return convert && isinstance(src, module_::import("collections.abc").attr("Mapping"));
}
//
// End: Equivalent of clif/python/runtime.cc
//
/// Extracts an const lvalue reference or rvalue reference for U based on the type of T (e.g. for
/// forwarding a container element). Typically used indirect via forwarded_type(), below.
template <typename T, typename U>
using forwarded_type = conditional_t<std::is_lvalue_reference<T>::value,
remove_reference_t<U> &,
remove_reference_t<U> &&>;
/// Forwards a value U as rvalue or lvalue according to whether T is rvalue or lvalue; typically
/// used for forwarding a container's elements.
template <typename T, typename U>
constexpr forwarded_type<T, U> forward_like(U &&u) {
return std::forward<detail::forwarded_type<T, U>>(std::forward<U>(u));
}
// Checks if a container has a STL style reserve method.
// This will only return true for a `reserve()` with a `void` return.
template <typename C>
using has_reserve_method = std::is_same<decltype(std::declval<C>().reserve(0)), void>;
template <typename Type, typename Key>
struct set_caster {
using type = Type;
using key_conv = make_caster<Key>;
private:
template <typename T = Type, enable_if_t<has_reserve_method<T>::value, int> = 0>
void reserve_maybe(const anyset &s, Type *) {
value.reserve(s.size());
}
void reserve_maybe(const anyset &, void *) {}
bool convert_iterable(const iterable &itbl, bool convert) {
for (const auto &it : itbl) {
key_conv conv;
if (!conv.load(it, convert)) {
return false;
}
value.insert(cast_op<Key &&>(std::move(conv)));
}
return true;
}
bool convert_anyset(const anyset &s, bool convert) {
value.clear();
reserve_maybe(s, &value);
return convert_iterable(s, convert);
}
public:
bool load(handle src, bool convert) {
if (!object_is_convertible_to_std_set(src, convert)) {
return false;
}
if (isinstance<anyset>(src)) {
value.clear();
return convert_anyset(reinterpret_borrow<anyset>(src), convert);
}
if (!convert) {
return false;
}
assert(isinstance<iterable>(src));
value.clear();
return convert_iterable(reinterpret_borrow<iterable>(src), convert);
}
template <typename T>
static handle cast(T &&src, return_value_policy policy, handle parent) {
if (!std::is_lvalue_reference<T>::value) {
policy = return_value_policy_override<Key>::policy(policy);
}
pybind11::set s;
for (auto &&value : src) {
auto value_ = reinterpret_steal<object>(
key_conv::cast(detail::forward_like<T>(value), policy, parent));
if (!value_ || !s.add(std::move(value_))) {
return handle();
}
}
return s.release();
}
PYBIND11_TYPE_CASTER(type,
io_name("collections.abc.Set", "set") + const_name("[") + key_conv::name
+ const_name("]"));
};
template <typename Type, typename Key, typename Value>
struct map_caster {
using key_conv = make_caster<Key>;
using value_conv = make_caster<Value>;
private:
template <typename T = Type, enable_if_t<has_reserve_method<T>::value, int> = 0>
void reserve_maybe(const dict &d, Type *) {
value.reserve(d.size());
}
void reserve_maybe(const dict &, void *) {}
bool convert_elements(const dict &d, bool convert) {
value.clear();
reserve_maybe(d, &value);
for (const auto &it : d) {
key_conv kconv;
value_conv vconv;
if (!kconv.load(it.first.ptr(), convert) || !vconv.load(it.second.ptr(), convert)) {
return false;
}
value.emplace(cast_op<Key &&>(std::move(kconv)), cast_op<Value &&>(std::move(vconv)));
}
return true;
}
public:
bool load(handle src, bool convert) {
if (!object_is_convertible_to_std_map(src, convert)) {
return false;
}
if (isinstance<dict>(src)) {
return convert_elements(reinterpret_borrow<dict>(src), convert);
}
if (!convert) {
return false;
}
auto items = reinterpret_steal<object>(PyMapping_Items(src.ptr()));
if (!items) {
throw error_already_set();
}
assert(isinstance<iterable>(items));
return convert_elements(dict(reinterpret_borrow<iterable>(items)), convert);
}
template <typename T>
static handle cast(T &&src, return_value_policy policy, handle parent) {
dict d;
return_value_policy policy_key = policy;
return_value_policy policy_value = policy;
if (!std::is_lvalue_reference<T>::value) {
policy_key = return_value_policy_override<Key>::policy(policy_key);
policy_value = return_value_policy_override<Value>::policy(policy_value);
}
for (auto &&kv : src) {
auto key = reinterpret_steal<object>(
key_conv::cast(detail::forward_like<T>(kv.first), policy_key, parent));
auto value = reinterpret_steal<object>(
value_conv::cast(detail::forward_like<T>(kv.second), policy_value, parent));
if (!key || !value) {
return handle();
}
d[std::move(key)] = std::move(value);
}
return d.release();
}
PYBIND11_TYPE_CASTER(Type,
io_name("collections.abc.Mapping", "dict") + const_name("[")
+ key_conv::name + const_name(", ") + value_conv::name
+ const_name("]"));
};
template <typename Type, typename Value>
struct list_caster {
using value_conv = make_caster<Value>;
bool load(handle src, bool convert) {
if (!object_is_convertible_to_std_vector(src)) {
return false;
}
if (isinstance<sequence>(src)) {
return convert_elements(src, convert);
}
if (!convert) {
return false;
}
// Designed to be behavior-equivalent to passing tuple(src) from Python:
// The conversion to a tuple will first exhaust the generator object, to ensure that
// the generator is not left in an unpredictable (to the caller) partially-consumed
// state.
assert(isinstance<iterable>(src));
return convert_elements(tuple(reinterpret_borrow<iterable>(src)), convert);
}
private:
template <typename T = Type, enable_if_t<has_reserve_method<T>::value, int> = 0>
void reserve_maybe(const sequence &s, Type *) {
value.reserve(s.size());
}
void reserve_maybe(const sequence &, void *) {}
bool convert_elements(handle seq, bool convert) {
auto s = reinterpret_borrow<sequence>(seq);
value.clear();
reserve_maybe(s, &value);
for (const auto &it : seq) {
value_conv conv;
if (!conv.load(it, convert)) {
return false;
}
value.push_back(cast_op<Value &&>(std::move(conv)));
}
return true;
}
public:
template <typename T>
static handle cast(T &&src, return_value_policy policy, handle parent) {
if (!std::is_lvalue_reference<T>::value) {
policy = return_value_policy_override<Value>::policy(policy);
}
list l(src.size());
ssize_t index = 0;
for (auto &&value : src) {
auto value_ = reinterpret_steal<object>(
value_conv::cast(detail::forward_like<T>(value), policy, parent));
if (!value_) {
return handle();
}
PyList_SET_ITEM(l.ptr(), index++, value_.release().ptr()); // steals a reference
}
return l.release();
}
PYBIND11_TYPE_CASTER(Type,
io_name("collections.abc.Sequence", "list") + const_name("[")
+ value_conv::name + const_name("]"));
};
template <typename Type, typename Alloc>
struct type_caster<std::vector<Type, Alloc>> : list_caster<std::vector<Type, Alloc>, Type> {};
template <typename Type, typename Alloc>
struct type_caster<std::deque<Type, Alloc>> : list_caster<std::deque<Type, Alloc>, Type> {};
template <typename Type, typename Alloc>
struct type_caster<std::list<Type, Alloc>> : list_caster<std::list<Type, Alloc>, Type> {};
template <typename ArrayType, typename V, size_t... I>
ArrayType vector_to_array_impl(V &&v, index_sequence<I...>) {
return {{std::move(v[I])...}};
}
// Based on https://en.cppreference.com/w/cpp/container/array/to_array
template <typename ArrayType, size_t N, typename V>
ArrayType vector_to_array(V &&v) {
return vector_to_array_impl<ArrayType, V>(std::forward<V>(v), make_index_sequence<N>{});
}
template <typename ArrayType, typename Value, bool Resizable, size_t Size = 0>
struct array_caster {
using value_conv = make_caster<Value>;
private:
std::unique_ptr<ArrayType> value;
template <bool R = Resizable, enable_if_t<R, int> = 0>
bool convert_elements(handle seq, bool convert) {
auto l = reinterpret_borrow<sequence>(seq);
value.reset(new ArrayType{});
// Using `resize` to preserve the behavior exactly as it was before PR #5305
// For the `resize` to work, `Value` must be default constructible.
// For `std::valarray`, this is a requirement:
// https://en.cppreference.com/w/cpp/named_req/NumericType
value->resize(l.size());
size_t ctr = 0;
for (const auto &it : l) {
value_conv conv;
if (!conv.load(it, convert)) {
return false;
}
(*value)[ctr++] = cast_op<Value &&>(std::move(conv));
}
return true;
}
template <bool R = Resizable, enable_if_t<!R, int> = 0>
bool convert_elements(handle seq, bool convert) {
auto l = reinterpret_borrow<sequence>(seq);
if (l.size() != Size) {
return false;
}
// The `temp` storage is needed to support `Value` types that are not
// default-constructible.
// Deliberate choice: no template specializations, for simplicity, and
// because the compile time overhead for the specializations is deemed
// more significant than the runtime overhead for the `temp` storage.
std::vector<Value> temp;
temp.reserve(l.size());
for (auto it : l) {
value_conv conv;
if (!conv.load(it, convert)) {
return false;
}
temp.emplace_back(cast_op<Value &&>(std::move(conv)));
}
value.reset(new ArrayType(vector_to_array<ArrayType, Size>(std::move(temp))));
return true;
}
public:
bool load(handle src, bool convert) {
if (!object_is_convertible_to_std_vector(src)) {
return false;
}
if (isinstance<sequence>(src)) {
return convert_elements(src, convert);
}
if (!convert) {
return false;
}
// Designed to be behavior-equivalent to passing tuple(src) from Python:
// The conversion to a tuple will first exhaust the generator object, to ensure that
// the generator is not left in an unpredictable (to the caller) partially-consumed
// state.
assert(isinstance<iterable>(src));
return convert_elements(tuple(reinterpret_borrow<iterable>(src)), convert);
}
template <typename T>
static handle cast(T &&src, return_value_policy policy, handle parent) {
list l(src.size());
ssize_t index = 0;
for (auto &&value : src) {
auto value_ = reinterpret_steal<object>(
value_conv::cast(detail::forward_like<T>(value), policy, parent));
if (!value_) {
return handle();
}
PyList_SET_ITEM(l.ptr(), index++, value_.release().ptr()); // steals a reference
}
return l.release();
}
// Code copied from PYBIND11_TYPE_CASTER macro.
// Intentionally preserving the behavior exactly as it was before PR #5305
template <typename T_, enable_if_t<std::is_same<ArrayType, remove_cv_t<T_>>::value, int> = 0>
static handle cast(T_ *src, return_value_policy policy, handle parent) {
if (!src) {
return none().release();
}
if (policy == return_value_policy::take_ownership) {
auto h = cast(std::move(*src), policy, parent);
delete src; // WARNING: Assumes `src` was allocated with `new`.
return h;
}
return cast(*src, policy, parent);
}
// NOLINTNEXTLINE(google-explicit-constructor)
operator ArrayType *() { return &(*value); }
// NOLINTNEXTLINE(google-explicit-constructor)
operator ArrayType &() { return *value; }
// NOLINTNEXTLINE(google-explicit-constructor)
operator ArrayType &&() && { return std::move(*value); }
template <typename T_>
using cast_op_type = movable_cast_op_type<T_>;
static constexpr auto name
= const_name<Resizable>(const_name(""), const_name("typing.Annotated["))
+ io_name("collections.abc.Sequence", "list") + const_name("[") + value_conv::name
+ const_name("]")
+ const_name<Resizable>(const_name(""),
const_name(", \"FixedSize(") + const_name<Size>()
+ const_name(")\"]"));
};
template <typename Type, size_t Size>
struct type_caster<std::array<Type, Size>>
: array_caster<std::array<Type, Size>, Type, false, Size> {};
template <typename Type>
struct type_caster<std::valarray<Type>> : array_caster<std::valarray<Type>, Type, true> {};
template <typename Key, typename Compare, typename Alloc>
struct type_caster<std::set<Key, Compare, Alloc>>
: set_caster<std::set<Key, Compare, Alloc>, Key> {};
template <typename Key, typename Hash, typename Equal, typename Alloc>
struct type_caster<std::unordered_set<Key, Hash, Equal, Alloc>>
: set_caster<std::unordered_set<Key, Hash, Equal, Alloc>, Key> {};
template <typename Key, typename Value, typename Compare, typename Alloc>
struct type_caster<std::map<Key, Value, Compare, Alloc>>
: map_caster<std::map<Key, Value, Compare, Alloc>, Key, Value> {};
template <typename Key, typename Value, typename Hash, typename Equal, typename Alloc>
struct type_caster<std::unordered_map<Key, Value, Hash, Equal, Alloc>>
: map_caster<std::unordered_map<Key, Value, Hash, Equal, Alloc>, Key, Value> {};
// This type caster is intended to be used for std::optional and std::experimental::optional
template <typename Type, typename Value = typename Type::value_type>
struct optional_caster {
using value_conv = make_caster<Value>;
template <typename T>
static handle cast(T &&src, return_value_policy policy, handle parent) {
if (!src) {
return none().release();
}
if (!std::is_lvalue_reference<T>::value) {
policy = return_value_policy_override<Value>::policy(policy);
}
// NOLINTNEXTLINE(bugprone-unchecked-optional-access)
return value_conv::cast(*std::forward<T>(src), policy, parent);
}
bool load(handle src, bool convert) {
if (!src) {
return false;
}
if (src.is_none()) {
return true; // default-constructed value is already empty
}
value_conv inner_caster;
if (!inner_caster.load(src, convert)) {
return false;
}
value.emplace(cast_op<Value &&>(std::move(inner_caster)));
return true;
}
PYBIND11_TYPE_CASTER(Type, value_conv::name | make_caster<none>::name);
};
#if defined(PYBIND11_HAS_OPTIONAL)
template <typename T>
struct type_caster<std::optional<T>> : public optional_caster<std::optional<T>> {};
template <>
struct type_caster<std::nullopt_t> : public void_caster<std::nullopt_t> {};
#endif
#if defined(PYBIND11_HAS_EXP_OPTIONAL)
template <typename T>
struct type_caster<std::experimental::optional<T>>
: public optional_caster<std::experimental::optional<T>> {};
template <>
struct type_caster<std::experimental::nullopt_t>
: public void_caster<std::experimental::nullopt_t> {};
#endif
/// Visit a variant and cast any found type to Python
struct variant_caster_visitor {
return_value_policy policy;
handle parent;
using result_type = handle; // required by boost::variant in C++11
template <typename T>
result_type operator()(T &&src) const {
return make_caster<T>::cast(std::forward<T>(src), policy, parent);
}
};
/// Helper class which abstracts away variant's `visit` function. `std::variant` and similar
/// `namespace::variant` types which provide a `namespace::visit()` function are handled here
/// automatically using argument-dependent lookup. Users can provide specializations for other
/// variant-like classes, e.g. `boost::variant` and `boost::apply_visitor`.
template <template <typename...> class Variant>
struct visit_helper {
template <typename... Args>
static auto call(Args &&...args) -> decltype(visit(std::forward<Args>(args)...)) {
return visit(std::forward<Args>(args)...);
}
};
/// Generic variant caster
template <typename Variant>
struct variant_caster;
template <template <typename...> class V, typename... Ts>
struct variant_caster<V<Ts...>> {
static_assert(sizeof...(Ts) > 0, "Variant must consist of at least one alternative.");
template <typename U, typename... Us>
bool load_alternative(handle src, bool convert, type_list<U, Us...>) {
auto caster = make_caster<U>();
if (caster.load(src, convert)) {
value = cast_op<U>(std::move(caster));
return true;
}
return load_alternative(src, convert, type_list<Us...>{});
}
bool load_alternative(handle, bool, type_list<>) { return false; }
bool load(handle src, bool convert) {
// Do a first pass without conversions to improve constructor resolution.
// E.g. `py::int_(1).cast<variant<double, int>>()` needs to fill the `int`
// slot of the variant. Without two-pass loading `double` would be filled
// because it appears first and a conversion is possible.
if (convert && load_alternative(src, false, type_list<Ts...>{})) {
return true;
}
return load_alternative(src, convert, type_list<Ts...>{});
}
template <typename Variant>
static handle cast(Variant &&src, return_value_policy policy, handle parent) {
return visit_helper<V>::call(variant_caster_visitor{policy, parent},
std::forward<Variant>(src));
}
using Type = V<Ts...>;
PYBIND11_TYPE_CASTER(Type, ::pybind11::detail::union_concat(make_caster<Ts>::name...));
};
#if defined(PYBIND11_HAS_VARIANT)
template <typename... Ts>
struct type_caster<std::variant<Ts...>> : variant_caster<std::variant<Ts...>> {};
template <>
struct type_caster<std::monostate> : public void_caster<std::monostate> {};
#endif
PYBIND11_NAMESPACE_END(detail)
inline std::ostream &operator<<(std::ostream &os, const handle &obj) {
#ifdef PYBIND11_HAS_STRING_VIEW
os << str(obj).cast<std::string_view>();
#else
os << (std::string) str(obj);
#endif
return os;
}
PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)

View File

@@ -0,0 +1,114 @@
// Copyright (c) 2021 The Pybind Development Team.
// All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
#pragma once
#include <pybind11/cast.h>
#include <pybind11/detail/common.h>
#include <pybind11/detail/descr.h>
#include <pybind11/pybind11.h>
#include <pybind11/pytypes.h>
#include <string>
#if defined(PYBIND11_HAS_FILESYSTEM)
# include <filesystem>
#elif defined(PYBIND11_HAS_EXPERIMENTAL_FILESYSTEM)
# include <experimental/filesystem>
#else
# error "Neither #include <filesystem> nor #include <experimental/filesystem is available."
#endif
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
PYBIND11_NAMESPACE_BEGIN(detail)
#ifdef PYPY_VERSION
# define PYBIND11_REINTERPRET_CAST_VOID_PTR_IF_NOT_PYPY(...) (__VA_ARGS__)
#else
# define PYBIND11_REINTERPRET_CAST_VOID_PTR_IF_NOT_PYPY(...) \
(reinterpret_cast<void *>(__VA_ARGS__))
#endif
#if defined(PYBIND11_HAS_FILESYSTEM) || defined(PYBIND11_HAS_EXPERIMENTAL_FILESYSTEM)
template <typename T>
struct path_caster {
private:
static PyObject *unicode_from_fs_native(const std::string &w) {
# if !defined(PYPY_VERSION)
return PyUnicode_DecodeFSDefaultAndSize(w.c_str(), ssize_t(w.size()));
# else
// PyPy mistakenly declares the first parameter as non-const.
return PyUnicode_DecodeFSDefaultAndSize(const_cast<char *>(w.c_str()), ssize_t(w.size()));
# endif
}
static PyObject *unicode_from_fs_native(const std::wstring &w) {
return PyUnicode_FromWideChar(w.c_str(), ssize_t(w.size()));
}
public:
static handle cast(const T &path, return_value_policy, handle) {
if (auto py_str = unicode_from_fs_native(path.native())) {
return module_::import("pathlib")
.attr("Path")(reinterpret_steal<object>(py_str))
.release();
}
return nullptr;
}
bool load(handle handle, bool) {
// PyUnicode_FSConverter and PyUnicode_FSDecoder normally take care of
// calling PyOS_FSPath themselves, but that's broken on PyPy (PyPy
// issue #3168) so we do it ourselves instead.
PyObject *buf = PyOS_FSPath(handle.ptr());
if (!buf) {
PyErr_Clear();
return false;
}
PyObject *native = nullptr;
if constexpr (std::is_same_v<typename T::value_type, char>) {
if (PyUnicode_FSConverter(buf, PYBIND11_REINTERPRET_CAST_VOID_PTR_IF_NOT_PYPY(&native))
!= 0) {
if (auto *c_str = PyBytes_AsString(native)) {
// AsString returns a pointer to the internal buffer, which
// must not be free'd.
value = c_str;
}
}
} else if constexpr (std::is_same_v<typename T::value_type, wchar_t>) {
if (PyUnicode_FSDecoder(buf, PYBIND11_REINTERPRET_CAST_VOID_PTR_IF_NOT_PYPY(&native))
!= 0) {
if (auto *c_str = PyUnicode_AsWideCharString(native, nullptr)) {
// AsWideCharString returns a new string that must be free'd.
value = c_str; // Copies the string.
PyMem_Free(c_str);
}
}
}
Py_XDECREF(native);
Py_DECREF(buf);
if (PyErr_Occurred()) {
PyErr_Clear();
return false;
}
return true;
}
PYBIND11_TYPE_CASTER(T, io_name("os.PathLike | str | bytes", "pathlib.Path"));
};
#endif // PYBIND11_HAS_FILESYSTEM || defined(PYBIND11_HAS_EXPERIMENTAL_FILESYSTEM)
#if defined(PYBIND11_HAS_FILESYSTEM)
template <>
struct type_caster<std::filesystem::path> : public path_caster<std::filesystem::path> {};
#elif defined(PYBIND11_HAS_EXPERIMENTAL_FILESYSTEM)
template <>
struct type_caster<std::experimental::filesystem::path>
: public path_caster<std::experimental::filesystem::path> {};
#endif
PYBIND11_NAMESPACE_END(detail)
PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)

View File

@@ -0,0 +1,858 @@
/*
pybind11/std_bind.h: Binding generators for STL data types
Copyright (c) 2016 Sergey Lyskov and Wenzel Jakob
All rights reserved. Use of this source code is governed by a
BSD-style license that can be found in the LICENSE file.
*/
#pragma once
#include "detail/common.h"
#include "detail/type_caster_base.h"
#include "cast.h"
#include "operators.h"
#include <algorithm>
#include <sstream>
#include <type_traits>
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
PYBIND11_NAMESPACE_BEGIN(detail)
/* SFINAE helper class used by 'is_comparable */
template <typename T>
struct container_traits {
template <typename T2>
static std::true_type
test_comparable(decltype(std::declval<const T2 &>() == std::declval<const T2 &>()) *);
template <typename T2>
static std::false_type test_comparable(...);
template <typename T2>
static std::true_type test_value(typename T2::value_type *);
template <typename T2>
static std::false_type test_value(...);
template <typename T2>
static std::true_type test_pair(typename T2::first_type *, typename T2::second_type *);
template <typename T2>
static std::false_type test_pair(...);
static constexpr const bool is_comparable
= std::is_same<std::true_type, decltype(test_comparable<T>(nullptr))>::value;
static constexpr const bool is_pair
= std::is_same<std::true_type, decltype(test_pair<T>(nullptr, nullptr))>::value;
static constexpr const bool is_vector
= std::is_same<std::true_type, decltype(test_value<T>(nullptr))>::value;
static constexpr const bool is_element = !is_pair && !is_vector;
};
/* Default: is_comparable -> std::false_type */
template <typename T, typename SFINAE = void>
struct is_comparable : std::false_type {};
/* For non-map data structures, check whether operator== can be instantiated */
template <typename T>
struct is_comparable<
T,
enable_if_t<container_traits<T>::is_element && container_traits<T>::is_comparable>>
: std::true_type {};
/* For a vector/map data structure, recursively check the value type
(which is std::pair for maps) */
template <typename T>
struct is_comparable<T, enable_if_t<container_traits<T>::is_vector>>
: is_comparable<typename recursive_container_traits<T>::type_to_check_recursively> {};
template <>
struct is_comparable<recursive_bottom> : std::true_type {};
/* For pairs, recursively check the two data types */
template <typename T>
struct is_comparable<T, enable_if_t<container_traits<T>::is_pair>> {
static constexpr const bool value = is_comparable<typename T::first_type>::value
&& is_comparable<typename T::second_type>::value;
};
/* Fallback functions */
template <typename, typename, typename... Args>
void vector_if_copy_constructible(const Args &...) {}
template <typename, typename, typename... Args>
void vector_if_equal_operator(const Args &...) {}
template <typename, typename, typename... Args>
void vector_if_insertion_operator(const Args &...) {}
template <typename, typename, typename... Args>
void vector_modifiers(const Args &...) {}
template <typename Vector, typename Class_>
void vector_if_copy_constructible(enable_if_t<is_copy_constructible<Vector>::value, Class_> &cl) {
cl.def(init<const Vector &>(), "Copy constructor");
}
template <typename Vector, typename Class_>
void vector_if_equal_operator(enable_if_t<is_comparable<Vector>::value, Class_> &cl) {
using T = typename Vector::value_type;
cl.def(self == self);
cl.def(self != self);
cl.def(
"count",
[](const Vector &v, const T &x) { return std::count(v.begin(), v.end(), x); },
arg("x"),
"Return the number of times ``x`` appears in the list");
cl.def(
"remove",
[](Vector &v, const T &x) {
auto p = std::find(v.begin(), v.end(), x);
if (p != v.end()) {
v.erase(p);
} else {
throw value_error();
}
},
arg("x"),
"Remove the first item from the list whose value is x. "
"It is an error if there is no such item.");
cl.def(
"__contains__",
[](const Vector &v, const T &x) { return std::find(v.begin(), v.end(), x) != v.end(); },
arg("x"),
"Return true the container contains ``x``");
}
// Vector modifiers -- requires a copyable vector_type:
// (Technically, some of these (pop and __delitem__) don't actually require copyability, but it
// seems silly to allow deletion but not insertion, so include them here too.)
template <typename Vector, typename Class_>
void vector_modifiers(
enable_if_t<is_copy_constructible<typename Vector::value_type>::value, Class_> &cl) {
using T = typename Vector::value_type;
using SizeType = typename Vector::size_type;
using DiffType = typename Vector::difference_type;
auto wrap_i = [](DiffType i, SizeType n) {
if (i < 0) {
i += n;
}
if (i < 0 || (SizeType) i >= n) {
throw index_error();
}
return i;
};
cl.def(
"append",
[](Vector &v, const T &value) { v.push_back(value); },
arg("x"),
"Add an item to the end of the list");
cl.def(init([](const iterable &it) {
auto v = std::unique_ptr<Vector>(new Vector());
v->reserve(len_hint(it));
for (handle h : it) {
v->push_back(h.cast<T>());
}
return v.release();
}));
cl.def("clear", [](Vector &v) { v.clear(); }, "Clear the contents");
cl.def(
"extend",
[](Vector &v, const Vector &src) { v.insert(v.end(), src.begin(), src.end()); },
arg("L"),
"Extend the list by appending all the items in the given list");
cl.def(
"extend",
[](Vector &v, const iterable &it) {
const size_t old_size = v.size();
v.reserve(old_size + len_hint(it));
try {
for (handle h : it) {
v.push_back(h.cast<T>());
}
} catch (const cast_error &) {
v.erase(v.begin() + static_cast<typename Vector::difference_type>(old_size),
v.end());
try {
v.shrink_to_fit();
} catch (const std::exception &) { // NOLINT(bugprone-empty-catch)
// Do nothing
}
throw;
}
},
arg("L"),
"Extend the list by appending all the items in the given list");
cl.def(
"insert",
[](Vector &v, DiffType i, const T &x) {
// Can't use wrap_i; i == v.size() is OK
if (i < 0) {
i += v.size();
}
if (i < 0 || (SizeType) i > v.size()) {
throw index_error();
}
v.insert(v.begin() + i, x);
},
arg("i"),
arg("x"),
"Insert an item at a given position.");
cl.def(
"pop",
[](Vector &v) {
if (v.empty()) {
throw index_error();
}
T t = std::move(v.back());
v.pop_back();
return t;
},
"Remove and return the last item");
cl.def(
"pop",
[wrap_i](Vector &v, DiffType i) {
i = wrap_i(i, v.size());
T t = std::move(v[(SizeType) i]);
v.erase(std::next(v.begin(), i));
return t;
},
arg("i"),
"Remove and return the item at index ``i``");
cl.def("__setitem__", [wrap_i](Vector &v, DiffType i, const T &t) {
i = wrap_i(i, v.size());
v[(SizeType) i] = t;
});
/// Slicing protocol
cl.def(
"__getitem__",
[](const Vector &v, const slice &slice) -> Vector * {
size_t start = 0, stop = 0, step = 0, slicelength = 0;
if (!slice.compute(v.size(), &start, &stop, &step, &slicelength)) {
throw error_already_set();
}
auto *seq = new Vector();
seq->reserve((size_t) slicelength);
for (size_t i = 0; i < slicelength; ++i) {
seq->push_back(v[start]);
start += step;
}
return seq;
},
arg("s"),
"Retrieve list elements using a slice object");
cl.def(
"__setitem__",
[](Vector &v, const slice &slice, const Vector &value) {
size_t start = 0, stop = 0, step = 0, slicelength = 0;
if (!slice.compute(v.size(), &start, &stop, &step, &slicelength)) {
throw error_already_set();
}
if (slicelength != value.size()) {
throw std::runtime_error(
"Left and right hand size of slice assignment have different sizes!");
}
for (size_t i = 0; i < slicelength; ++i) {
v[start] = value[i];
start += step;
}
},
"Assign list elements using a slice object");
cl.def(
"__delitem__",
[wrap_i](Vector &v, DiffType i) {
i = wrap_i(i, v.size());
v.erase(v.begin() + i);
},
"Delete the list elements at index ``i``");
cl.def(
"__delitem__",
[](Vector &v, const slice &slice) {
size_t start = 0, stop = 0, step = 0, slicelength = 0;
if (!slice.compute(v.size(), &start, &stop, &step, &slicelength)) {
throw error_already_set();
}
if (step == 1 && false) {
v.erase(v.begin() + (DiffType) start, v.begin() + DiffType(start + slicelength));
} else {
for (size_t i = 0; i < slicelength; ++i) {
v.erase(v.begin() + DiffType(start));
start += step - 1;
}
}
},
"Delete list elements using a slice object");
}
// If the type has an operator[] that doesn't return a reference (most notably std::vector<bool>),
// we have to access by copying; otherwise we return by reference.
template <typename Vector>
using vector_needs_copy
= negation<std::is_same<decltype(std::declval<Vector>()[typename Vector::size_type()]),
typename Vector::value_type &>>;
// The usual case: access and iterate by reference
template <typename Vector, typename Class_>
void vector_accessor(enable_if_t<!vector_needs_copy<Vector>::value, Class_> &cl) {
using T = typename Vector::value_type;
using SizeType = typename Vector::size_type;
using DiffType = typename Vector::difference_type;
using ItType = typename Vector::iterator;
auto wrap_i = [](DiffType i, SizeType n) {
if (i < 0) {
i += n;
}
if (i < 0 || (SizeType) i >= n) {
throw index_error();
}
return i;
};
cl.def(
"__getitem__",
[wrap_i](Vector &v, DiffType i) -> T & {
i = wrap_i(i, v.size());
return v[(SizeType) i];
},
return_value_policy::reference_internal // ref + keepalive
);
cl.def(
"__iter__",
[](Vector &v) {
return make_iterator<return_value_policy::reference_internal, ItType, ItType, T &>(
v.begin(), v.end());
},
keep_alive<0, 1>() /* Essential: keep list alive while iterator exists */
);
}
// The case for special objects, like std::vector<bool>, that have to be returned-by-copy:
template <typename Vector, typename Class_>
void vector_accessor(enable_if_t<vector_needs_copy<Vector>::value, Class_> &cl) {
using T = typename Vector::value_type;
using SizeType = typename Vector::size_type;
using DiffType = typename Vector::difference_type;
using ItType = typename Vector::iterator;
cl.def("__getitem__", [](const Vector &v, DiffType i) -> T {
if (i < 0) {
i += v.size();
if (i < 0) {
throw index_error();
}
}
auto i_st = static_cast<SizeType>(i);
if (i_st >= v.size()) {
throw index_error();
}
return v[i_st];
});
cl.def(
"__iter__",
[](Vector &v) {
return make_iterator<return_value_policy::copy, ItType, ItType, T>(v.begin(), v.end());
},
keep_alive<0, 1>() /* Essential: keep list alive while iterator exists */
);
}
template <typename Vector, typename Class_>
auto vector_if_insertion_operator(Class_ &cl, std::string const &name)
-> decltype(std::declval<std::ostream &>() << std::declval<typename Vector::value_type>(),
void()) {
using size_type = typename Vector::size_type;
cl.def(
"__repr__",
[name](Vector &v) {
std::ostringstream s;
s << name << '[';
for (size_type i = 0; i < v.size(); ++i) {
s << v[i];
if (i != v.size() - 1) {
s << ", ";
}
}
s << ']';
return s.str();
},
"Return the canonical string representation of this list.");
}
// Provide the buffer interface for vectors if we have data() and we have a format for it
// GCC seems to have "void std::vector<bool>::data()" - doing SFINAE on the existence of data()
// is insufficient, we need to check it returns an appropriate pointer
template <typename Vector, typename = void>
struct vector_has_data_and_format : std::false_type {};
template <typename Vector>
struct vector_has_data_and_format<
Vector,
enable_if_t<std::is_same<decltype(format_descriptor<typename Vector::value_type>::format(),
std::declval<Vector>().data()),
typename Vector::value_type *>::value>> : std::true_type {};
// [workaround(intel)] Separate function required here
// Workaround as the Intel compiler does not compile the enable_if_t part below
// (tested with icc (ICC) 2021.1 Beta 20200827)
template <typename... Args>
constexpr bool args_any_are_buffer() {
return detail::any_of<std::is_same<Args, buffer_protocol>...>::value;
}
// [workaround(intel)] Separate function required here
// [workaround(msvc)] Can't use constexpr bool in return type
// Add the buffer interface to a vector
template <typename Vector, typename Class_, typename... Args>
void vector_buffer_impl(Class_ &cl, std::true_type) {
using T = typename Vector::value_type;
static_assert(vector_has_data_and_format<Vector>::value,
"There is not an appropriate format descriptor for this vector");
// numpy.h declares this for arbitrary types, but it may raise an exception and crash hard
// at runtime if PYBIND11_NUMPY_DTYPE hasn't been called, so check here
format_descriptor<T>::format();
cl.def_buffer([](Vector &v) -> buffer_info {
return buffer_info(v.data(),
static_cast<ssize_t>(sizeof(T)),
format_descriptor<T>::format(),
1,
{v.size()},
{sizeof(T)});
});
cl.def(init([](const buffer &buf) {
auto info = buf.request();
if (info.ndim != 1 || info.strides[0] % static_cast<ssize_t>(sizeof(T))) {
throw type_error("Only valid 1D buffers can be copied to a vector");
}
if (!detail::compare_buffer_info<T>::compare(info)
|| (ssize_t) sizeof(T) != info.itemsize) {
throw type_error("Format mismatch (Python: " + info.format
+ " C++: " + format_descriptor<T>::format() + ")");
}
T *p = static_cast<T *>(info.ptr);
ssize_t step = info.strides[0] / static_cast<ssize_t>(sizeof(T));
T *end = p + info.shape[0] * step;
if (step == 1) {
return Vector(p, end);
}
Vector vec;
vec.reserve((size_t) info.shape[0]);
for (; p != end; p += step) {
vec.push_back(*p);
}
return vec;
}));
return;
}
template <typename Vector, typename Class_, typename... Args>
void vector_buffer_impl(Class_ &, std::false_type) {}
template <typename Vector, typename Class_, typename... Args>
void vector_buffer(Class_ &cl) {
vector_buffer_impl<Vector, Class_, Args...>(
cl, detail::any_of<std::is_same<Args, buffer_protocol>...>{});
}
PYBIND11_NAMESPACE_END(detail)
//
// std::vector
//
template <typename Vector, typename holder_type = default_holder_type<Vector>, typename... Args>
class_<Vector, holder_type> bind_vector(handle scope, std::string const &name, Args &&...args) {
using Class_ = class_<Vector, holder_type>;
// If the value_type is unregistered (e.g. a converting type) or is itself registered
// module-local then make the vector binding module-local as well:
using vtype = typename Vector::value_type;
auto *vtype_info = detail::get_type_info(typeid(vtype));
bool local = !vtype_info || vtype_info->module_local;
Class_ cl(scope, name.c_str(), pybind11::module_local(local), std::forward<Args>(args)...);
// Declare the buffer interface if a buffer_protocol() is passed in
detail::vector_buffer<Vector, Class_, Args...>(cl);
cl.def(init<>());
// Register copy constructor (if possible)
detail::vector_if_copy_constructible<Vector, Class_>(cl);
// Register comparison-related operators and functions (if possible)
detail::vector_if_equal_operator<Vector, Class_>(cl);
// Register stream insertion operator (if possible)
detail::vector_if_insertion_operator<Vector, Class_>(cl, name);
// Modifiers require copyable vector value type
detail::vector_modifiers<Vector, Class_>(cl);
// Accessor and iterator; return by value if copyable, otherwise we return by ref + keep-alive
detail::vector_accessor<Vector, Class_>(cl);
cl.def(
"__bool__",
[](const Vector &v) -> bool { return !v.empty(); },
"Check whether the list is nonempty");
cl.def("__len__", [](const Vector &vec) { return vec.size(); });
#if 0
// C++ style functions deprecated, leaving it here as an example
cl.def(init<size_type>());
cl.def("resize",
(void (Vector::*) (size_type count)) & Vector::resize,
"changes the number of elements stored");
cl.def("erase",
[](Vector &v, SizeType i) {
if (i >= v.size())
throw index_error();
v.erase(v.begin() + i);
}, "erases element at index ``i``");
cl.def("empty", &Vector::empty, "checks whether the container is empty");
cl.def("size", &Vector::size, "returns the number of elements");
cl.def("push_back", (void (Vector::*)(const T&)) &Vector::push_back, "adds an element to the end");
cl.def("pop_back", &Vector::pop_back, "removes the last element");
cl.def("max_size", &Vector::max_size, "returns the maximum possible number of elements");
cl.def("reserve", &Vector::reserve, "reserves storage");
cl.def("capacity", &Vector::capacity, "returns the number of elements that can be held in currently allocated storage");
cl.def("shrink_to_fit", &Vector::shrink_to_fit, "reduces memory usage by freeing unused memory");
cl.def("clear", &Vector::clear, "clears the contents");
cl.def("swap", &Vector::swap, "swaps the contents");
cl.def("front", [](Vector &v) {
if (v.size()) return v.front();
else throw index_error();
}, "access the first element");
cl.def("back", [](Vector &v) {
if (v.size()) return v.back();
else throw index_error();
}, "access the last element ");
#endif
return cl;
}
//
// std::map, std::unordered_map
//
PYBIND11_NAMESPACE_BEGIN(detail)
/* Fallback functions */
template <typename, typename, typename... Args>
void map_if_insertion_operator(const Args &...) {}
template <typename, typename, typename... Args>
void map_assignment(const Args &...) {}
// Map assignment when copy-assignable: just copy the value
template <typename Map, typename Class_>
void map_assignment(
enable_if_t<is_copy_assignable<typename Map::mapped_type>::value, Class_> &cl) {
using KeyType = typename Map::key_type;
using MappedType = typename Map::mapped_type;
cl.def("__setitem__", [](Map &m, const KeyType &k, const MappedType &v) {
auto it = m.find(k);
if (it != m.end()) {
it->second = v;
} else {
m.emplace(k, v);
}
});
}
// Not copy-assignable, but still copy-constructible: we can update the value by erasing and
// reinserting
template <typename Map, typename Class_>
void map_assignment(enable_if_t<!is_copy_assignable<typename Map::mapped_type>::value
&& is_copy_constructible<typename Map::mapped_type>::value,
Class_> &cl) {
using KeyType = typename Map::key_type;
using MappedType = typename Map::mapped_type;
cl.def("__setitem__", [](Map &m, const KeyType &k, const MappedType &v) {
// We can't use m[k] = v; because value type might not be default constructable
auto r = m.emplace(k, v);
if (!r.second) {
// value type is not copy assignable so the only way to insert it is to erase it
// first...
m.erase(r.first);
m.emplace(k, v);
}
});
}
template <typename Map, typename Class_>
auto map_if_insertion_operator(Class_ &cl, std::string const &name)
-> decltype(std::declval<std::ostream &>() << std::declval<typename Map::key_type>()
<< std::declval<typename Map::mapped_type>(),
void()) {
cl.def(
"__repr__",
[name](Map &m) {
std::ostringstream s;
s << name << '{';
bool f = false;
for (auto const &kv : m) {
if (f) {
s << ", ";
}
s << kv.first << ": " << kv.second;
f = true;
}
s << '}';
return s.str();
},
"Return the canonical string representation of this map.");
}
struct keys_view {
virtual size_t len() = 0;
virtual iterator iter() = 0;
virtual bool contains(const handle &k) = 0;
virtual ~keys_view() = default;
};
struct values_view {
virtual size_t len() = 0;
virtual iterator iter() = 0;
virtual ~values_view() = default;
};
struct items_view {
virtual size_t len() = 0;
virtual iterator iter() = 0;
virtual ~items_view() = default;
};
template <typename Map>
struct KeysViewImpl : public detail::keys_view {
explicit KeysViewImpl(Map &map) : map(map) {}
size_t len() override { return map.size(); }
iterator iter() override { return make_key_iterator(map.begin(), map.end()); }
bool contains(const handle &k) override {
try {
return map.find(k.template cast<typename Map::key_type>()) != map.end();
} catch (const cast_error &) {
return false;
}
}
Map &map;
};
template <typename Map>
struct ValuesViewImpl : public detail::values_view {
explicit ValuesViewImpl(Map &map) : map(map) {}
size_t len() override { return map.size(); }
iterator iter() override { return make_value_iterator(map.begin(), map.end()); }
Map &map;
};
template <typename Map>
struct ItemsViewImpl : public detail::items_view {
explicit ItemsViewImpl(Map &map) : map(map) {}
size_t len() override { return map.size(); }
iterator iter() override { return make_iterator(map.begin(), map.end()); }
Map &map;
};
inline str format_message_key_error_key_object(handle py_key) {
str message = "pybind11::bind_map key";
if (!py_key) {
return message;
}
try {
message = str(py_key);
} catch (const std::exception &) {
try {
message = repr(py_key);
} catch (const std::exception &) {
return message;
}
}
const ssize_t cut_length = 100;
if (len(message) > 2 * cut_length + 3) {
return str(message[slice(0, cut_length, 1)]) + str("✄✄✄")
+ str(message[slice(-cut_length, static_cast<ssize_t>(len(message)), 1)]);
}
return message;
}
template <typename KeyType>
str format_message_key_error(const KeyType &key) {
object py_key;
try {
py_key = cast(key);
} catch (const std::exception &) {
do { // Trick to avoid "empty catch" warning/error.
} while (false);
}
return format_message_key_error_key_object(py_key);
}
PYBIND11_NAMESPACE_END(detail)
template <typename Map, typename holder_type = default_holder_type<Map>, typename... Args>
class_<Map, holder_type> bind_map(handle scope, const std::string &name, Args &&...args) {
using KeyType = typename Map::key_type;
using MappedType = typename Map::mapped_type;
using KeysView = detail::keys_view;
using ValuesView = detail::values_view;
using ItemsView = detail::items_view;
using Class_ = class_<Map, holder_type>;
// If either type is a non-module-local bound type then make the map binding non-local as well;
// otherwise (e.g. both types are either module-local or converting) the map will be
// module-local.
auto *tinfo = detail::get_type_info(typeid(MappedType));
bool local = !tinfo || tinfo->module_local;
if (local) {
tinfo = detail::get_type_info(typeid(KeyType));
local = !tinfo || tinfo->module_local;
}
Class_ cl(scope, name.c_str(), pybind11::module_local(local), std::forward<Args>(args)...);
// Wrap KeysView if it wasn't already wrapped
if (!detail::get_type_info(typeid(KeysView))) {
class_<KeysView> keys_view(scope, "KeysView", pybind11::module_local(local));
keys_view.def("__len__", &KeysView::len);
keys_view.def("__iter__",
&KeysView::iter,
keep_alive<0, 1>() /* Essential: keep view alive while iterator exists */
);
keys_view.def("__contains__", &KeysView::contains);
}
// Similarly for ValuesView:
if (!detail::get_type_info(typeid(ValuesView))) {
class_<ValuesView> values_view(scope, "ValuesView", pybind11::module_local(local));
values_view.def("__len__", &ValuesView::len);
values_view.def("__iter__",
&ValuesView::iter,
keep_alive<0, 1>() /* Essential: keep view alive while iterator exists */
);
}
// Similarly for ItemsView:
if (!detail::get_type_info(typeid(ItemsView))) {
class_<ItemsView> items_view(scope, "ItemsView", pybind11::module_local(local));
items_view.def("__len__", &ItemsView::len);
items_view.def("__iter__",
&ItemsView::iter,
keep_alive<0, 1>() /* Essential: keep view alive while iterator exists */
);
}
cl.def(init<>());
// Register stream insertion operator (if possible)
detail::map_if_insertion_operator<Map, Class_>(cl, name);
cl.def(
"__bool__",
[](const Map &m) -> bool { return !m.empty(); },
"Check whether the map is nonempty");
cl.def(
"__iter__",
[](Map &m) { return make_key_iterator(m.begin(), m.end()); },
keep_alive<0, 1>() /* Essential: keep map alive while iterator exists */
);
cl.def(
"keys",
[](Map &m) { return std::unique_ptr<KeysView>(new detail::KeysViewImpl<Map>(m)); },
keep_alive<0, 1>() /* Essential: keep map alive while view exists */
);
cl.def(
"values",
[](Map &m) { return std::unique_ptr<ValuesView>(new detail::ValuesViewImpl<Map>(m)); },
keep_alive<0, 1>() /* Essential: keep map alive while view exists */
);
cl.def(
"items",
[](Map &m) { return std::unique_ptr<ItemsView>(new detail::ItemsViewImpl<Map>(m)); },
keep_alive<0, 1>() /* Essential: keep map alive while view exists */
);
cl.def(
"__getitem__",
[](Map &m, const KeyType &k) -> MappedType & {
auto it = m.find(k);
if (it == m.end()) {
set_error(PyExc_KeyError, detail::format_message_key_error(k));
throw error_already_set();
}
return it->second;
},
return_value_policy::reference_internal // ref + keepalive
);
cl.def("__contains__", [](Map &m, const KeyType &k) -> bool {
auto it = m.find(k);
if (it == m.end()) {
return false;
}
return true;
});
// Fallback for when the object is not of the key type
cl.def("__contains__", [](Map &, const object &) -> bool { return false; });
// Assignment provided only if the type is copyable
detail::map_assignment<Map, Class_>(cl);
cl.def("__delitem__", [](Map &m, const KeyType &k) {
auto it = m.find(k);
if (it == m.end()) {
set_error(PyExc_KeyError, detail::format_message_key_error(k));
throw error_already_set();
}
m.erase(it);
});
// Always use a lambda in case of `using` declaration
cl.def("__len__", [](const Map &m) { return m.size(); });
return cl;
}
PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)

View File

@@ -0,0 +1,299 @@
/*
pybind11/subinterpreter.h: Support for creating and using subinterpreters
Copyright (c) 2025 The Pybind Development Team.
All rights reserved. Use of this source code is governed by a
BSD-style license that can be found in the LICENSE file.
*/
#pragma once
#include "detail/common.h"
#include "detail/internals.h"
#include "gil.h"
#include <stdexcept>
#ifndef PYBIND11_HAS_SUBINTERPRETER_SUPPORT
# error "This platform does not support subinterpreters, do not include this file."
#endif
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
PYBIND11_NAMESPACE_BEGIN(detail)
inline PyInterpreterState *get_interpreter_state_unchecked() {
auto cur_tstate = get_thread_state_unchecked();
if (cur_tstate)
return cur_tstate->interp;
else
return nullptr;
}
PYBIND11_NAMESPACE_END(detail)
class subinterpreter;
/// Activate the subinterpreter and acquire its GIL, while also releasing any GIL and interpreter
/// currently held. Upon exiting the scope, the previous subinterpreter (if any) and its
/// associated GIL are restored to their state as they were before the scope was entered.
class subinterpreter_scoped_activate {
public:
explicit subinterpreter_scoped_activate(subinterpreter const &si);
~subinterpreter_scoped_activate();
subinterpreter_scoped_activate(subinterpreter_scoped_activate &&) = delete;
subinterpreter_scoped_activate(subinterpreter_scoped_activate const &) = delete;
subinterpreter_scoped_activate &operator=(subinterpreter_scoped_activate &) = delete;
subinterpreter_scoped_activate &operator=(subinterpreter_scoped_activate const &) = delete;
private:
PyThreadState *old_tstate_ = nullptr;
PyThreadState *tstate_ = nullptr;
PyGILState_STATE gil_state_;
bool simple_gil_ = false;
};
/// Holds a Python subinterpreter instance
class subinterpreter {
public:
/// empty/unusable, but move-assignable. use create() to create a subinterpreter.
subinterpreter() = default;
subinterpreter(subinterpreter const &copy) = delete;
subinterpreter &operator=(subinterpreter const &copy) = delete;
subinterpreter(subinterpreter &&old) noexcept
: istate_(old.istate_), creation_tstate_(old.creation_tstate_) {
old.istate_ = nullptr;
old.creation_tstate_ = nullptr;
}
subinterpreter &operator=(subinterpreter &&old) noexcept {
std::swap(old.istate_, istate_);
std::swap(old.creation_tstate_, creation_tstate_);
return *this;
}
/// Create a new subinterpreter with the specified configuration
/// @note This function acquires (and then releases) the main interpreter GIL, but the main
/// interpreter and its GIL are not required to be held prior to calling this function.
static inline subinterpreter create(PyInterpreterConfig const &cfg) {
error_scope err_scope;
subinterpreter result;
{
// we must hold the main GIL in order to create a subinterpreter
subinterpreter_scoped_activate main_guard(main());
auto prev_tstate = PyThreadState_Get();
PyStatus status;
{
/*
Several internal CPython modules are lacking proper subinterpreter support in 3.12
even though it is "stable" in that version. This most commonly seems to cause
crashes when two interpreters concurrently initialize, which imports several things
(like builtins, unicode, codecs).
*/
#if PY_VERSION_HEX < 0x030D0000 && defined(Py_MOD_PER_INTERPRETER_GIL_SUPPORTED)
static std::mutex one_at_a_time;
std::lock_guard<std::mutex> guard(one_at_a_time);
#endif
status = Py_NewInterpreterFromConfig(&result.creation_tstate_, &cfg);
}
// this doesn't raise a normal Python exception, it provides an exit() status code.
if (PyStatus_Exception(status)) {
pybind11_fail("failed to create new sub-interpreter");
}
// upon success, the new interpreter is activated in this thread
result.istate_ = result.creation_tstate_->interp;
detail::get_num_interpreters_seen() += 1; // there are now many interpreters
detail::get_internals(); // initialize internals.tstate, amongst other things...
// In 3.13+ this state should be deleted right away, and the memory will be reused for
// the next threadstate on this interpreter. However, on 3.12 we cannot do that, we
// must keep it around (but not use it) ... see destructor.
#if PY_VERSION_HEX >= 0x030D0000
PyThreadState_Clear(result.creation_tstate_);
PyThreadState_DeleteCurrent();
#endif
// we have to switch back to main, and then the scopes will handle cleanup
PyThreadState_Swap(prev_tstate);
}
return result;
}
/// Calls create() with a default configuration of an isolated interpreter that disallows fork,
/// exec, and Python threads.
static inline subinterpreter create() {
// same as the default config in the python docs
PyInterpreterConfig cfg;
std::memset(&cfg, 0, sizeof(cfg));
cfg.allow_threads = 1;
cfg.check_multi_interp_extensions = 1;
cfg.gil = PyInterpreterConfig_OWN_GIL;
return create(cfg);
}
~subinterpreter() {
if (!creation_tstate_) {
// non-owning wrapper, do nothing.
return;
}
PyThreadState *destroy_tstate;
PyThreadState *old_tstate;
// Python 3.12 requires us to keep the original PyThreadState alive until we are ready to
// destroy the interpreter. We prefer to use that to destroy the interpreter.
#if PY_VERSION_HEX < 0x030D0000
// The tstate passed to Py_EndInterpreter MUST have been created on the current OS thread.
bool same_thread = false;
# ifdef PY_HAVE_THREAD_NATIVE_ID
same_thread = PyThread_get_thread_native_id() == creation_tstate_->native_thread_id;
# endif
if (same_thread) {
// OK it is safe to use the creation state here
destroy_tstate = creation_tstate_;
old_tstate = PyThreadState_Swap(destroy_tstate);
} else {
// We have to make a new tstate on this thread and use that.
destroy_tstate = PyThreadState_New(istate_);
old_tstate = PyThreadState_Swap(destroy_tstate);
// We can use the one we just created, so we must delete the creation state.
PyThreadState_Clear(creation_tstate_);
PyThreadState_Delete(creation_tstate_);
}
#else
destroy_tstate = PyThreadState_New(istate_);
old_tstate = PyThreadState_Swap(destroy_tstate);
#endif
bool switch_back = old_tstate && old_tstate->interp != istate_;
// Internals always exists in the subinterpreter, this class enforces it when it creates
// the subinterpreter. Even if it didn't, this only creates the pointer-to-pointer, not the
// internals themselves.
detail::get_internals_pp_manager().get_pp();
detail::get_local_internals_pp_manager().get_pp();
// End it
Py_EndInterpreter(destroy_tstate);
// It's possible for the internals to be created during endinterpreter (e.g. if a
// py::capsule calls `get_internals()` during destruction), so we destroy afterward.
detail::get_internals_pp_manager().destroy();
detail::get_local_internals_pp_manager().destroy();
// switch back to the old tstate and old GIL (if there was one)
if (switch_back)
PyThreadState_Swap(old_tstate);
}
/// Get a handle to the main interpreter that can be used with subinterpreter_scoped_activate
/// Note that destructing the handle is a noop, the main interpreter can only be ended by
/// py::finalize_interpreter()
static subinterpreter main() {
subinterpreter m;
m.istate_ = PyInterpreterState_Main();
m.disarm(); // make destruct a noop
return m;
}
/// Get a non-owning wrapper of the currently active interpreter (if any)
static subinterpreter current() {
subinterpreter c;
c.istate_ = detail::get_interpreter_state_unchecked();
c.disarm(); // make destruct a noop, we don't own this...
return c;
}
/// Get the numerical identifier for the sub-interpreter
int64_t id() const {
if (istate_ != nullptr)
return PyInterpreterState_GetID(istate_);
else
return -1; // CPython uses one-up numbers from 0, so negative should be safe to return
// here.
}
/// Get the interpreter's state dict. This interpreter's GIL must be held before calling!
dict state_dict() { return reinterpret_borrow<dict>(PyInterpreterState_GetDict(istate_)); }
/// abandon cleanup of this subinterpreter (leak it). this might be needed during
/// finalization...
void disarm() { creation_tstate_ = nullptr; }
/// An empty wrapper cannot be activated
bool empty() const { return istate_ == nullptr; }
/// Is this wrapper non-empty
explicit operator bool() const { return !empty(); }
private:
friend class subinterpreter_scoped_activate;
PyInterpreterState *istate_ = nullptr;
PyThreadState *creation_tstate_ = nullptr;
};
class scoped_subinterpreter {
public:
scoped_subinterpreter() : si_(subinterpreter::create()), scope_(si_) {}
explicit scoped_subinterpreter(PyInterpreterConfig const &cfg)
: si_(subinterpreter::create(cfg)), scope_(si_) {}
private:
subinterpreter si_;
subinterpreter_scoped_activate scope_;
};
inline subinterpreter_scoped_activate::subinterpreter_scoped_activate(subinterpreter const &si) {
if (!si.istate_) {
pybind11_fail("null subinterpreter");
}
if (detail::get_interpreter_state_unchecked() == si.istate_) {
// we are already on this interpreter, make sure we hold the GIL
simple_gil_ = true;
gil_state_ = PyGILState_Ensure();
return;
}
// we can't really interact with the interpreter at all until we switch to it
// not even to, for example, look in its state dict or touch its internals
tstate_ = PyThreadState_New(si.istate_);
// make the interpreter active and acquire the GIL
old_tstate_ = PyThreadState_Swap(tstate_);
// save this in internals for scoped_gil calls
detail::get_internals().tstate = tstate_;
}
inline subinterpreter_scoped_activate::~subinterpreter_scoped_activate() {
if (simple_gil_) {
// We were on this interpreter already, so just make sure the GIL goes back as it was
PyGILState_Release(gil_state_);
} else {
if (tstate_) {
#if defined(PYBIND11_DETAILED_ERROR_MESSAGES)
if (detail::get_thread_state_unchecked() != tstate_) {
pybind11_fail("~subinterpreter_scoped_activate: thread state must be current!");
}
#endif
detail::get_internals().tstate.reset();
PyThreadState_Clear(tstate_);
PyThreadState_DeleteCurrent();
}
// Go back the previous interpreter (if any) and acquire THAT gil
PyThreadState_Swap(old_tstate_);
}
}
PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)

View File

@@ -0,0 +1,65 @@
// Copyright (c) 2021 The Pybind Development Team.
// All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
#pragma once
#include "detail/common.h"
#include "detail/using_smart_holder.h"
#include "detail/value_and_holder.h"
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
PYBIND11_NAMESPACE_BEGIN(detail)
// PYBIND11:REMINDER: Needs refactoring of existing pybind11 code.
inline bool deregister_instance(instance *self, void *valptr, const type_info *tinfo);
PYBIND11_NAMESPACE_END(detail)
// The original core idea for this struct goes back to PyCLIF:
// https://github.com/google/clif/blob/07f95d7e69dca2fcf7022978a55ef3acff506c19/clif/python/runtime.cc#L37
// URL provided here mainly to give proper credit.
struct trampoline_self_life_support {
// NOTE: PYBIND11_INTERNALS_VERSION needs to be bumped if changes are made to this struct.
detail::value_and_holder v_h;
trampoline_self_life_support() = default;
void activate_life_support(const detail::value_and_holder &v_h_) {
Py_INCREF((PyObject *) v_h_.inst);
v_h = v_h_;
}
void deactivate_life_support() {
Py_DECREF((PyObject *) v_h.inst);
v_h = detail::value_and_holder();
}
~trampoline_self_life_support() {
if (v_h.inst != nullptr && v_h.vh != nullptr) {
void *value_void_ptr = v_h.value_ptr();
if (value_void_ptr != nullptr) {
PyGILState_STATE threadstate = PyGILState_Ensure();
v_h.value_ptr() = nullptr;
v_h.holder<smart_holder>().release_disowned();
detail::deregister_instance(v_h.inst, value_void_ptr, v_h.type);
Py_DECREF((PyObject *) v_h.inst); // Must be after deregister.
PyGILState_Release(threadstate);
}
}
}
// For the next two, the default implementations generate undefined behavior (ASAN failures
// manually verified). The reason is that v_h needs to be kept default-initialized.
trampoline_self_life_support(const trampoline_self_life_support &) {}
trampoline_self_life_support(trampoline_self_life_support &&) noexcept {}
// These should never be needed (please provide test cases if you think they are).
trampoline_self_life_support &operator=(const trampoline_self_life_support &) = delete;
trampoline_self_life_support &operator=(trampoline_self_life_support &&) = delete;
};
PYBIND11_NAMESPACE_BEGIN(detail)
using get_trampoline_self_life_support_fn = trampoline_self_life_support *(*) (void *);
PYBIND11_NAMESPACE_END(detail)
PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)

View File

@@ -0,0 +1,61 @@
// Copyright (c) 2023 The pybind Community.
#pragma once
#include "detail/common.h"
#include "detail/descr.h"
#include "cast.h"
#include "pytypes.h"
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
PYBIND11_NAMESPACE_BEGIN(detail)
template <>
class type_caster<PyObject> {
public:
static constexpr auto name = const_name("object"); // See discussion under PR #4601.
// This overload is purely to guard against accidents.
template <typename T,
detail::enable_if_t<!is_same_ignoring_cvref<T, PyObject *>::value, int> = 0>
static handle cast(T &&, return_value_policy, handle /*parent*/) {
static_assert(is_same_ignoring_cvref<T, PyObject *>::value,
"Invalid C++ type T for to-Python conversion (type_caster<PyObject>).");
return nullptr; // Unreachable.
}
static handle cast(PyObject *src, return_value_policy policy, handle /*parent*/) {
if (src == nullptr) {
throw error_already_set();
}
if (PyErr_Occurred()) {
raise_from(PyExc_SystemError, "src != nullptr but PyErr_Occurred()");
throw error_already_set();
}
if (policy == return_value_policy::take_ownership) {
return src;
}
if (policy == return_value_policy::reference
|| policy == return_value_policy::automatic_reference) {
return handle(src).inc_ref();
}
pybind11_fail("type_caster<PyObject>::cast(): unsupported return_value_policy: "
+ std::to_string(static_cast<int>(policy)));
}
bool load(handle src, bool) {
value = reinterpret_borrow<object>(src);
return true;
}
template <typename T>
using cast_op_type = PyObject *;
explicit operator PyObject *() { return value.ptr(); }
private:
object value;
};
PYBIND11_NAMESPACE_END(detail)
PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)

View File

@@ -0,0 +1,298 @@
/*
pybind11/typing.h: Convenience wrapper classes for basic Python types
with more explicit annotations.
Copyright (c) 2023 Dustin Spicuzza <dustin@virtualroadside.com>
All rights reserved. Use of this source code is governed by a
BSD-style license that can be found in the LICENSE file.
*/
#pragma once
#include "detail/common.h"
#include "cast.h"
#include "pytypes.h"
#include <algorithm>
#if defined(__cpp_nontype_template_args) && __cpp_nontype_template_args >= 201911L
# define PYBIND11_TYPING_H_HAS_STRING_LITERAL
# include <numeric>
# include <ranges>
# include <string_view>
#endif
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
PYBIND11_NAMESPACE_BEGIN(typing)
/*
The following types can be used to direct pybind11-generated docstrings
to have have more explicit types (e.g., `list[str]` instead of `list`).
Just use these in place of existing types.
There is no additional enforcement of types at runtime.
*/
template <typename... Types>
class Tuple : public tuple {
using tuple::tuple;
};
template <typename K, typename V>
class Dict : public dict {
using dict::dict;
};
template <typename T>
class List : public list {
using list::list;
};
template <typename T>
class Set : public set {
using set::set;
};
template <typename T>
class Iterable : public iterable {
using iterable::iterable;
};
template <typename T>
class Iterator : public iterator {
using iterator::iterator;
};
template <typename Signature>
class Callable;
template <typename Return, typename... Args>
class Callable<Return(Args...)> : public function {
using function::function;
};
template <typename T>
class Type : public type {
using type::type;
};
template <typename... Types>
class Union : public object {
PYBIND11_OBJECT_DEFAULT(Union, object, PyObject_Type)
using object::object;
};
template <typename T>
class Optional : public object {
PYBIND11_OBJECT_DEFAULT(Optional, object, PyObject_Type)
using object::object;
};
template <typename T>
class Final : public object {
PYBIND11_OBJECT_DEFAULT(Final, object, PyObject_Type)
using object::object;
};
template <typename T>
class ClassVar : public object {
PYBIND11_OBJECT_DEFAULT(ClassVar, object, PyObject_Type)
using object::object;
};
template <typename T>
class TypeGuard : public bool_ {
using bool_::bool_;
};
template <typename T>
class TypeIs : public bool_ {
using bool_::bool_;
};
class NoReturn : public none {
using none::none;
};
class Never : public none {
using none::none;
};
#if defined(PYBIND11_TYPING_H_HAS_STRING_LITERAL)
template <size_t N>
struct StringLiteral {
constexpr StringLiteral(const char (&str)[N]) { std::copy_n(str, N, name); }
char name[N];
};
template <StringLiteral... StrLits>
class Literal : public object {
PYBIND11_OBJECT_DEFAULT(Literal, object, PyObject_Type)
};
// Example syntax for creating a TypeVar.
// typedef typing::TypeVar<"T"> TypeVarT;
template <StringLiteral>
class TypeVar : public object {
PYBIND11_OBJECT_DEFAULT(TypeVar, object, PyObject_Type)
using object::object;
};
#endif
PYBIND11_NAMESPACE_END(typing)
PYBIND11_NAMESPACE_BEGIN(detail)
template <typename... Types>
struct handle_type_name<typing::Tuple<Types...>> {
static constexpr auto name = const_name("tuple[")
+ ::pybind11::detail::concat(make_caster<Types>::name...)
+ const_name("]");
};
template <>
struct handle_type_name<typing::Tuple<>> {
// PEP 484 specifies this syntax for an empty tuple
static constexpr auto name = const_name("tuple[()]");
};
template <typename T>
struct handle_type_name<typing::Tuple<T, ellipsis>> {
// PEP 484 specifies this syntax for a variable-length tuple
static constexpr auto name
= const_name("tuple[") + make_caster<T>::name + const_name(", ...]");
};
template <typename K, typename V>
struct handle_type_name<typing::Dict<K, V>> {
static constexpr auto name = const_name("dict[") + make_caster<K>::name + const_name(", ")
+ make_caster<V>::name + const_name("]");
};
template <typename T>
struct handle_type_name<typing::List<T>> {
static constexpr auto name = const_name("list[") + make_caster<T>::name + const_name("]");
};
template <typename T>
struct handle_type_name<typing::Set<T>> {
static constexpr auto name = const_name("set[") + make_caster<T>::name + const_name("]");
};
template <typename T>
struct handle_type_name<typing::Iterable<T>> {
static constexpr auto name
= const_name("collections.abc.Iterable[") + make_caster<T>::name + const_name("]");
};
template <typename T>
struct handle_type_name<typing::Iterator<T>> {
static constexpr auto name
= const_name("collections.abc.Iterator[") + make_caster<T>::name + const_name("]");
};
template <typename Return, typename... Args>
struct handle_type_name<typing::Callable<Return(Args...)>> {
using retval_type = conditional_t<std::is_same<Return, void>::value, void_type, Return>;
static constexpr auto name
= const_name("collections.abc.Callable[[")
+ ::pybind11::detail::concat(::pybind11::detail::arg_descr(make_caster<Args>::name)...)
+ const_name("], ") + ::pybind11::detail::return_descr(make_caster<retval_type>::name)
+ const_name("]");
};
template <typename Return>
struct handle_type_name<typing::Callable<Return(ellipsis)>> {
// PEP 484 specifies this syntax for defining only return types of callables
using retval_type = conditional_t<std::is_same<Return, void>::value, void_type, Return>;
static constexpr auto name = const_name("collections.abc.Callable[..., ")
+ ::pybind11::detail::return_descr(make_caster<retval_type>::name)
+ const_name("]");
};
template <typename T>
struct handle_type_name<typing::Type<T>> {
static constexpr auto name = const_name("type[") + make_caster<T>::name + const_name("]");
};
template <typename... Types>
struct handle_type_name<typing::Union<Types...>> {
static constexpr auto name = ::pybind11::detail::union_concat(make_caster<Types>::name...);
};
template <typename T>
struct handle_type_name<typing::Optional<T>> {
static constexpr auto name = make_caster<T>::name | make_caster<none>::name;
};
template <typename T>
struct handle_type_name<typing::Final<T>> {
static constexpr auto name = const_name("typing.Final[")
+ ::pybind11::detail::return_descr(make_caster<T>::name)
+ const_name("]");
};
template <typename T>
struct handle_type_name<typing::ClassVar<T>> {
static constexpr auto name
= const_name("typing.ClassVar[") + make_caster<T>::name + const_name("]");
};
template <typename T>
struct handle_type_name<typing::TypeGuard<T>> {
static constexpr auto name = const_name(PYBIND11_TYPE_GUARD_TYPE_HINT) + const_name("[")
+ make_caster<T>::name + const_name("]");
};
template <typename T>
struct handle_type_name<typing::TypeIs<T>> {
static constexpr auto name = const_name(PYBIND11_TYPE_IS_TYPE_HINT) + const_name("[")
+ make_caster<T>::name + const_name("]");
};
template <>
struct handle_type_name<typing::NoReturn> {
static constexpr auto name = const_name("typing.NoReturn");
};
template <>
struct handle_type_name<typing::Never> {
static constexpr auto name = const_name(PYBIND11_NEVER_TYPE_HINT);
};
#if defined(PYBIND11_TYPING_H_HAS_STRING_LITERAL)
template <typing::StringLiteral StrLit>
consteval auto sanitize_string_literal() {
constexpr std::string_view v(StrLit.name);
constexpr std::string_view special_chars("!@%{}-");
constexpr auto num_special_chars = std::accumulate(
special_chars.begin(), special_chars.end(), (size_t) 0, [&v](auto acc, const char &c) {
return std::move(acc) + std::ranges::count(v, c);
});
char result[v.size() + num_special_chars + 1];
size_t i = 0;
for (auto c : StrLit.name) {
if (special_chars.find(c) != std::string_view::npos) {
result[i++] = '!';
}
result[i++] = c;
}
return typing::StringLiteral(result);
}
template <typing::StringLiteral... Literals>
struct handle_type_name<typing::Literal<Literals...>> {
static constexpr auto name
= const_name("typing.Literal[")
+ pybind11::detail::concat(const_name(sanitize_string_literal<Literals>().name)...)
+ const_name("]");
};
template <typing::StringLiteral StrLit>
struct handle_type_name<typing::TypeVar<StrLit>> {
static constexpr auto name = const_name(sanitize_string_literal<StrLit>().name);
};
#endif
PYBIND11_NAMESPACE_END(detail)
PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)

View File

@@ -0,0 +1,75 @@
/*
pybind11/warnings.h: Python warnings wrappers.
Copyright (c) 2024 Jan Iwaszkiewicz <jiwaszkiewicz6@gmail.com>
All rights reserved. Use of this source code is governed by a
BSD-style license that can be found in the LICENSE file.
*/
#pragma once
#include "pybind11.h"
#include "detail/common.h"
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
PYBIND11_NAMESPACE_BEGIN(detail)
inline bool PyWarning_Check(PyObject *obj) {
int result = PyObject_IsSubclass(obj, PyExc_Warning);
if (result == 1) {
return true;
}
if (result == -1) {
raise_from(PyExc_SystemError,
"pybind11::detail::PyWarning_Check(): PyObject_IsSubclass() call failed.");
throw error_already_set();
}
return false;
}
PYBIND11_NAMESPACE_END(detail)
PYBIND11_NAMESPACE_BEGIN(warnings)
inline object
new_warning_type(handle scope, const char *name, handle base = PyExc_RuntimeWarning) {
if (!detail::PyWarning_Check(base.ptr())) {
pybind11_fail("pybind11::warnings::new_warning_type(): cannot create custom warning, base "
"must be a subclass of "
"PyExc_Warning!");
}
if (hasattr(scope, name)) {
pybind11_fail("pybind11::warnings::new_warning_type(): an attribute with name \""
+ std::string(name) + "\" exists already.");
}
std::string full_name = scope.attr("__name__").cast<std::string>() + std::string(".") + name;
handle h(PyErr_NewException(full_name.c_str(), base.ptr(), nullptr));
if (!h) {
raise_from(PyExc_SystemError,
"pybind11::warnings::new_warning_type(): PyErr_NewException() call failed.");
throw error_already_set();
}
auto obj = reinterpret_steal<object>(h);
scope.attr(name) = obj;
return obj;
}
// Similar to Python `warnings.warn()`
inline void
warn(const char *message, handle category = PyExc_RuntimeWarning, int stack_level = 2) {
if (!detail::PyWarning_Check(category.ptr())) {
pybind11_fail(
"pybind11::warnings::warn(): cannot raise warning, category must be a subclass of "
"PyExc_Warning!");
}
if (PyErr_WarnEx(category.ptr(), message, stack_level) == -1) {
throw error_already_set();
}
}
PYBIND11_NAMESPACE_END(warnings)
PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)

View File

@@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-07-13 16:24-0300\n"
"POT-Creation-Date: 2026-07-17 15:13-0300\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
@@ -1935,6 +1935,17 @@ msgstr ""
msgid "Info"
msgstr ""
msgid "Loading Plugins"
msgstr ""
#, possible-c-format, possible-boost-format
msgid "Plugin %s is no longer available."
msgstr ""
#, possible-c-format, possible-boost-format
msgid "Plugin %s access is unauthorized."
msgstr ""
msgid "Loading printer & filament profiles"
msgstr ""
@@ -2048,6 +2059,18 @@ msgstr ""
msgid "Resolve cloud sync conflict"
msgstr ""
msgid "Syncing your account…"
msgstr ""
msgid "Migrating presets…"
msgstr ""
msgid "Fetching plugins…"
msgstr ""
msgid "Loading user presets…"
msgstr ""
msgid "Retrieving printer information, please try again later."
msgstr ""
@@ -2166,6 +2189,21 @@ msgstr ""
msgid "*"
msgstr ""
msgid "Plugins"
msgstr ""
#, possible-c-format, possible-boost-format
msgid ""
"Failed to open the Plugins dialog:\n"
"%s"
msgstr ""
msgid "Failed to open the Plugins dialog (unknown error)."
msgstr ""
msgid "Plugin Terminal"
msgstr ""
msgid "Changing application language"
msgstr ""
@@ -4809,6 +4847,28 @@ msgstr ""
msgid "N/A"
msgstr ""
msgid "System agents"
msgstr ""
msgid "No plugin selected"
msgstr ""
msgid "Add plugin"
msgstr ""
msgid "Select plugin"
msgstr ""
msgid "Remove plugin"
msgstr ""
msgid "Configure"
msgstr ""
#, possible-c-format, possible-boost-format
msgid "Configure (%d)"
msgstr ""
msgid "Pick"
msgstr ""
@@ -4974,9 +5034,6 @@ msgstr ""
msgid "Fan speed"
msgstr ""
msgid "°C"
msgstr ""
msgid "Time"
msgstr ""
@@ -6939,6 +6996,14 @@ msgctxt "Layers"
msgid "Bottom"
msgstr ""
msgid "Plugin Selection"
msgstr ""
msgid ""
"No plugins capabilities available for this type.\n"
"Enable or install some to use."
msgstr ""
msgid "Enable detection of build plate position"
msgstr ""
@@ -7791,6 +7856,40 @@ msgstr ""
msgid "Synchronize AMS Filament Information"
msgstr ""
msgid "OrcaCloud plugins required by the current preset are not installed:"
msgstr ""
msgid "Install Plugins"
msgstr ""
msgid "Local plugins required by the current preset are missing:"
msgstr ""
msgid "Find on OrcaCloud"
msgstr ""
msgid "Plugins required by the current preset are not activated:"
msgstr ""
msgid "Activate Now"
msgstr ""
msgid "The installed plugin does not provide the required capability — it may be outdated:"
msgstr ""
msgid "Preparing to install plugins..."
msgstr ""
msgid "Installing plugins"
msgstr ""
msgid "Cancelling — finishing the current plugin..."
msgstr ""
#, possible-boost-format
msgid "Installing %1%..."
msgstr ""
msgid "Plate Settings"
msgstr ""
@@ -8814,6 +8913,9 @@ msgstr ""
msgid "Your filament grouping method in the sliced file is not optimal."
msgstr ""
msgid "To ensure print quality, the drying temperature will be lowered during printing."
msgstr ""
msgid "Auto Bed Leveling"
msgstr ""
@@ -9507,6 +9609,12 @@ msgstr ""
msgid "Post-processing Scripts"
msgstr ""
msgid "Slicing Pipeline Plugin"
msgstr ""
msgid "Plugin Configuration"
msgstr ""
msgid "Notes"
msgstr ""
@@ -10583,6 +10691,9 @@ msgstr ""
msgid "Switch between Prepare/Preview"
msgstr ""
msgid "Open actions speed dial"
msgstr ""
msgid "Plater"
msgstr ""
@@ -11394,6 +11505,9 @@ msgstr ""
msgid "HTTP digest"
msgstr ""
msgid "Configuration for the plugin capabilities this preset uses, overriding the global Capabilities configuration. Stored as a raw JSON array and edited through the dialog behind the button, never typed in directly."
msgstr ""
msgid "Avoid crossing walls"
msgstr ""
@@ -12230,6 +12344,24 @@ msgid ""
"WARNING: Lowering this value may negatively affect bed adhesion."
msgstr ""
msgid "Top surface fill order"
msgstr ""
msgid ""
"Direction in which top surfaces are filled when using a center-based pattern (Concentric, Archimedean Chords, Octagram Spiral).\n"
"Outward starts at the center of the surface, so any excess material is pushed towards the edge where it is least visible. Inward starts at the edge and ends with the tight curves at the center.\n"
"Default uses shortest-path ordering, which may run in either direction."
msgstr ""
msgid "Bottom surface fill order"
msgstr ""
msgid ""
"Direction in which bottom surfaces are filled when using a center-based pattern (Concentric, Archimedean Chords, Octagram Spiral).\n"
"Inward starts each surface with the wider outer curves, which improves first layer adhesion on build plates where the tight curves at the center may not stick. Outward starts at the center, pushing any excess material towards the edge.\n"
"Default uses shortest-path ordering, which may run in either direction."
msgstr ""
msgid "Internal solid infill pattern"
msgstr ""
@@ -13358,9 +13490,6 @@ msgid ""
"Set to 0 to deactivate."
msgstr ""
msgid "%"
msgstr ""
msgid "Time cost"
msgstr ""
@@ -14011,6 +14140,9 @@ msgid ""
"RRF: X and Y values are equal."
msgstr ""
msgid "Hz"
msgstr ""
msgid "Y"
msgstr ""
@@ -14251,6 +14383,15 @@ msgstr ""
msgid "This G-code is inserted when the extrusion role is changed. It runs after the machine and filament extrusion role G-code."
msgstr ""
msgid "Plugins Used"
msgstr ""
msgid "Plugin capabilities referenced by this preset, stored as name;uuid;capability."
msgstr ""
msgid "Python plugin(s) invoked at each slicing pipeline step to read and modify intermediate slicing data, including a final G-code post-processing step. Research/experimental."
msgstr ""
msgid "Printer type"
msgstr ""
@@ -14311,6 +14452,15 @@ msgstr ""
msgid "This is the length of fast retraction before a wipe, relative to retraction length."
msgstr ""
msgid "Retract amount after wipe"
msgstr ""
#, possible-c-format
msgid ""
"The length of fast retraction after wipe, relative to retraction length.\n"
"The value will be clamped by 100% minus the retract amount before the wipe value."
msgstr ""
msgid "Retract on layer change"
msgstr ""
@@ -15243,16 +15393,6 @@ msgstr ""
msgid "The number of top solid layers is increased when slicing if the thickness calculated by top shell layers is thinner than this value. This can avoid having too thin a shell when layer height is small. 0 means that this setting is disabled and thickness of top shell is determined simply by the number of top shell layers."
msgstr ""
msgid "Anisotropic surfaces"
msgstr ""
msgid ""
"Anisotropic patterns on the top and bottom surfaces.\n"
"Co-directional printing mode will be applied. For certain patterns, omni-directional filling provides color dispersion when using multi-colored or silk plastics.\n"
"This option disable the gap fill.\n"
"This option can increase a printing time."
msgstr ""
msgid "Separated infills"
msgstr ""
@@ -16960,9 +17100,6 @@ msgstr ""
msgid "Frequency settings"
msgstr ""
msgid "Hz"
msgstr ""
msgid "RepRap firmware uses the same frequency range for both axes."
msgstr ""
@@ -18866,6 +19003,145 @@ msgstr ""
msgid "Open File"
msgstr ""
msgid "AMS Dryness Control"
msgstr ""
msgid "Filament Drying Settings"
msgstr ""
msgid "Stopping"
msgstr ""
msgid "Unable to dry temporarily due to ..."
msgstr ""
msgid "Drying Error"
msgstr ""
msgid "Please check the Assistant for troubleshooting"
msgstr ""
msgid "Please remove and store the filament (as shown)."
msgstr ""
msgid "The AMS can rotate the filament which is properly stored, providing better drying results."
msgstr ""
msgid "Rotate spool when drying"
msgstr ""
msgctxt "amsdrying"
msgid "Back"
msgstr ""
msgid "Drying-Heating"
msgstr ""
msgid "Drying-Dehumidifying"
msgstr ""
msgid " maximum drying temperature is "
msgstr ""
msgid " minimum drying temperature is "
msgstr ""
msgid "This filament may not be completely dried."
msgstr ""
msgid "This AMS is currently printing. To ensure print quality, the drying temperature cannot exceed the recommended drying temperature."
msgstr ""
msgid "The temperature shall not exceed the filament's heat distortion temperature"
msgstr ""
msgid "Minimum time value cannot be less than 1."
msgstr ""
msgid "Maximum time value cannot be greater than 24."
msgstr ""
msgid "Insufficient power"
msgstr ""
msgid " Too many AMS drying simultaneously. Please plug in the power or stop other drying processes before starting."
msgstr ""
msgid "AMS is busy"
msgstr ""
msgid " AMS is calibrating | reading RFID | loading/unloading material, please wait."
msgstr ""
msgid "Filament in AMS outlet"
msgstr ""
msgid " The high drying temperature may cause AMS blockage, please unload first."
msgstr ""
msgid "Initiating AMS drying"
msgstr ""
msgid "Not supported in 2D mode"
msgstr ""
msgid "Task in progress"
msgstr ""
msgid " The AMS might be in use during Task."
msgstr ""
msgid " Firmware update in progress, please wait..."
msgstr ""
msgid " Please plug in the power and then use the drying function."
msgstr ""
msgid " The high drying temperature may cause AMS blockage. Please unload the filament manually before proceeding."
msgstr ""
msgid "System is busy"
msgstr ""
msgid " Initiating other drying processes, please wait a few seconds..."
msgstr ""
msgid "For better drying results, remove the filament and allow it to rotate."
msgstr ""
msgid "The AMS will automatically rotate the stored filament slots to enhance the drying performance."
msgstr ""
msgid "Alternatively, you can dry the filament without removing it."
msgstr ""
msgid "Unknown filaments will be treated as PLA."
msgstr ""
msgid "Please store the filament marked with an exclamation mark."
msgstr ""
msgid "Filament left in the feeder during drying may soften because the drying temperature exceeds the softening point of materials like PLA and TPU."
msgstr ""
msgid "Starting: Checking adapter connection"
msgstr ""
msgid "Starting: Checking filament status"
msgstr ""
msgid "Starting: Checking drying presets"
msgstr ""
msgid "Starting: Checking filament location"
msgstr ""
msgid "Starting: Checking air intake"
msgstr ""
msgid "Starting: Checking air vent"
msgstr ""
msgid "The filament may not be compatible with the current machine settings. Generic filament presets will be used."
msgstr ""

View File

@@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-07-13 16:24-0300\n"
"POT-Creation-Date: 2026-07-17 15:13-0300\n"
"PO-Revision-Date: 2025-03-15 10:55+0100\n"
"Last-Translator: \n"
"Language-Team: \n"
@@ -1990,6 +1990,17 @@ msgstr "Aquesta és la versió més recent."
msgid "Info"
msgstr "Informació"
msgid "Loading Plugins"
msgstr ""
#, c-format, boost-format
msgid "Plugin %s is no longer available."
msgstr ""
#, c-format, boost-format
msgid "Plugin %s access is unauthorized."
msgstr ""
msgid "Loading printer & filament profiles"
msgstr ""
@@ -2107,6 +2118,18 @@ msgstr ""
msgid "Resolve cloud sync conflict"
msgstr ""
msgid "Syncing your account…"
msgstr ""
msgid "Migrating presets…"
msgstr ""
msgid "Fetching plugins…"
msgstr ""
msgid "Loading user presets…"
msgstr ""
msgid "Retrieving printer information, please try again later."
msgstr "Recuperant informació de la impressora, torneu-ho a provar més tard."
@@ -2232,6 +2255,21 @@ msgstr ""
msgid "*"
msgstr "*"
msgid "Plugins"
msgstr ""
#, c-format, boost-format
msgid ""
"Failed to open the Plugins dialog:\n"
"%s"
msgstr ""
msgid "Failed to open the Plugins dialog (unknown error)."
msgstr ""
msgid "Plugin Terminal"
msgstr ""
msgid "Changing application language"
msgstr "Canviant de l'idioma de l'aplicació"
@@ -5057,6 +5095,28 @@ msgstr "Format no vàlid. Format vectorial esperat: \"%1%\""
msgid "N/A"
msgstr "N/D"
msgid "System agents"
msgstr ""
msgid "No plugin selected"
msgstr ""
msgid "Add plugin"
msgstr ""
msgid "Select plugin"
msgstr ""
msgid "Remove plugin"
msgstr ""
msgid "Configure"
msgstr ""
#, c-format, boost-format
msgid "Configure (%d)"
msgstr ""
msgid "Pick"
msgstr "Tria"
@@ -5222,9 +5282,6 @@ msgstr "Ratio de Flux"
msgid "Fan speed"
msgstr "Velocitat del ventilador"
msgid "°C"
msgstr "°C"
msgid "Time"
msgstr "Temps"
@@ -7257,6 +7314,14 @@ msgctxt "Layers"
msgid "Bottom"
msgstr "Inferior"
msgid "Plugin Selection"
msgstr ""
msgid ""
"No plugins capabilities available for this type.\n"
"Enable or install some to use."
msgstr ""
msgid "Enable detection of build plate position"
msgstr "Activar detecció de la posició de la placa"
@@ -8166,6 +8231,40 @@ msgstr "Pàgina del dispositiu"
msgid "Synchronize AMS Filament Information"
msgstr "Sincronitza la informació del filament de l'AMS"
msgid "OrcaCloud plugins required by the current preset are not installed:"
msgstr ""
msgid "Install Plugins"
msgstr ""
msgid "Local plugins required by the current preset are missing:"
msgstr ""
msgid "Find on OrcaCloud"
msgstr ""
msgid "Plugins required by the current preset are not activated:"
msgstr ""
msgid "Activate Now"
msgstr ""
msgid "The installed plugin does not provide the required capability — it may be outdated:"
msgstr ""
msgid "Preparing to install plugins..."
msgstr ""
msgid "Installing plugins"
msgstr ""
msgid "Cancelling — finishing the current plugin..."
msgstr ""
#, boost-format
msgid "Installing %1%..."
msgstr ""
msgid "Plate Settings"
msgstr "Configuració de la placa"
@@ -9227,6 +9326,9 @@ msgstr "Multicolor amb extern"
msgid "Your filament grouping method in the sliced file is not optimal."
msgstr "El vostre mètode d'agrupació de filaments al fitxer tallat no és òptim."
msgid "To ensure print quality, the drying temperature will be lowered during printing."
msgstr ""
msgid "Auto Bed Leveling"
msgstr "Anivellament automàtic del llit"
@@ -9958,6 +10060,12 @@ msgstr "Codi-G de canvi del rol d'extrusió"
msgid "Post-processing Scripts"
msgstr "Scripts de postprocessament"
msgid "Slicing Pipeline Plugin"
msgstr ""
msgid "Plugin Configuration"
msgstr ""
msgid "Notes"
msgstr ""
@@ -11087,6 +11195,9 @@ msgstr ""
msgid "Switch between Prepare/Preview"
msgstr "Canviar entre Preparar/Previsualitzar"
msgid "Open actions speed dial"
msgstr ""
msgid "Plater"
msgstr "Plataforma"
@@ -11947,6 +12058,9 @@ msgstr "Codi API"
msgid "HTTP digest"
msgstr "HTTP-Digest"
msgid "Configuration for the plugin capabilities this preset uses, overriding the global Capabilities configuration. Stored as a raw JSON array and edited through the dialog behind the button, never typed in directly."
msgstr ""
msgid "Avoid crossing walls"
msgstr "Evitar creuar perímetre"
@@ -12926,6 +13040,24 @@ msgstr ""
"Densitat de la capa de superfície inferior. Destinat a fins estètics o funcionals, no per solucionar problemes com la sobreextrusió.\n"
"AVÍS: reduir aquest valor pot afectar negativament l'adhesió al llit."
msgid "Top surface fill order"
msgstr ""
msgid ""
"Direction in which top surfaces are filled when using a center-based pattern (Concentric, Archimedean Chords, Octagram Spiral).\n"
"Outward starts at the center of the surface, so any excess material is pushed towards the edge where it is least visible. Inward starts at the edge and ends with the tight curves at the center.\n"
"Default uses shortest-path ordering, which may run in either direction."
msgstr ""
msgid "Bottom surface fill order"
msgstr ""
msgid ""
"Direction in which bottom surfaces are filled when using a center-based pattern (Concentric, Archimedean Chords, Octagram Spiral).\n"
"Inward starts each surface with the wider outer curves, which improves first layer adhesion on build plates where the tight curves at the center may not stick. Outward starts at the center, pushing any excess material towards the edge.\n"
"Default uses shortest-path ordering, which may run in either direction."
msgstr ""
msgid "Internal solid infill pattern"
msgstr "Patró de farciment sòlid intern"
@@ -14158,9 +14290,6 @@ msgid ""
"Set to 0 to deactivate."
msgstr ""
msgid "%"
msgstr "%"
msgid "Time cost"
msgstr "Cost per Temps"
@@ -14848,6 +14977,9 @@ msgid ""
"RRF: X and Y values are equal."
msgstr ""
msgid "Hz"
msgstr "Hz"
msgid "Y"
msgstr "Y"
@@ -15123,6 +15255,15 @@ msgstr ""
msgid "This G-code is inserted when the extrusion role is changed. It runs after the machine and filament extrusion role G-code."
msgstr ""
msgid "Plugins Used"
msgstr ""
msgid "Plugin capabilities referenced by this preset, stored as name;uuid;capability."
msgstr ""
msgid "Python plugin(s) invoked at each slicing pipeline step to read and modify intermediate slicing data, including a final G-code post-processing step. Research/experimental."
msgstr ""
msgid "Printer type"
msgstr "Tipus d'impressora"
@@ -15191,6 +15332,15 @@ msgstr "Quantitat de retracció abans de netejar"
msgid "This is the length of fast retraction before a wipe, relative to retraction length."
msgstr "La longitud de retracció ràpida abans de la neteja, en relació amb la longitud de retracció"
msgid "Retract amount after wipe"
msgstr ""
#, c-format
msgid ""
"The length of fast retraction after wipe, relative to retraction length.\n"
"The value will be clamped by 100% minus the retract amount before the wipe value."
msgstr ""
# TODO: Review, changed by lang refactor. PR 14254
msgid "Retract on layer change"
msgstr "Retracció quan canvia de capa"
@@ -16198,16 +16348,6 @@ msgstr "Gruix mínim de la carcassa superior"
msgid "The number of top solid layers is increased when slicing if the thickness calculated by top shell layers is thinner than this value. This can avoid having too thin a shell when layer height is small. 0 means that this setting is disabled and thickness of top shell is determined simply by the number of top shell layers."
msgstr "El nombre de capes sòlides superiors augmenta quan es tallen si el gruix calculat per les capes de closca superior és més prim que aquest valor. Això pot evitar tenir una closca massa fina quan l'alçada de la capa és petita. 0 significa que aquesta configuració està desactivada i que el gruix de la carcassa superior està absolutament determinat per les capes de la carcassa superior"
msgid "Anisotropic surfaces"
msgstr ""
msgid ""
"Anisotropic patterns on the top and bottom surfaces.\n"
"Co-directional printing mode will be applied. For certain patterns, omni-directional filling provides color dispersion when using multi-colored or silk plastics.\n"
"This option disable the gap fill.\n"
"This option can increase a printing time."
msgstr ""
msgid "Separated infills"
msgstr ""
@@ -18041,9 +18181,6 @@ msgstr "Inici / Final"
msgid "Frequency settings"
msgstr "Configuració de freqüència"
msgid "Hz"
msgstr "Hz"
msgid "RepRap firmware uses the same frequency range for both axes."
msgstr "El firmware RepRap utilitza el mateix rang de freqüència per a ambdós eixos."
@@ -20036,6 +20173,145 @@ msgstr ""
msgid "Open File"
msgstr ""
msgid "AMS Dryness Control"
msgstr ""
msgid "Filament Drying Settings"
msgstr ""
msgid "Stopping"
msgstr ""
msgid "Unable to dry temporarily due to ..."
msgstr ""
msgid "Drying Error"
msgstr ""
msgid "Please check the Assistant for troubleshooting"
msgstr ""
msgid "Please remove and store the filament (as shown)."
msgstr ""
msgid "The AMS can rotate the filament which is properly stored, providing better drying results."
msgstr ""
msgid "Rotate spool when drying"
msgstr ""
msgctxt "amsdrying"
msgid "Back"
msgstr ""
msgid "Drying-Heating"
msgstr ""
msgid "Drying-Dehumidifying"
msgstr ""
msgid " maximum drying temperature is "
msgstr ""
msgid " minimum drying temperature is "
msgstr ""
msgid "This filament may not be completely dried."
msgstr ""
msgid "This AMS is currently printing. To ensure print quality, the drying temperature cannot exceed the recommended drying temperature."
msgstr ""
msgid "The temperature shall not exceed the filament's heat distortion temperature"
msgstr ""
msgid "Minimum time value cannot be less than 1."
msgstr ""
msgid "Maximum time value cannot be greater than 24."
msgstr ""
msgid "Insufficient power"
msgstr ""
msgid " Too many AMS drying simultaneously. Please plug in the power or stop other drying processes before starting."
msgstr ""
msgid "AMS is busy"
msgstr ""
msgid " AMS is calibrating | reading RFID | loading/unloading material, please wait."
msgstr ""
msgid "Filament in AMS outlet"
msgstr ""
msgid " The high drying temperature may cause AMS blockage, please unload first."
msgstr ""
msgid "Initiating AMS drying"
msgstr ""
msgid "Not supported in 2D mode"
msgstr ""
msgid "Task in progress"
msgstr ""
msgid " The AMS might be in use during Task."
msgstr ""
msgid " Firmware update in progress, please wait..."
msgstr ""
msgid " Please plug in the power and then use the drying function."
msgstr ""
msgid " The high drying temperature may cause AMS blockage. Please unload the filament manually before proceeding."
msgstr ""
msgid "System is busy"
msgstr ""
msgid " Initiating other drying processes, please wait a few seconds..."
msgstr ""
msgid "For better drying results, remove the filament and allow it to rotate."
msgstr ""
msgid "The AMS will automatically rotate the stored filament slots to enhance the drying performance."
msgstr ""
msgid "Alternatively, you can dry the filament without removing it."
msgstr ""
msgid "Unknown filaments will be treated as PLA."
msgstr ""
msgid "Please store the filament marked with an exclamation mark."
msgstr ""
msgid "Filament left in the feeder during drying may soften because the drying temperature exceeds the softening point of materials like PLA and TPU."
msgstr ""
msgid "Starting: Checking adapter connection"
msgstr ""
msgid "Starting: Checking filament status"
msgstr ""
msgid "Starting: Checking drying presets"
msgstr ""
msgid "Starting: Checking filament location"
msgstr ""
msgid "Starting: Checking air intake"
msgstr ""
msgid "Starting: Checking air vent"
msgstr ""
msgid "The filament may not be compatible with the current machine settings. Generic filament presets will be used."
msgstr "El filament pot no ser compatible amb la configuració actual de la màquina. S'utilitzaran els perfils de filament genèrics."
@@ -20358,6 +20634,12 @@ msgstr ""
"Evitar la deformació( warping )\n"
"Sabíeu que quan imprimiu materials propensos a deformar-se, com ara l'ABS, augmentar adequadament la temperatura del llit pot reduir la probabilitat de deformació?"
#~ msgid "°C"
#~ msgstr "°C"
#~ msgid "%"
#~ msgstr "%"
#~ msgid "Continue to sync filaments"
#~ msgstr "Continua sincronitzant filaments"

View File

@@ -3,7 +3,7 @@ msgid ""
msgstr ""
"Project-Id-Version: Orca Slicer\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-07-13 16:24-0300\n"
"POT-Creation-Date: 2026-07-17 15:13-0300\n"
"PO-Revision-Date: \n"
"Last-Translator: Jakub Hencl\n"
"Language-Team: \n"
@@ -1982,6 +1982,17 @@ msgstr "Toto je nejnovější verze."
msgid "Info"
msgstr ""
msgid "Loading Plugins"
msgstr ""
#, c-format, boost-format
msgid "Plugin %s is no longer available."
msgstr ""
#, c-format, boost-format
msgid "Plugin %s access is unauthorized."
msgstr ""
msgid "Loading printer & filament profiles"
msgstr ""
@@ -2099,6 +2110,18 @@ msgstr ""
msgid "Resolve cloud sync conflict"
msgstr ""
msgid "Syncing your account…"
msgstr ""
msgid "Migrating presets…"
msgstr ""
msgid "Fetching plugins…"
msgstr ""
msgid "Loading user presets…"
msgstr ""
msgid "Retrieving printer information, please try again later."
msgstr "Načítání informací o tiskárně, zkuste to prosím později."
@@ -2230,6 +2253,21 @@ msgstr ""
msgid "*"
msgstr "*"
msgid "Plugins"
msgstr ""
#, c-format, boost-format
msgid ""
"Failed to open the Plugins dialog:\n"
"%s"
msgstr ""
msgid "Failed to open the Plugins dialog (unknown error)."
msgstr ""
msgid "Plugin Terminal"
msgstr ""
msgid "Changing application language"
msgstr "Měním jazyk aplikace"
@@ -5054,6 +5092,28 @@ msgstr "Neplatný formát. Očekávaný vektorový formát: \"%1%\""
msgid "N/A"
msgstr ""
msgid "System agents"
msgstr ""
msgid "No plugin selected"
msgstr ""
msgid "Add plugin"
msgstr ""
msgid "Select plugin"
msgstr ""
msgid "Remove plugin"
msgstr ""
msgid "Configure"
msgstr ""
#, c-format, boost-format
msgid "Configure (%d)"
msgstr ""
msgid "Pick"
msgstr "Vybrat"
@@ -5219,9 +5279,6 @@ msgstr "Průtok"
msgid "Fan speed"
msgstr "Rychlost ventilátoru"
msgid "°C"
msgstr "°C"
msgid "Time"
msgstr "Čas"
@@ -7262,6 +7319,14 @@ msgctxt "Layers"
msgid "Bottom"
msgstr "Spodní"
msgid "Plugin Selection"
msgstr ""
msgid ""
"No plugins capabilities available for this type.\n"
"Enable or install some to use."
msgstr ""
msgid "Enable detection of build plate position"
msgstr "Povolit detekci pozice tiskové podložky"
@@ -8163,6 +8228,40 @@ msgstr "Stránka zařízení"
msgid "Synchronize AMS Filament Information"
msgstr "Synchronizovat informace o filamentech AMS"
msgid "OrcaCloud plugins required by the current preset are not installed:"
msgstr ""
msgid "Install Plugins"
msgstr ""
msgid "Local plugins required by the current preset are missing:"
msgstr ""
msgid "Find on OrcaCloud"
msgstr ""
msgid "Plugins required by the current preset are not activated:"
msgstr ""
msgid "Activate Now"
msgstr ""
msgid "The installed plugin does not provide the required capability — it may be outdated:"
msgstr ""
msgid "Preparing to install plugins..."
msgstr ""
msgid "Installing plugins"
msgstr ""
msgid "Cancelling — finishing the current plugin..."
msgstr ""
#, boost-format
msgid "Installing %1%..."
msgstr ""
msgid "Plate Settings"
msgstr "Nastavení desky"
@@ -9221,6 +9320,9 @@ msgstr "Vícebarevný tisk s externím filamentem"
msgid "Your filament grouping method in the sliced file is not optimal."
msgstr "Metoda seskupení filamentů ve slicovacím souboru není optimální."
msgid "To ensure print quality, the drying temperature will be lowered during printing."
msgstr ""
msgid "Auto Bed Leveling"
msgstr "Automatické vyrovnání podložky"
@@ -9949,6 +10051,12 @@ msgstr "Změnit G-code role extruze"
msgid "Post-processing Scripts"
msgstr "Post-processing skripty"
msgid "Slicing Pipeline Plugin"
msgstr ""
msgid "Plugin Configuration"
msgstr ""
msgid "Notes"
msgstr "Poznámky"
@@ -11089,6 +11197,9 @@ msgstr "Přepnout tisknutelnost objektu/části"
msgid "Switch between Prepare/Preview"
msgstr "Přepnout mezi Přípravou/Náhledem"
msgid "Open actions speed dial"
msgstr ""
msgid "Plater"
msgstr "Deska"
@@ -11953,6 +12064,9 @@ msgstr "API klíč"
msgid "HTTP digest"
msgstr ""
msgid "Configuration for the plugin capabilities this preset uses, overriding the global Capabilities configuration. Stored as a raw JSON array and edited through the dialog behind the button, never typed in directly."
msgstr ""
msgid "Avoid crossing walls"
msgstr "Vyhněte se křížení stěn"
@@ -12930,6 +13044,24 @@ msgstr ""
"Hustota spodní povrchové vrstvy. Určeno pro estetické nebo funkční účely, nikoli k řešení problémů, jako je přeextruze.\n"
"VAROVÁNÍ: Snížení této hodnoty může negativně ovlivnit přilnavost k podložce."
msgid "Top surface fill order"
msgstr ""
msgid ""
"Direction in which top surfaces are filled when using a center-based pattern (Concentric, Archimedean Chords, Octagram Spiral).\n"
"Outward starts at the center of the surface, so any excess material is pushed towards the edge where it is least visible. Inward starts at the edge and ends with the tight curves at the center.\n"
"Default uses shortest-path ordering, which may run in either direction."
msgstr ""
msgid "Bottom surface fill order"
msgstr ""
msgid ""
"Direction in which bottom surfaces are filled when using a center-based pattern (Concentric, Archimedean Chords, Octagram Spiral).\n"
"Inward starts each surface with the wider outer curves, which improves first layer adhesion on build plates where the tight curves at the center may not stick. Outward starts at the center, pushing any excess material towards the edge.\n"
"Default uses shortest-path ordering, which may run in either direction."
msgstr ""
msgid "Internal solid infill pattern"
msgstr "Vzor vnitřní plné výplně"
@@ -14182,9 +14314,6 @@ msgid ""
"Set to 0 to deactivate."
msgstr ""
msgid "%"
msgstr "%"
msgid "Time cost"
msgstr "Časová náročnost"
@@ -14885,6 +15014,9 @@ msgstr ""
"Pro vypnutí input shapingu použijte typ Zakázat.\n"
"RRF: Hodnoty X a Y jsou shodné."
msgid "Hz"
msgstr "Hz"
msgid "Y"
msgstr "Y"
@@ -15170,6 +15302,15 @@ msgstr "G-code při změně role extruze (proces)"
msgid "This G-code is inserted when the extrusion role is changed. It runs after the machine and filament extrusion role G-code."
msgstr "Tento G-code se vloží při změně role extruze. Spouští se po G-code změny role extruze tiskárny a filamentu."
msgid "Plugins Used"
msgstr ""
msgid "Plugin capabilities referenced by this preset, stored as name;uuid;capability."
msgstr ""
msgid "Python plugin(s) invoked at each slicing pipeline step to read and modify intermediate slicing data, including a final G-code post-processing step. Research/experimental."
msgstr ""
msgid "Printer type"
msgstr "Typ tiskárny"
@@ -15238,6 +15379,15 @@ msgstr "Množství retrakce před setřením"
msgid "This is the length of fast retraction before a wipe, relative to retraction length."
msgstr "Délka rychlého zpětného pohybu před setřením, relativně k délce zatažení."
msgid "Retract amount after wipe"
msgstr ""
#, c-format
msgid ""
"The length of fast retraction after wipe, relative to retraction length.\n"
"The value will be clamped by 100% minus the retract amount before the wipe value."
msgstr ""
# TODO: Review, changed by lang refactor. PR 14254
msgid "Retract on layer change"
msgstr "Retrakce při změně vrstvy"
@@ -16240,16 +16390,6 @@ msgstr "Tloušťka horního pláště"
msgid "The number of top solid layers is increased when slicing if the thickness calculated by top shell layers is thinner than this value. This can avoid having too thin a shell when layer height is small. 0 means that this setting is disabled and thickness of top shell is determined simply by the number of top shell layers."
msgstr "Počet horních pevných vrstev bude při slicování zvýšen, pokud tloušťka vypočtená podle horních vrstev bude menší než tato hodnota. Tím lze předejít příliš tenké skořepině při malé výšce vrstvy. 0 znamená, že je nastavení vypnuté a tloušťka horní skořepiny je určena pouze počtem horních vrstev."
msgid "Anisotropic surfaces"
msgstr ""
msgid ""
"Anisotropic patterns on the top and bottom surfaces.\n"
"Co-directional printing mode will be applied. For certain patterns, omni-directional filling provides color dispersion when using multi-colored or silk plastics.\n"
"This option disable the gap fill.\n"
"This option can increase a printing time."
msgstr ""
msgid "Separated infills"
msgstr ""
@@ -18081,9 +18221,6 @@ msgstr "Začátek / Konec"
msgid "Frequency settings"
msgstr "Nastavení frekvence"
msgid "Hz"
msgstr "Hz"
msgid "RepRap firmware uses the same frequency range for both axes."
msgstr "Firmware RepRap používá stejný rozsah frekvence pro obě osy."
@@ -20070,6 +20207,145 @@ msgstr ""
msgid "Open File"
msgstr ""
msgid "AMS Dryness Control"
msgstr ""
msgid "Filament Drying Settings"
msgstr ""
msgid "Stopping"
msgstr ""
msgid "Unable to dry temporarily due to ..."
msgstr ""
msgid "Drying Error"
msgstr ""
msgid "Please check the Assistant for troubleshooting"
msgstr ""
msgid "Please remove and store the filament (as shown)."
msgstr ""
msgid "The AMS can rotate the filament which is properly stored, providing better drying results."
msgstr ""
msgid "Rotate spool when drying"
msgstr ""
msgctxt "amsdrying"
msgid "Back"
msgstr ""
msgid "Drying-Heating"
msgstr ""
msgid "Drying-Dehumidifying"
msgstr ""
msgid " maximum drying temperature is "
msgstr ""
msgid " minimum drying temperature is "
msgstr ""
msgid "This filament may not be completely dried."
msgstr ""
msgid "This AMS is currently printing. To ensure print quality, the drying temperature cannot exceed the recommended drying temperature."
msgstr ""
msgid "The temperature shall not exceed the filament's heat distortion temperature"
msgstr ""
msgid "Minimum time value cannot be less than 1."
msgstr ""
msgid "Maximum time value cannot be greater than 24."
msgstr ""
msgid "Insufficient power"
msgstr ""
msgid " Too many AMS drying simultaneously. Please plug in the power or stop other drying processes before starting."
msgstr ""
msgid "AMS is busy"
msgstr ""
msgid " AMS is calibrating | reading RFID | loading/unloading material, please wait."
msgstr ""
msgid "Filament in AMS outlet"
msgstr ""
msgid " The high drying temperature may cause AMS blockage, please unload first."
msgstr ""
msgid "Initiating AMS drying"
msgstr ""
msgid "Not supported in 2D mode"
msgstr ""
msgid "Task in progress"
msgstr ""
msgid " The AMS might be in use during Task."
msgstr ""
msgid " Firmware update in progress, please wait..."
msgstr ""
msgid " Please plug in the power and then use the drying function."
msgstr ""
msgid " The high drying temperature may cause AMS blockage. Please unload the filament manually before proceeding."
msgstr ""
msgid "System is busy"
msgstr ""
msgid " Initiating other drying processes, please wait a few seconds..."
msgstr ""
msgid "For better drying results, remove the filament and allow it to rotate."
msgstr ""
msgid "The AMS will automatically rotate the stored filament slots to enhance the drying performance."
msgstr ""
msgid "Alternatively, you can dry the filament without removing it."
msgstr ""
msgid "Unknown filaments will be treated as PLA."
msgstr ""
msgid "Please store the filament marked with an exclamation mark."
msgstr ""
msgid "Filament left in the feeder during drying may soften because the drying temperature exceeds the softening point of materials like PLA and TPU."
msgstr ""
msgid "Starting: Checking adapter connection"
msgstr ""
msgid "Starting: Checking filament status"
msgstr ""
msgid "Starting: Checking drying presets"
msgstr ""
msgid "Starting: Checking filament location"
msgstr ""
msgid "Starting: Checking air intake"
msgstr ""
msgid "Starting: Checking air vent"
msgstr ""
msgid "The filament may not be compatible with the current machine settings. Generic filament presets will be used."
msgstr ""
@@ -20392,6 +20668,12 @@ msgstr ""
"Zamezte kroucení\n"
"Víte, že při tisku materiálů náchylných ke kroucení, jako je ABS, může vhodné zvýšení teploty vyhřívané desky snížit pravděpodobnost kroucení?"
#~ msgid "°C"
#~ msgstr "°C"
#~ msgid "%"
#~ msgstr "%"
#~ msgid "Align infill direction to model"
#~ msgstr "Zarovnat směr výplně podle modelu"

View File

@@ -3,7 +3,7 @@ msgid ""
msgstr ""
"Project-Id-Version: Orca Slicer\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-07-13 16:24-0300\n"
"POT-Creation-Date: 2026-07-17 15:13-0300\n"
"PO-Revision-Date: \n"
"Last-Translator: Heiko Liebscher <hliebschergmail.com>\n"
"Language-Team: \n"
@@ -1986,6 +1986,17 @@ msgstr "Dies ist die neueste Version."
msgid "Info"
msgstr "Info"
msgid "Loading Plugins"
msgstr ""
#, c-format, boost-format
msgid "Plugin %s is no longer available."
msgstr ""
#, c-format, boost-format
msgid "Plugin %s access is unauthorized."
msgstr ""
msgid "Loading printer & filament profiles"
msgstr "Lade Drucker- und Filamentprofile"
@@ -2105,6 +2116,18 @@ msgstr ""
msgid "Resolve cloud sync conflict"
msgstr "Cloud-Synchronisationskonflikt lösen"
msgid "Syncing your account…"
msgstr ""
msgid "Migrating presets…"
msgstr ""
msgid "Fetching plugins…"
msgstr ""
msgid "Loading user presets…"
msgstr ""
msgid "Retrieving printer information, please try again later."
msgstr "Empfange Druckerinformationen, bitte später erneut versuchen."
@@ -2235,6 +2258,21 @@ msgstr ""
msgid "*"
msgstr "*"
msgid "Plugins"
msgstr ""
#, c-format, boost-format
msgid ""
"Failed to open the Plugins dialog:\n"
"%s"
msgstr ""
msgid "Failed to open the Plugins dialog (unknown error)."
msgstr ""
msgid "Plugin Terminal"
msgstr ""
msgid "Changing application language"
msgstr "Anwendungssprache ändern"
@@ -5058,6 +5096,28 @@ msgstr "Ungültiges Format. Erwartetes Vektorformat: \"%1%\""
msgid "N/A"
msgstr "Nicht verfügbar"
msgid "System agents"
msgstr ""
msgid "No plugin selected"
msgstr ""
msgid "Add plugin"
msgstr ""
msgid "Select plugin"
msgstr ""
msgid "Remove plugin"
msgstr ""
msgid "Configure"
msgstr ""
#, c-format, boost-format
msgid "Configure (%d)"
msgstr ""
msgid "Pick"
msgstr "Wähle"
@@ -5223,9 +5283,6 @@ msgstr "Durchflussrate"
msgid "Fan speed"
msgstr "Lüftergeschwindigkeit"
msgid "°C"
msgstr "°C"
msgid "Time"
msgstr "Zeit"
@@ -7260,6 +7317,14 @@ msgctxt "Layers"
msgid "Bottom"
msgstr "Untere"
msgid "Plugin Selection"
msgstr ""
msgid ""
"No plugins capabilities available for this type.\n"
"Enable or install some to use."
msgstr ""
msgid "Enable detection of build plate position"
msgstr "Positionserkennung der Druckplatte aktivieren"
@@ -8170,6 +8235,40 @@ msgstr "Geräteseite"
msgid "Synchronize AMS Filament Information"
msgstr "Synchronisiere AMS-Filamentinformationen"
msgid "OrcaCloud plugins required by the current preset are not installed:"
msgstr ""
msgid "Install Plugins"
msgstr ""
msgid "Local plugins required by the current preset are missing:"
msgstr ""
msgid "Find on OrcaCloud"
msgstr ""
msgid "Plugins required by the current preset are not activated:"
msgstr ""
msgid "Activate Now"
msgstr ""
msgid "The installed plugin does not provide the required capability — it may be outdated:"
msgstr ""
msgid "Preparing to install plugins..."
msgstr ""
msgid "Installing plugins"
msgstr ""
msgid "Cancelling — finishing the current plugin..."
msgstr ""
#, boost-format
msgid "Installing %1%..."
msgstr ""
msgid "Plate Settings"
msgstr "Druck-Platteneinstellungen"
@@ -9246,6 +9345,9 @@ msgstr "Mehrfarben mit externen Spulen"
msgid "Your filament grouping method in the sliced file is not optimal."
msgstr "Ihre Filament-Gruppierungsmethode in der gesliceten Datei ist nicht optimal."
msgid "To ensure print quality, the drying temperature will be lowered during printing."
msgstr ""
msgid "Auto Bed Leveling"
msgstr "Automatische Bett-Nivellierung"
@@ -9972,6 +10074,12 @@ msgstr "Ändere den G-Code der Extrusionsart"
msgid "Post-processing Scripts"
msgstr "Nachbearbeitungsskripte"
msgid "Slicing Pipeline Plugin"
msgstr ""
msgid "Plugin Configuration"
msgstr ""
msgid "Notes"
msgstr "Notizen"
@@ -11118,6 +11226,9 @@ msgstr "Druckbar für Objekt/Teil umschalten"
msgid "Switch between Prepare/Preview"
msgstr "Zwischen Vorbereiten/ Vorschau wechseln"
msgid "Open actions speed dial"
msgstr ""
msgid "Plater"
msgstr "Druckplatte"
@@ -11985,6 +12096,9 @@ msgstr "API-Schlüssel"
msgid "HTTP digest"
msgstr "HTTP-Digest"
msgid "Configuration for the plugin capabilities this preset uses, overriding the global Capabilities configuration. Stored as a raw JSON array and edited through the dialog behind the button, never typed in directly."
msgstr ""
msgid "Avoid crossing walls"
msgstr "Vermeiden von Wandüberquerungen"
@@ -13017,6 +13131,24 @@ msgstr ""
"Dichte der unteren Oberflächenschicht. Diese Einstellung dient ästhetischen oder funktionalen Zwecken und nicht zur Behebung von Problemen wie Überextrusion.\n"
"ACHTUNG: Eine Verringerung dieses Wertes kann die Haftung am Druckbett negativ beeinflussen."
msgid "Top surface fill order"
msgstr ""
msgid ""
"Direction in which top surfaces are filled when using a center-based pattern (Concentric, Archimedean Chords, Octagram Spiral).\n"
"Outward starts at the center of the surface, so any excess material is pushed towards the edge where it is least visible. Inward starts at the edge and ends with the tight curves at the center.\n"
"Default uses shortest-path ordering, which may run in either direction."
msgstr ""
msgid "Bottom surface fill order"
msgstr ""
msgid ""
"Direction in which bottom surfaces are filled when using a center-based pattern (Concentric, Archimedean Chords, Octagram Spiral).\n"
"Inward starts each surface with the wider outer curves, which improves first layer adhesion on build plates where the tight curves at the center may not stick. Outward starts at the center, pushing any excess material towards the edge.\n"
"Default uses shortest-path ordering, which may run in either direction."
msgstr ""
msgid "Internal solid infill pattern"
msgstr "Muster für das interne feste Füllmuster"
@@ -14270,9 +14402,6 @@ msgstr ""
"\n"
"Setze den Wert auf 0, um diese Funktion zu deaktivieren."
msgid "%"
msgstr "%"
msgid "Time cost"
msgstr "Druckzeit Kosten"
@@ -14974,6 +15103,9 @@ msgstr ""
"Um die Eingangsformung zu deaktivieren, verwenden Sie den Typ Deaktivieren.\n"
"RRF: X- und Y-Werte sind gleich."
msgid "Hz"
msgstr "Hz"
msgid "Y"
msgstr "Y"
@@ -15261,6 +15393,15 @@ msgstr "G-Code für den Wechsel der Extrusionsrolle (Prozess)"
msgid "This G-code is inserted when the extrusion role is changed. It runs after the machine and filament extrusion role G-code."
msgstr "Dieser G-Code wird eingefügt, wenn die Extrusionsrolle gewechselt wird. Er wird nach dem G-Code für die Maschine und die Filamentextrusionsrolle ausgeführt."
msgid "Plugins Used"
msgstr ""
msgid "Plugin capabilities referenced by this preset, stored as name;uuid;capability."
msgstr ""
msgid "Python plugin(s) invoked at each slicing pipeline step to read and modify intermediate slicing data, including a final G-code post-processing step. Research/experimental."
msgstr ""
msgid "Printer type"
msgstr "Druckertyp"
@@ -15329,6 +15470,15 @@ msgstr "Rückzugsmenge vor der Reinigung"
msgid "This is the length of fast retraction before a wipe, relative to retraction length."
msgstr "Die Länge des schnellen Rückzugs vor dem Abwischen, relativ zur Rückzugslänge."
msgid "Retract amount after wipe"
msgstr ""
#, c-format
msgid ""
"The length of fast retraction after wipe, relative to retraction length.\n"
"The value will be clamped by 100% minus the retract amount before the wipe value."
msgstr ""
# TODO: Review, changed by lang refactor. PR 14254
msgid "Retract on layer change"
msgstr "Zurückziehen beim Schichtwechsel"
@@ -16356,16 +16506,6 @@ msgstr "Dicke der oberen Schale"
msgid "The number of top solid layers is increased when slicing if the thickness calculated by top shell layers is thinner than this value. This can avoid having too thin a shell when layer height is small. 0 means that this setting is disabled and thickness of top shell is determined simply by the number of top shell layers."
msgstr "Die Anzahl der oberen festen Schichten wird beim Slicen erhöht, wenn die obere Schalenstärke dünner als dieser Wert ist. Dies kann verhindern, dass die Schale zu dünn wird, wenn eine geringe Schichthöhe verwendet wird. 0 bedeutet, dass diese Einstellung deaktiviert ist und die Dicke der oberen Schale absolut durch die oberen Schalenschichten bestimmt wird."
msgid "Anisotropic surfaces"
msgstr ""
msgid ""
"Anisotropic patterns on the top and bottom surfaces.\n"
"Co-directional printing mode will be applied. For certain patterns, omni-directional filling provides color dispersion when using multi-colored or silk plastics.\n"
"This option disable the gap fill.\n"
"This option can increase a printing time."
msgstr ""
msgid "Separated infills"
msgstr ""
@@ -18197,9 +18337,6 @@ msgstr "Start / Ende"
msgid "Frequency settings"
msgstr "Frequenz Einstellungen"
msgid "Hz"
msgstr "Hz"
msgid "RepRap firmware uses the same frequency range for both axes."
msgstr "RepRap-Firmware verwendet denselben Frequenzbereich für beide Achsen."
@@ -20200,6 +20337,145 @@ msgstr "Archivvorschau"
msgid "Open File"
msgstr "Datei öffnen"
msgid "AMS Dryness Control"
msgstr ""
msgid "Filament Drying Settings"
msgstr ""
msgid "Stopping"
msgstr ""
msgid "Unable to dry temporarily due to ..."
msgstr ""
msgid "Drying Error"
msgstr ""
msgid "Please check the Assistant for troubleshooting"
msgstr ""
msgid "Please remove and store the filament (as shown)."
msgstr ""
msgid "The AMS can rotate the filament which is properly stored, providing better drying results."
msgstr ""
msgid "Rotate spool when drying"
msgstr ""
msgctxt "amsdrying"
msgid "Back"
msgstr ""
msgid "Drying-Heating"
msgstr ""
msgid "Drying-Dehumidifying"
msgstr ""
msgid " maximum drying temperature is "
msgstr ""
msgid " minimum drying temperature is "
msgstr ""
msgid "This filament may not be completely dried."
msgstr ""
msgid "This AMS is currently printing. To ensure print quality, the drying temperature cannot exceed the recommended drying temperature."
msgstr ""
msgid "The temperature shall not exceed the filament's heat distortion temperature"
msgstr ""
msgid "Minimum time value cannot be less than 1."
msgstr ""
msgid "Maximum time value cannot be greater than 24."
msgstr ""
msgid "Insufficient power"
msgstr ""
msgid " Too many AMS drying simultaneously. Please plug in the power or stop other drying processes before starting."
msgstr ""
msgid "AMS is busy"
msgstr ""
msgid " AMS is calibrating | reading RFID | loading/unloading material, please wait."
msgstr ""
msgid "Filament in AMS outlet"
msgstr ""
msgid " The high drying temperature may cause AMS blockage, please unload first."
msgstr ""
msgid "Initiating AMS drying"
msgstr ""
msgid "Not supported in 2D mode"
msgstr ""
msgid "Task in progress"
msgstr ""
msgid " The AMS might be in use during Task."
msgstr ""
msgid " Firmware update in progress, please wait..."
msgstr ""
msgid " Please plug in the power and then use the drying function."
msgstr ""
msgid " The high drying temperature may cause AMS blockage. Please unload the filament manually before proceeding."
msgstr ""
msgid "System is busy"
msgstr ""
msgid " Initiating other drying processes, please wait a few seconds..."
msgstr ""
msgid "For better drying results, remove the filament and allow it to rotate."
msgstr ""
msgid "The AMS will automatically rotate the stored filament slots to enhance the drying performance."
msgstr ""
msgid "Alternatively, you can dry the filament without removing it."
msgstr ""
msgid "Unknown filaments will be treated as PLA."
msgstr ""
msgid "Please store the filament marked with an exclamation mark."
msgstr ""
msgid "Filament left in the feeder during drying may soften because the drying temperature exceeds the softening point of materials like PLA and TPU."
msgstr ""
msgid "Starting: Checking adapter connection"
msgstr ""
msgid "Starting: Checking filament status"
msgstr ""
msgid "Starting: Checking drying presets"
msgstr ""
msgid "Starting: Checking filament location"
msgstr ""
msgid "Starting: Checking air intake"
msgstr ""
msgid "Starting: Checking air vent"
msgstr ""
msgid "The filament may not be compatible with the current machine settings. Generic filament presets will be used."
msgstr "Das Filament ist möglicherweise nicht mit den aktuellen Maschineneinstellungen kompatibel. Es werden generische Filament-Profile verwendet."
@@ -20524,6 +20800,12 @@ msgstr ""
"Verwerfungen vermeiden\n"
"Wussten Sie, dass beim Drucken von Materialien, die zu Verwerfungen neigen, wie z.B. ABS, durch eine entsprechende Erhöhung der Heizbetttemperatur die Wahrscheinlichkeit von Verwerfungen verringert werden kann?"
#~ msgid "°C"
#~ msgstr "°C"
#~ msgid "%"
#~ msgstr "%"
#~ msgid "Renders cast shadows on the plate in realistic view."
#~ msgstr "Zeigt geworfene Schatten auf der Platte in der realistischen Ansicht an."

View File

@@ -3,7 +3,7 @@ msgid ""
msgstr ""
"Project-Id-Version: Orca Slicer\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-07-13 16:24-0300\n"
"POT-Creation-Date: 2026-07-17 15:13-0300\n"
"PO-Revision-Date: 2026-06-17 15:44-0300\n"
"Last-Translator: Alexandre Folle de Menezes\n"
"Language-Team: \n"
@@ -1931,6 +1931,17 @@ msgstr ""
msgid "Info"
msgstr ""
msgid "Loading Plugins"
msgstr ""
#, c-format, boost-format
msgid "Plugin %s is no longer available."
msgstr ""
#, c-format, boost-format
msgid "Plugin %s access is unauthorized."
msgstr ""
msgid "Loading printer & filament profiles"
msgstr ""
@@ -2044,6 +2055,18 @@ msgstr ""
msgid "Resolve cloud sync conflict"
msgstr ""
msgid "Syncing your account…"
msgstr ""
msgid "Migrating presets…"
msgstr ""
msgid "Fetching plugins…"
msgstr ""
msgid "Loading user presets…"
msgstr ""
msgid "Retrieving printer information, please try again later."
msgstr ""
@@ -2162,6 +2185,21 @@ msgstr ""
msgid "*"
msgstr ""
msgid "Plugins"
msgstr ""
#, c-format, boost-format
msgid ""
"Failed to open the Plugins dialog:\n"
"%s"
msgstr ""
msgid "Failed to open the Plugins dialog (unknown error)."
msgstr ""
msgid "Plugin Terminal"
msgstr ""
msgid "Changing application language"
msgstr ""
@@ -4805,6 +4843,28 @@ msgstr ""
msgid "N/A"
msgstr ""
msgid "System agents"
msgstr ""
msgid "No plugin selected"
msgstr ""
msgid "Add plugin"
msgstr ""
msgid "Select plugin"
msgstr ""
msgid "Remove plugin"
msgstr ""
msgid "Configure"
msgstr ""
#, c-format, boost-format
msgid "Configure (%d)"
msgstr ""
msgid "Pick"
msgstr ""
@@ -4970,9 +5030,6 @@ msgstr ""
msgid "Fan speed"
msgstr ""
msgid "°C"
msgstr ""
msgid "Time"
msgstr ""
@@ -6935,6 +6992,14 @@ msgctxt "Layers"
msgid "Bottom"
msgstr ""
msgid "Plugin Selection"
msgstr ""
msgid ""
"No plugins capabilities available for this type.\n"
"Enable or install some to use."
msgstr ""
msgid "Enable detection of build plate position"
msgstr ""
@@ -7787,6 +7852,40 @@ msgstr ""
msgid "Synchronize AMS Filament Information"
msgstr ""
msgid "OrcaCloud plugins required by the current preset are not installed:"
msgstr ""
msgid "Install Plugins"
msgstr ""
msgid "Local plugins required by the current preset are missing:"
msgstr ""
msgid "Find on OrcaCloud"
msgstr ""
msgid "Plugins required by the current preset are not activated:"
msgstr ""
msgid "Activate Now"
msgstr ""
msgid "The installed plugin does not provide the required capability — it may be outdated:"
msgstr ""
msgid "Preparing to install plugins..."
msgstr ""
msgid "Installing plugins"
msgstr ""
msgid "Cancelling — finishing the current plugin..."
msgstr ""
#, boost-format
msgid "Installing %1%..."
msgstr ""
msgid "Plate Settings"
msgstr ""
@@ -8810,6 +8909,9 @@ msgstr ""
msgid "Your filament grouping method in the sliced file is not optimal."
msgstr ""
msgid "To ensure print quality, the drying temperature will be lowered during printing."
msgstr ""
msgid "Auto Bed Leveling"
msgstr ""
@@ -9503,6 +9605,12 @@ msgstr ""
msgid "Post-processing Scripts"
msgstr ""
msgid "Slicing Pipeline Plugin"
msgstr ""
msgid "Plugin Configuration"
msgstr ""
msgid "Notes"
msgstr ""
@@ -10579,6 +10687,9 @@ msgstr ""
msgid "Switch between Prepare/Preview"
msgstr ""
msgid "Open actions speed dial"
msgstr ""
msgid "Plater"
msgstr ""
@@ -11390,6 +11501,9 @@ msgstr ""
msgid "HTTP digest"
msgstr ""
msgid "Configuration for the plugin capabilities this preset uses, overriding the global Capabilities configuration. Stored as a raw JSON array and edited through the dialog behind the button, never typed in directly."
msgstr ""
msgid "Avoid crossing walls"
msgstr ""
@@ -12226,6 +12340,24 @@ msgid ""
"WARNING: Lowering this value may negatively affect bed adhesion."
msgstr ""
msgid "Top surface fill order"
msgstr ""
msgid ""
"Direction in which top surfaces are filled when using a center-based pattern (Concentric, Archimedean Chords, Octagram Spiral).\n"
"Outward starts at the center of the surface, so any excess material is pushed towards the edge where it is least visible. Inward starts at the edge and ends with the tight curves at the center.\n"
"Default uses shortest-path ordering, which may run in either direction."
msgstr ""
msgid "Bottom surface fill order"
msgstr ""
msgid ""
"Direction in which bottom surfaces are filled when using a center-based pattern (Concentric, Archimedean Chords, Octagram Spiral).\n"
"Inward starts each surface with the wider outer curves, which improves first layer adhesion on build plates where the tight curves at the center may not stick. Outward starts at the center, pushing any excess material towards the edge.\n"
"Default uses shortest-path ordering, which may run in either direction."
msgstr ""
msgid "Internal solid infill pattern"
msgstr ""
@@ -13354,9 +13486,6 @@ msgid ""
"Set to 0 to deactivate."
msgstr ""
msgid "%"
msgstr ""
msgid "Time cost"
msgstr ""
@@ -14007,6 +14136,9 @@ msgid ""
"RRF: X and Y values are equal."
msgstr ""
msgid "Hz"
msgstr ""
msgid "Y"
msgstr ""
@@ -14247,6 +14379,15 @@ msgstr ""
msgid "This G-code is inserted when the extrusion role is changed. It runs after the machine and filament extrusion role G-code."
msgstr ""
msgid "Plugins Used"
msgstr ""
msgid "Plugin capabilities referenced by this preset, stored as name;uuid;capability."
msgstr ""
msgid "Python plugin(s) invoked at each slicing pipeline step to read and modify intermediate slicing data, including a final G-code post-processing step. Research/experimental."
msgstr ""
msgid "Printer type"
msgstr ""
@@ -14307,6 +14448,15 @@ msgstr ""
msgid "This is the length of fast retraction before a wipe, relative to retraction length."
msgstr ""
msgid "Retract amount after wipe"
msgstr ""
#, c-format
msgid ""
"The length of fast retraction after wipe, relative to retraction length.\n"
"The value will be clamped by 100% minus the retract amount before the wipe value."
msgstr ""
msgid "Retract on layer change"
msgstr ""
@@ -15239,16 +15389,6 @@ msgstr ""
msgid "The number of top solid layers is increased when slicing if the thickness calculated by top shell layers is thinner than this value. This can avoid having too thin a shell when layer height is small. 0 means that this setting is disabled and thickness of top shell is determined simply by the number of top shell layers."
msgstr ""
msgid "Anisotropic surfaces"
msgstr ""
msgid ""
"Anisotropic patterns on the top and bottom surfaces.\n"
"Co-directional printing mode will be applied. For certain patterns, omni-directional filling provides color dispersion when using multi-colored or silk plastics.\n"
"This option disable the gap fill.\n"
"This option can increase a printing time."
msgstr ""
msgid "Separated infills"
msgstr ""
@@ -16956,9 +17096,6 @@ msgstr ""
msgid "Frequency settings"
msgstr ""
msgid "Hz"
msgstr ""
msgid "RepRap firmware uses the same frequency range for both axes."
msgstr ""
@@ -18862,6 +18999,145 @@ msgstr ""
msgid "Open File"
msgstr ""
msgid "AMS Dryness Control"
msgstr ""
msgid "Filament Drying Settings"
msgstr ""
msgid "Stopping"
msgstr ""
msgid "Unable to dry temporarily due to ..."
msgstr ""
msgid "Drying Error"
msgstr ""
msgid "Please check the Assistant for troubleshooting"
msgstr ""
msgid "Please remove and store the filament (as shown)."
msgstr ""
msgid "The AMS can rotate the filament which is properly stored, providing better drying results."
msgstr ""
msgid "Rotate spool when drying"
msgstr ""
msgctxt "amsdrying"
msgid "Back"
msgstr ""
msgid "Drying-Heating"
msgstr ""
msgid "Drying-Dehumidifying"
msgstr ""
msgid " maximum drying temperature is "
msgstr ""
msgid " minimum drying temperature is "
msgstr ""
msgid "This filament may not be completely dried."
msgstr ""
msgid "This AMS is currently printing. To ensure print quality, the drying temperature cannot exceed the recommended drying temperature."
msgstr ""
msgid "The temperature shall not exceed the filament's heat distortion temperature"
msgstr ""
msgid "Minimum time value cannot be less than 1."
msgstr ""
msgid "Maximum time value cannot be greater than 24."
msgstr ""
msgid "Insufficient power"
msgstr ""
msgid " Too many AMS drying simultaneously. Please plug in the power or stop other drying processes before starting."
msgstr ""
msgid "AMS is busy"
msgstr ""
msgid " AMS is calibrating | reading RFID | loading/unloading material, please wait."
msgstr ""
msgid "Filament in AMS outlet"
msgstr ""
msgid " The high drying temperature may cause AMS blockage, please unload first."
msgstr ""
msgid "Initiating AMS drying"
msgstr ""
msgid "Not supported in 2D mode"
msgstr ""
msgid "Task in progress"
msgstr ""
msgid " The AMS might be in use during Task."
msgstr ""
msgid " Firmware update in progress, please wait..."
msgstr ""
msgid " Please plug in the power and then use the drying function."
msgstr ""
msgid " The high drying temperature may cause AMS blockage. Please unload the filament manually before proceeding."
msgstr ""
msgid "System is busy"
msgstr ""
msgid " Initiating other drying processes, please wait a few seconds..."
msgstr ""
msgid "For better drying results, remove the filament and allow it to rotate."
msgstr ""
msgid "The AMS will automatically rotate the stored filament slots to enhance the drying performance."
msgstr ""
msgid "Alternatively, you can dry the filament without removing it."
msgstr ""
msgid "Unknown filaments will be treated as PLA."
msgstr ""
msgid "Please store the filament marked with an exclamation mark."
msgstr ""
msgid "Filament left in the feeder during drying may soften because the drying temperature exceeds the softening point of materials like PLA and TPU."
msgstr ""
msgid "Starting: Checking adapter connection"
msgstr ""
msgid "Starting: Checking filament status"
msgstr ""
msgid "Starting: Checking drying presets"
msgstr ""
msgid "Starting: Checking filament location"
msgstr ""
msgid "Starting: Checking air intake"
msgstr ""
msgid "Starting: Checking air vent"
msgstr ""
msgid "The filament may not be compatible with the current machine settings. Generic filament presets will be used."
msgstr ""

View File

@@ -3,7 +3,7 @@ msgid ""
msgstr ""
"Project-Id-Version: Orca Slicer\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-07-13 16:24-0300\n"
"POT-Creation-Date: 2026-07-17 15:13-0300\n"
"PO-Revision-Date: \n"
"Last-Translator: Ian A. Bassi <>\n"
"Language-Team: \n"
@@ -36,22 +36,22 @@ msgid "AMS does not support 'Bambu Lab PET-CF'."
msgstr "'Bambu Lab PET-CF' no soportado por el AMS."
msgid "The current filament doesn't support the E3D high-flow nozzle and can't be used."
msgstr ""
msgstr "El filamento actual no es compatible con la boquilla de alto flujo E3D y no se puede utilizar."
msgid "The current filament doesn't support the TPU high-flow nozzle and can't be used."
msgstr ""
msgstr "El filamento actual no es compatible con la boquilla de alto flujo para TPU y no se puede utilizar."
msgid "Auto dynamic flow calibration is not supported for TPU filament."
msgstr ""
msgstr "La calibración dinámica automática de flujo no es compatible con el filamento TPU."
msgid "Bambu TPU 85A is not supported for printing with 0.4 mm Standard or High Flow nozzles."
msgstr ""
msgstr "El Bambu TPU 85A no es compatible con la impresión con boquillas estándar o de alto flujo de 0,4 mm."
msgid "How to feed TPU filament."
msgstr ""
msgstr "Cómo alimentar el filamento TPU."
msgid "How to feed TPU filament on X2D."
msgstr ""
msgstr "Cómo alimentar el filamento TPU en la X2D."
msgid "Please cold pull before printing TPU to avoid clogging. You may use cold pull maintenance on the printer."
msgstr "Por favor, realice un cold pull antes de imprimir TPU para evitar obstrucciones. Puede utilizar el cold pull de mantenimiento de la impresora."
@@ -66,7 +66,7 @@ msgid "The rough surface of PLA Glow can accelerate wear on the AMS system, part
msgstr "La superficie rugosa del PLA Glow puede acelerar el desgaste del sistema AMS, especialmente en los componentes internos del AMS Lite."
msgid "PLA Glow may wear the AMS first stage feeder. Use an external spool instead."
msgstr ""
msgstr "El PLA Glow puede desgastar el alimentador de primera etapa del AMS. Utilice un carrete externo en su lugar."
msgid "CF/GF filaments are hard and brittle, it's easy to break or get stuck in AMS, please use with caution."
msgstr "Los filamentos CF/GF son duros y quebradizos. Es fácil romperlos o crear atascos en el AMS, por favor úselos con precaución."
@@ -78,23 +78,23 @@ msgid "PPA-CF is brittle and could break in bended PTFE tube above Toolhead."
msgstr "PPA-CF es quebradizo y podría romperse en el tubo PTFE doblado por encima del cabezal de la herramienta."
msgid "Default settings may affect print quality. Adjust as needed for best results."
msgstr ""
msgstr "La configuración predeterminada puede afectar a la calidad de impresión. Ajústela según sea necesario para obtener los mejores resultados."
#, c-format, boost-format
msgid "%s has a risk of nozzle clogging when using 0.4mm high-flow nozzles. Use with caution."
msgstr ""
msgstr "%s tiene riesgo de obstrucción de la boquilla al usar boquillas de alto flujo de 0,4 mm. Úselo con precaución."
#, c-format, boost-format
msgid "%s filaments are hard and brittle and could break in AMS, and there is also a risk of nozzle clogging when using 0.4mm high-flow nozzles. Use with caution."
msgstr ""
msgstr "Los filamentos %s son duros y quebradizos y podrían romperse en el AMS; además, existe riesgo de obstrucción de la boquilla al usar boquillas de alto flujo de 0,4 mm. Úselo con precaución."
#, c-format, boost-format
msgid "%s has a risk of nozzle clogging when using 0.4, 0.6, 0.8mm high-flow nozzles. Use with caution."
msgstr ""
msgstr "%s tiene riesgo de obstrucción de la boquilla al usar boquillas de alto flujo de 0,4, 0,6 y 0,8 mm. Úselo con precaución."
#, c-format, boost-format
msgid "%s may fail to load or unload due to the Filament Track Switch. If you wish to continue."
msgstr ""
msgstr "%s puede fallar al cargar o descargar debido al Filament Track Switch. Si desea continuar."
#, c-format, boost-format
msgid "%s is not supported by %s extruder."
@@ -102,19 +102,19 @@ msgstr "%s no es compatible con el extrusor %s."
#, c-format, boost-format
msgid "There may be critical print quality issues when printing '%s' with %s Bowden extruder. Use with caution!"
msgstr ""
msgstr "Puede haber problemas críticos de calidad de impresión al imprimir '%s' con el extrusor Bowden %s. ¡Úselo con precaución!"
#, c-format, boost-format
msgid "There may be critical print quality issues when printing '%s' with %s extruder. Use with caution!"
msgstr ""
msgstr "Puede haber problemas críticos de calidad de impresión al imprimir '%s' con el extrusor %s. ¡Úselo con precaución!"
#, c-format, boost-format
msgid "There may be print quality issues when printing '%s' with %s Bowden extruder. Use with caution."
msgstr ""
msgstr "Puede haber problemas de calidad de impresión al imprimir '%s' con el extrusor Bowden %s. Úselo con precaución."
#, c-format, boost-format
msgid "There may be print quality issues when printing '%s' with %s extruder. Use with caution."
msgstr ""
msgstr "Puede haber problemas de calidad de impresión al imprimir '%s' con el extrusor %s. Úselo con precaución."
msgid "High Flow"
msgstr "Flujo alto"
@@ -1971,6 +1971,17 @@ msgstr "Esta es la versión más reciente."
msgid "Info"
msgstr "Información"
msgid "Loading Plugins"
msgstr "Cargando plugins"
#, c-format, boost-format
msgid "Plugin %s is no longer available."
msgstr "El plugin %s ya no está disponible."
#, c-format, boost-format
msgid "Plugin %s access is unauthorized."
msgstr "El acceso al plugin %s no está autorizado."
msgid "Loading printer & filament profiles"
msgstr "Cargando perfiles de impresora y filamento"
@@ -2099,6 +2110,18 @@ msgstr ""
msgid "Resolve cloud sync conflict"
msgstr "Resolver conflictos de sincronización con la nube"
msgid "Syncing your account…"
msgstr "Sincronizando tu cuenta…"
msgid "Migrating presets…"
msgstr "Migrando perfiles…"
msgid "Fetching plugins…"
msgstr "Obteniendo plugins…"
msgid "Loading user presets…"
msgstr "Cargando perfiles de usuario…"
msgid "Retrieving printer information, please try again later."
msgstr "Recuperando información de la impresora, por favor, inténtelo de nuevo más tarde."
@@ -2231,6 +2254,23 @@ msgstr "Orca Slicer - Error al cambiar el idioma"
msgid "*"
msgstr "*"
msgid "Plugins"
msgstr "Plugins"
#, c-format, boost-format
msgid ""
"Failed to open the Plugins dialog:\n"
"%s"
msgstr ""
"No se pudo abrir el cuadro de diálogo de plugins:\n"
"%s"
msgid "Failed to open the Plugins dialog (unknown error)."
msgstr "No se pudo abrir el cuadro de diálogo de plugins (error desconocido)."
msgid "Plugin Terminal"
msgstr "Terminal de plugins"
msgid "Changing application language"
msgstr "Cambiar el idioma de la aplicación"
@@ -3239,7 +3279,7 @@ msgid "Filament type is unknown which is required to perform this action. Please
msgstr "Se desconoce el tipo de filamento necesario para realizar esta acción. Configure la información del filamento de destino."
msgid "AMS has not been initialized. Please initialize it before use."
msgstr ""
msgstr "El AMS no se ha inicializado. Inicialícelo antes de usarlo."
msgid "Changing fan speed during printing may affect print quality, please choose carefully."
msgstr "Cambiar la velocidad del ventilador durante la impresión puede afectar a la calidad de impresión, por lo que se recomienda elegir con cuidado."
@@ -3363,22 +3403,22 @@ msgid "Check filament location"
msgstr "Probar localización de filamento"
msgid "Switch"
msgstr ""
msgstr "Cambiar"
msgid "hotend"
msgstr ""
msgstr "hotend"
msgid "Wait for AMS cooling"
msgstr ""
msgstr "Esperar a que se enfríe el AMS"
msgid "Switch current filament at Filament Track Switch"
msgstr ""
msgstr "Cambiar el filamento actual en el Filament Track Switch"
msgid "Pull back current filament at Filament Track Switch"
msgstr ""
msgstr "Retirar el filamento actual en el Filament Track Switch"
msgid "Switch track at Filament Track Switch"
msgstr ""
msgstr "Cambiar de vía en el Filament Track Switch"
msgid "The maximum temperature cannot exceed "
msgstr "La temperatura máxima no puede superar "
@@ -3432,7 +3472,7 @@ msgid "Launch troubleshoot center"
msgstr "Abrir el centro de resolución de problemas"
msgid "Set nozzle count"
msgstr ""
msgstr "Establecer el número de boquillas"
msgid "Please set nozzle count"
msgstr "Por favor, configure el número de boquillas"
@@ -4021,7 +4061,7 @@ msgid "Printing with the current nozzle may produce an extra %0.2f g of waste."
msgstr "La impresión con la boquilla actual puede producir un extra de %0.2f g de desperdicio."
msgid "External spools is not supported since Filament Track Switch has been installed. If you want to use external spool, please uninstall it."
msgstr ""
msgstr "Los carretes externos no son compatibles porque se ha instalado el Filament Track Switch. Si desea utilizar un carrete externo, desinstálelo."
#, c-format, boost-format
msgid "Note: the filament type(%s) does not match with the filament type(%s) in the slicing file. If you want to use this slot, you can install %s instead of %s and change slot information on the 'Device' page."
@@ -4963,6 +5003,28 @@ msgstr "Formato inválido. Formato de vector esperado: \"%1%\""
msgid "N/A"
msgstr "N/A"
msgid "System agents"
msgstr "Agentes del sistema"
msgid "No plugin selected"
msgstr "Ningún plugin seleccionado"
msgid "Add plugin"
msgstr "Añadir plugin"
msgid "Select plugin"
msgstr "Seleccionar plugin"
msgid "Remove plugin"
msgstr "Eliminar plugin"
msgid "Configure"
msgstr "Configurar"
#, c-format, boost-format
msgid "Configure (%d)"
msgstr "Configurar (%d)"
msgid "Pick"
msgstr "Seleccionar"
@@ -5128,9 +5190,6 @@ msgstr "Test de Flujo"
msgid "Fan speed"
msgstr "Velocidad del ventilador"
msgid "°C"
msgstr "°C"
msgid "Time"
msgstr "Tiempo"
@@ -6662,7 +6721,7 @@ msgid "Safety Options"
msgstr "Opciones de seguridad"
msgid "Hotends"
msgstr ""
msgstr "Hotends"
msgid "Lamp"
msgstr "Luz"
@@ -6698,10 +6757,10 @@ msgid "Current extruder is busy changing filament."
msgstr "El extrusor actual está ocupado cambiando el filamento."
msgid "\"Load\" or \"Unload\" is not supported for external spool while using Filament Track Switch."
msgstr ""
msgstr "\"Cargar\" o \"Descargar\" no es compatible con el carrete externo mientras se usa el Filament Track Switch."
msgid "The Filament Track Switch has not been setup. Please setup on printer."
msgstr ""
msgstr "El Filament Track Switch no se ha configurado. Configúrelo en la impresora."
msgid "Current slot has already been loaded."
msgstr "La ranura actual ya está cargada."
@@ -7133,6 +7192,16 @@ msgctxt "Layers"
msgid "Bottom"
msgstr "Inferior"
msgid "Plugin Selection"
msgstr "Selección de plugins"
msgid ""
"No plugins capabilities available for this type.\n"
"Enable or install some to use."
msgstr ""
"No hay capacidades de plugins disponibles para este tipo.\n"
"Active o instale alguna para usarla."
msgid "Enable detection of build plate position"
msgstr "Activar detección de posición de cama"
@@ -7230,7 +7299,7 @@ msgid "High flow"
msgstr "Alto flujo"
msgid "TPU High flow"
msgstr ""
msgstr "TPU de alto flujo"
msgid "No wiki link available for this printer."
msgstr "No hay enlace a la wiki disponible para esta impresora."
@@ -7358,10 +7427,10 @@ msgid "Configuration incompatible"
msgstr "Configuración incompatible"
msgid "Filament switcher detected. All AMS filaments are now available for both extruders. The slicer will auto-assign for optimal printing. "
msgstr ""
msgstr "Se ha detectado un conmutador de filamento. Todos los filamentos del AMS están ahora disponibles para ambos extrusores. El laminador asignará automáticamente para una impresión óptima. "
msgid "A filament switcher is detected but not calibrated and thus currently unavailable. Please calibrate it on the printer and synchronize before use. "
msgstr ""
msgstr "Se ha detectado un conmutador de filamento, pero no está calibrado, por lo que actualmente no está disponible. Calíbrelo en la impresora y sincronícelo antes de usarlo. "
msgid "Tips"
msgstr "Consejos"
@@ -7395,7 +7464,7 @@ msgid "Project Filaments"
msgstr "Filamentos del proyecto"
msgid "Purge mode"
msgstr ""
msgstr "Modo de purga"
msgid "Flushing volumes"
msgstr "Volúmenes de limpieza"
@@ -8008,6 +8077,40 @@ msgstr "Página del dispositivo"
msgid "Synchronize AMS Filament Information"
msgstr "Sincronizar información de filamentos AMS"
msgid "OrcaCloud plugins required by the current preset are not installed:"
msgstr "Los plugins de OrcaCloud requeridos por el perfil actual no están instalados:"
msgid "Install Plugins"
msgstr "Instalar plugins"
msgid "Local plugins required by the current preset are missing:"
msgstr "Faltan los plugins locales requeridos por el perfil actual:"
msgid "Find on OrcaCloud"
msgstr "Buscar en OrcaCloud"
msgid "Plugins required by the current preset are not activated:"
msgstr "Los plugins requeridos por el perfil actual no están activados:"
msgid "Activate Now"
msgstr "Activar ahora"
msgid "The installed plugin does not provide the required capability — it may be outdated:"
msgstr "El plugin instalado no proporciona la capacidad requerida; puede estar desactualizado:"
msgid "Preparing to install plugins..."
msgstr "Preparando la instalación de plugins..."
msgid "Installing plugins"
msgstr "Instalando plugins"
msgid "Cancelling — finishing the current plugin..."
msgstr "Cancelando; finalizando el plugin actual..."
#, boost-format
msgid "Installing %1%..."
msgstr "Instalando %1%..."
msgid "Plate Settings"
msgstr "Configuración de Cama"
@@ -8837,7 +8940,7 @@ msgid "My Printer"
msgstr "Mi impresora"
msgid "AMS filaments"
msgstr ""
msgstr "Filamentos del AMS"
msgid "Left filaments"
msgstr "Filamentos del lado izquierdo"
@@ -9082,6 +9185,9 @@ msgstr "Multicolor con externo"
msgid "Your filament grouping method in the sliced file is not optimal."
msgstr "Su método de agrupación de filamentos en el archivo laminado no es óptimo."
msgid "To ensure print quality, the drying temperature will be lowered during printing."
msgstr "Para garantizar la calidad de impresión, la temperatura de secado se reducirá durante la impresión."
msgid "Auto Bed Leveling"
msgstr "Nivelado automático de cama"
@@ -9125,35 +9231,35 @@ msgid "Extra info"
msgstr "Información extra"
msgid "The Filament Track Switch installed on the printer does not match the slicing file. Please re-slice to avoid print quality issues."
msgstr ""
msgstr "El Filament Track Switch instalado en la impresora no coincide con el archivo laminado. Vuelva a laminar para evitar problemas de calidad de impresión."
msgid "This print requires a Filament Track Switch. Please install it first."
msgstr ""
msgstr "Esta impresión requiere un Filament Track Switch. Instálelo primero."
msgid "The Filament Track Switch has not been setup. Please setup it first."
msgstr ""
msgstr "El Filament Track Switch no se ha configurado. Configúrelo primero."
#, c-format, boost-format
msgid "Failed to send nozzle auto-mapping request to printer { code: %d }. Please try to refresh the printer information. If it still does not recover, you can try to rebind the printer and check the network connection."
msgstr ""
msgstr "No se pudo enviar la solicitud de mapeo automático de boquillas a la impresora { code: %d }. Intente actualizar la información de la impresora. Si aún así no se recupera, puede intentar volver a vincular la impresora y comprobar la conexión de red."
msgid "The printer is calculating nozzle mapping."
msgstr ""
msgstr "La impresora está calculando el mapeo de boquillas."
msgid "Please wait a moment..."
msgstr ""
msgstr "Espere un momento..."
#, c-format, boost-format
msgid "Failed to receive nozzle auto-mapping table from printer { msg: %s }. Please refresh the printer information."
msgstr ""
msgstr "No se pudo recibir la tabla de mapeo automático de boquillas de la impresora { msg: %s }. Actualice la información de la impresora."
#, c-format, boost-format
msgid "The printer failed to build the nozzle auto-mapping table { code: %d }. Please refresh nozzle information."
msgstr ""
msgstr "La impresora no pudo crear la tabla de mapeo automático de boquillas { code: %d }. Actualice la información de las boquillas."
#, c-format, boost-format
msgid "The current nozzle mapping may produce an extra %0.2f g of waste."
msgstr ""
msgstr "El mapeo de boquillas actual puede producir %0.2f g adicionales de residuos."
#, c-format, boost-format
msgid "Filament %s does not match the filament in AMS slot %s. Please update the printer firmware to support AMS slot assignment."
@@ -9217,32 +9323,32 @@ msgstr "boquilla"
#, c-format, boost-format
msgid "Refreshing information of hotends(%d/%d)."
msgstr ""
msgstr "Actualizando la información de los hotends (%d/%d)."
msgid "There are not enough available hotends currently."
msgstr ""
msgstr "Actualmente no hay suficientes hotends disponibles."
msgid "Please complete the hotend rack setup and try again."
msgstr ""
msgstr "Complete la configuración del rack del hotend e inténtelo de nuevo."
msgid "Please refresh the nozzle information and try again."
msgstr ""
msgstr "Actualice la información de las boquillas e inténtelo de nuevo."
msgid "Please re-slice to avoid filament waste."
msgstr ""
msgstr "Vuelva a laminar para evitar desperdicio de filamento."
msgid "The reported hotend information may be unreliable."
msgstr ""
msgstr "La información notificada de los hotends puede no ser fiable."
#, c-format, boost-format
msgid "The printer has no nozzle matching the slicing file (%s)."
msgstr ""
msgstr "La impresora no tiene ninguna boquilla que coincida con el archivo laminado (%s)."
msgid "Please install a matching nozzle in the hotend rack, or set the corresponding printer preset while slicing."
msgstr ""
msgstr "Instale una boquilla compatible en el rack del hotend, o establezca el perfil de impresora correspondiente al laminar."
msgid "The toolhead and hotend rack are full. Please remove at least one hotend before printing."
msgstr ""
msgstr "El cabezal y el rack del hotend están llenos. Retire al menos un hotend antes de imprimir."
#, c-format, boost-format
msgid "The nozzle flow setting of %s(%s) doesn't match with the slicing file(%s). Please make sure the nozzle installed matches with settings in printer, then set the corresponding printer preset while slicing."
@@ -9268,7 +9374,7 @@ msgstr "La dureza del material actual (%s) supera la dureza de %s(%s). Verifique
#, c-format, boost-format
msgid "The hardness of current material (%s) exceeds the hardness of %s(%s). It may cause nozzle wear, leading to material leakage and unstable flow. Please exercise caution when using it."
msgstr ""
msgstr "La dureza del material actual (%s) supera la dureza de %s(%s). Puede provocar el desgaste de la boquilla, dando lugar a fugas de material y flujo inestable. Tenga precaución al utilizarlo."
#, c-format, boost-format
msgid "[ %s ] requires printing in a high-temperature environment. Please close the door."
@@ -9797,6 +9903,12 @@ msgstr "G-Code de cambio de rol de extrusión"
msgid "Post-processing Scripts"
msgstr "Script de Post-procesado"
msgid "Slicing Pipeline Plugin"
msgstr "Plugin de la canalización de laminado"
msgid "Plugin Configuration"
msgstr "Configuración del plugin"
msgid "Notes"
msgstr "Anotaciones"
@@ -10928,6 +11040,9 @@ msgstr "Activar/desactivar la impresión para el objeto/pieza"
msgid "Switch between Prepare/Preview"
msgstr "Cambiar entre Preparar/Previsualizar"
msgid "Open actions speed dial"
msgstr "Abrir el menú rápido de acciones"
msgid "Plater"
msgstr "Cama"
@@ -11125,7 +11240,7 @@ msgid "Auto Fire Extinguishing System"
msgstr "Sistema de extinción automática de incendios"
msgid "Filament Track Switch"
msgstr ""
msgstr "Filament Track Switch"
msgid "Beta"
msgstr "Beta"
@@ -11252,7 +11367,7 @@ msgid " can not be placed in the "
msgstr " no se puede colocar en el "
msgid "Group error in manual mode. Please check nozzle count or regroup."
msgstr ""
msgstr "Error de agrupación en modo manual. Compruebe el número de boquillas o vuelva a agrupar."
msgid "Internal Bridge"
msgstr "Puente Interior"
@@ -11757,6 +11872,9 @@ msgstr "Clave API"
msgid "HTTP digest"
msgstr "Resumen HTTP"
msgid "Configuration for the plugin capabilities this preset uses, overriding the global Capabilities configuration. Stored as a raw JSON array and edited through the dialog behind the button, never typed in directly."
msgstr "Configuración de las capacidades de plugins que utiliza este perfil, que anula la configuración global de Capacidades. Se almacena como un array JSON sin procesar y se edita a través del cuadro de diálogo que hay detrás del botón, nunca se escribe directamente."
msgid "Avoid crossing walls"
msgstr "Evitar cruzar perímetro"
@@ -12788,6 +12906,30 @@ msgstr ""
"Densidad de la capa superficial inferior. Destinada a fines estéticos o funcionales, no para corregir problemas como la sobreextrusión.\n"
"ADVERTENCIA: Reducir este valor puede afectar negativamente la adherencia a la cama."
msgid "Top surface fill order"
msgstr "Orden de relleno de la superficie superior"
msgid ""
"Direction in which top surfaces are filled when using a center-based pattern (Concentric, Archimedean Chords, Octagram Spiral).\n"
"Outward starts at the center of the surface, so any excess material is pushed towards the edge where it is least visible. Inward starts at the edge and ends with the tight curves at the center.\n"
"Default uses shortest-path ordering, which may run in either direction."
msgstr ""
"Dirección en la que se rellenan las superficies superiores al usar un patrón basado en el centro (Concéntrico, Cuerdas de Arquímedes, Espiral de octograma).\n"
"Hacia afuera comienza en el centro de la superficie, de modo que cualquier exceso de material se empuja hacia el borde, donde es menos visible. Hacia adentro comienza en el borde y termina con las curvas cerradas del centro.\n"
"Por defecto usa el orden de ruta más corta, que puede ir en cualquier dirección."
msgid "Bottom surface fill order"
msgstr "Orden de relleno de la superficie inferior"
msgid ""
"Direction in which bottom surfaces are filled when using a center-based pattern (Concentric, Archimedean Chords, Octagram Spiral).\n"
"Inward starts each surface with the wider outer curves, which improves first layer adhesion on build plates where the tight curves at the center may not stick. Outward starts at the center, pushing any excess material towards the edge.\n"
"Default uses shortest-path ordering, which may run in either direction."
msgstr ""
"Dirección en la que se rellenan las superficies inferiores al usar un patrón basado en el centro (Concéntrico, Cuerdas de Arquímedes, Espiral de octograma).\n"
"Hacia adentro comienza cada superficie con las curvas exteriores más amplias, lo que mejora la adherencia de la primera capa en las camas donde las curvas cerradas del centro pueden no adherirse. Hacia afuera comienza en el centro, empujando cualquier exceso de material hacia el borde.\n"
"Por defecto usa el orden de ruta más corta, que puede ir en cualquier dirección."
msgid "Internal solid infill pattern"
msgstr "Patrón de relleno sólido interno"
@@ -13115,7 +13257,7 @@ msgid "Temperature when flushing filament. 0 indicates the upper bound of the re
msgstr "Temperatura al limpiar el filamento. 0 indica el límite superior del rango de temperatura recomendado para la boquilla."
msgid "Flush temperature used in fast purge mode."
msgstr ""
msgstr "Temperatura de purga utilizada en el modo de purga rápida."
msgid "Flush volumetric speed"
msgstr "Velocidad volumétrica de descarga"
@@ -13380,10 +13522,10 @@ msgid "The filament is printable in extruder."
msgstr "El filamento es imprimible en el extrusor."
msgid "Filament-extruder compatibility"
msgstr ""
msgstr "Compatibilidad filamento-extrusor"
msgid "A single 32-bit int encoding the compatibility level of a filament across all extruders (up to 10). Every 3 bits represent one extruder (bits [3*i, 3*i+2] for extruder i). 0: printable, 1: error, 2: critical warning, 3: warning, 4-7: reserved."
msgstr ""
msgstr "Un único entero de 32 bits que codifica el nivel de compatibilidad de un filamento en todos los extrusores (hasta 10). Cada 3 bits representan un extrusor (bits [3*i, 3*i+2] para el extrusor i). 0: imprimible, 1: error, 2: advertencia crítica, 3: advertencia, 4-7: reservado."
msgid "Softening temperature"
msgstr "Temperatura de ablandado"
@@ -13982,13 +14124,13 @@ msgid "Enable this option if machine has auxiliary part cooling fan. G-code comm
msgstr "Activar esta opción si la máquina dispone de ventilador auxiliar de refrigeración de piezas. Comando G-Code: M106 P2 S(0-255)."
msgid "Fan direction"
msgstr ""
msgstr "Dirección del ventilador"
msgid "Cooling fan direction of the printer"
msgstr ""
msgstr "Dirección del ventilador de refrigeración de la impresora"
msgid "Both"
msgstr ""
msgstr "Ambos"
msgid ""
"Start the fan this number of seconds earlier than its target start time (you can use fractional seconds). It assumes infinite acceleration for this time estimation, and will only take into account G1 and G0 moves (arc fitting is unsupported).\n"
@@ -14031,9 +14173,6 @@ msgstr ""
"Si tu firmware ya desactiva el ventilador por debajo de un umbral (por ejemplo, [fan] off_below: 0.10 de Klipper apaga el ventilador siempre que el ciclo de trabajo ordenado sea inferior al 10 %), lo ideal es que esta opción y el umbral del firmware se establezcan en el mismo valor. Hacer que coincidan (por ejemplo, off_below: 0,10 en Klipper y 10 % aquí) garantiza que el cortador nunca emita un valor distinto de cero que el firmware descartaría silenciosamente, y que el ventilador nunca reciba un valor inferior al que sabes que realmente puede alcanzar.\n"
"Establece en 0 para desactivar."
msgid "%"
msgstr "%"
msgid "Time cost"
msgstr "Coste monetario por hora"
@@ -14595,7 +14734,7 @@ msgid "The allowed maximum output force of Y axis"
msgstr "La fuerza máxima permitida del eje Y"
msgid "N"
msgstr ""
msgstr "N"
msgid "Bed mass of the Y axis"
msgstr "Masa de la cama del eje Y"
@@ -14604,7 +14743,7 @@ msgid "The machine bed mass load of Y axis"
msgstr "La carga de la masa de la cama de la máquina del eje Y"
msgid "g"
msgstr ""
msgstr "g"
msgid "The allowed max printed mass"
msgstr "Masa máxima de impresión permitida"
@@ -14721,6 +14860,9 @@ msgstr ""
"Para desactivar el input shaper, utilice el tipo «Desactivar».\n"
"RRF: los valores de X e Y son iguales."
msgid "Hz"
msgstr "Hz"
msgid "Y"
msgstr "Y"
@@ -15002,6 +15144,15 @@ msgstr "G-Code de cambio de rol de extrusión (proceso)"
msgid "This G-code is inserted when the extrusion role is changed. It runs after the machine and filament extrusion role G-code."
msgstr "Este G-code se inserta cuando se cambia la función de extrusión. Se ejecuta después del G-code de la máquina y de la función de extrusión del filamento."
msgid "Plugins Used"
msgstr "Plugins utilizados"
msgid "Plugin capabilities referenced by this preset, stored as name;uuid;capability."
msgstr "Capacidades de plugins referenciadas por este perfil, almacenadas como name;uuid;capability."
msgid "Python plugin(s) invoked at each slicing pipeline step to read and modify intermediate slicing data, including a final G-code post-processing step. Research/experimental."
msgstr "Plugin(s) de Python que se invocan en cada paso de la canalización de laminado para leer y modificar los datos intermedios de laminado, incluido un paso final de posprocesamiento de G-code. Investigación/experimental."
msgid "Printer type"
msgstr "Tipo de impresora"
@@ -15062,6 +15213,17 @@ msgstr "Longitud de retracción antes de purgado"
msgid "This is the length of fast retraction before a wipe, relative to retraction length."
msgstr "La longitud de la retracción rápida antes de la purga, en relación con la longitud de la retracción."
msgid "Retract amount after wipe"
msgstr "Cantidad de retracción después de la limpieza"
#, c-format
msgid ""
"The length of fast retraction after wipe, relative to retraction length.\n"
"The value will be clamped by 100% minus the retract amount before the wipe value."
msgstr ""
"La longitud de la retracción rápida después de la limpieza, relativa a la longitud de retracción.\n"
"El valor se limitará al 100 % menos el valor de la cantidad de retracción antes de la limpieza."
msgid "Retract on layer change"
msgstr "Retracción al cambiar de capa"
@@ -15201,10 +15363,10 @@ msgid "Speed for reloading filament into the nozzle. Zero means same speed of re
msgstr "Velocidad para recargar el filamento en la boquilla. Cero significa la misma velocidad que la retracción."
msgid "Deretraction speed (extruder change)"
msgstr ""
msgstr "Velocidad de De-retracción (cambio de extrusor)"
msgid "Speed for reloading filament into the nozzle when switching extruder."
msgstr ""
msgstr "Velocidad de recarga del filamento en la boquilla al cambiar de extrusor."
msgid "Use firmware retraction"
msgstr "Usar retracción de firmware (beta)"
@@ -15510,10 +15672,10 @@ msgid "Traditional"
msgstr "Tradicional"
msgid "Farthest point timelapse"
msgstr ""
msgstr "Timelapse del punto más lejano"
msgid "When enabled, the timelapse snapshot is taken at the farthest point from camera instead of traveling to the wipe tower or excess chute. Only effective in traditional timelapse mode on non-I3 printers."
msgstr ""
msgstr "Cuando está activado, la instantánea del timelapse se toma en el punto más lejano de la cámara en lugar de desplazarse a la torre de purga o a la rampa de exceso. Solo es efectivo en el modo timelapse tradicional en impresoras que no son I3."
msgid "Temperature variation"
msgstr "Variación de temperatura"
@@ -16051,20 +16213,6 @@ msgstr "Espesor mínimo de la cubierta superior"
msgid "The number of top solid layers is increased when slicing if the thickness calculated by top shell layers is thinner than this value. This can avoid having too thin a shell when layer height is small. 0 means that this setting is disabled and thickness of top shell is determined simply by the number of top shell layers."
msgstr "El número de capas sólidas superiores se incrementa al laminar si el espesor calculado por las capas de la cubierta es más delgado que este valor. Esto puede evitar tener una cubierta demasiado fina cuando la altura de la capa es pequeña. 0 significa que este ajuste está desactivado y el grosor de la capa superior está absolutamente determinado por las capas de la cubierta superior."
msgid "Anisotropic surfaces"
msgstr "Superficies anisótropas"
msgid ""
"Anisotropic patterns on the top and bottom surfaces.\n"
"Co-directional printing mode will be applied. For certain patterns, omni-directional filling provides color dispersion when using multi-colored or silk plastics.\n"
"This option disable the gap fill.\n"
"This option can increase a printing time."
msgstr ""
"Patrones anisótropos en las superficies superior e inferior.\n"
"Se aplicará el modo de impresión codireccional. Para ciertos patrones, el relleno omnidireccional proporciona dispersión del color al usar plásticos multicolor o de tipo seda.\n"
"Esta opción desactiva el relleno de huecos.\n"
"Esta opción puede aumentar el tiempo de impresión."
msgid "Separated infills"
msgstr "Rellenos separados"
@@ -16146,10 +16294,10 @@ msgid "The actual flushing volumes is equal to the flush multiplier value multip
msgstr "El volumen de flujo real es igual al producto del multiplicador de flujo y los volúmenes de flujo de la tabla."
msgid "Flush multiplier (Fast mode)"
msgstr ""
msgstr "Multiplicador de purga (modo rápido)"
msgid "The flush multiplier used in fast purge mode."
msgstr ""
msgstr "El multiplicador de purga utilizado en el modo de purga rápida."
msgid "Prime volume"
msgstr "Volumen de purga"
@@ -16158,16 +16306,16 @@ msgid "This is the volume of material to prime the extruder with on the tower."
msgstr "El volumen de material para purgar la extrusora en la torre."
msgid "Prime volume mode"
msgstr ""
msgstr "Modo de volumen de cebado"
msgid "Selects how the wipe-tower prime and flush volumes are computed on multi-extruder printers."
msgstr ""
msgstr "Selecciona cómo se calculan los volúmenes de cebado y purga de la torre de purga en impresoras multiextrusor."
msgid "Saving"
msgstr ""
msgstr "Guardando"
msgid "Fast"
msgstr ""
msgstr "Rápido"
msgid "This is the width of prime towers."
msgstr "Ancho de la torre de purga."
@@ -16493,10 +16641,10 @@ msgid "When this retraction value is modified, it will be used as the amount of
msgstr "Cuando se modifique este valor de retracción, se utilizará como la cantidad de filamento retraído dentro del hotend antes de cambiar los hotends."
msgid "Support fast purge mode"
msgstr ""
msgstr "Compatible con el modo de purga rápida"
msgid "Whether this printer supports fast purge mode with optimized temperature and multiplier."
msgstr ""
msgstr "Indica si esta impresora es compatible con el modo de purga rápida con temperatura y multiplicador optimizados."
msgid "The volume of material required to prime the extruder for a hotend change on the tower."
msgstr "El volumen de material necesario para cebar el extrusor al cambiar el Hotend en la torre."
@@ -17874,9 +18022,6 @@ msgstr "Inicio / Fin"
msgid "Frequency settings"
msgstr "Ajustes de frecuencia"
msgid "Hz"
msgstr "Hz"
msgid "RepRap firmware uses the same frequency range for both axes."
msgstr "El firmware RepRap utiliza el mismo rango de frecuencia para ambos ejes."
@@ -19367,10 +19512,10 @@ msgid "Removed"
msgstr "Eliminado"
msgid "Enable smart filament assign: Assign one filament to multiple nozzles to maximize savings"
msgstr ""
msgstr "Activar la asignación inteligente de filamento: asigna un filamento a varias boquillas para maximizar el ahorro"
msgid "Fila Saving"
msgstr ""
msgstr "Ahorro de filamento"
msgid "Don't remind me again"
msgstr "No me recuerdes de nuevo"
@@ -19407,7 +19552,7 @@ msgstr "(Sincronizar con impresora)"
#, c-format, boost-format
msgid "Error: %s extruder has no available %s nozzle, current group result is invalid."
msgstr ""
msgstr "Error: el extrusor %s no tiene ninguna boquilla %s disponible; el resultado del grupo actual no es válido."
msgid "We will slice according to this grouping method:"
msgstr "Laminar según este método de agrupación:"
@@ -19416,13 +19561,13 @@ msgid "Tip: You can drag the filaments to reassign them to different nozzles."
msgstr "Tip: Puedes arrastrar los filamentos para reasignarlos a diferentes boquillas."
msgid "Please adjust your grouping or click "
msgstr ""
msgstr "Ajuste su agrupación o haga clic en "
msgid " to set nozzle count"
msgstr ""
msgstr " para establecer el número de boquillas"
msgid "Set the physical nozzle count..."
msgstr ""
msgstr "Establecer el número físico de boquillas..."
msgid "The filament grouping method for current plate is determined by the dropdown option at the slicing plate button."
msgstr "El método de agrupación de filamentos para la placa actual se determina por la opción desplegable en el botón de placa de laminado."
@@ -19854,6 +19999,145 @@ msgstr "Vista previa del archivo"
msgid "Open File"
msgstr "Abrir archivo"
msgid "AMS Dryness Control"
msgstr "Control de secado del AMS"
msgid "Filament Drying Settings"
msgstr "Ajustes de secado del filamento"
msgid "Stopping"
msgstr "Deteniendo"
msgid "Unable to dry temporarily due to ..."
msgstr "No se puede secar temporalmente debido a ..."
msgid "Drying Error"
msgstr "Error de secado"
msgid "Please check the Assistant for troubleshooting"
msgstr "Consulte el Asistente para solucionar problemas"
msgid "Please remove and store the filament (as shown)."
msgstr "Retire y almacene el filamento (como se muestra)."
msgid "The AMS can rotate the filament which is properly stored, providing better drying results."
msgstr "El AMS puede rotar el filamento que está correctamente almacenado, proporcionando mejores resultados de secado."
msgid "Rotate spool when drying"
msgstr "Rotar el carrete durante el secado"
msgctxt "amsdrying"
msgid "Back"
msgstr "Atrás"
msgid "Drying-Heating"
msgstr "Secado - Calentamiento"
msgid "Drying-Dehumidifying"
msgstr "Secado - Deshumidificación"
msgid " maximum drying temperature is "
msgstr " la temperatura máxima de secado es "
msgid " minimum drying temperature is "
msgstr " la temperatura mínima de secado es "
msgid "This filament may not be completely dried."
msgstr "Es posible que este filamento no esté completamente seco."
msgid "This AMS is currently printing. To ensure print quality, the drying temperature cannot exceed the recommended drying temperature."
msgstr "Este AMS está imprimiendo actualmente. Para garantizar la calidad de impresión, la temperatura de secado no puede superar la temperatura de secado recomendada."
msgid "The temperature shall not exceed the filament's heat distortion temperature"
msgstr "La temperatura no debe superar la temperatura de distorsión térmica del filamento"
msgid "Minimum time value cannot be less than 1."
msgstr "El valor de tiempo mínimo no puede ser inferior a 1."
msgid "Maximum time value cannot be greater than 24."
msgstr "El valor de tiempo máximo no puede ser superior a 24."
msgid "Insufficient power"
msgstr "Potencia insuficiente"
msgid " Too many AMS drying simultaneously. Please plug in the power or stop other drying processes before starting."
msgstr " Demasiados AMS secando simultáneamente. Conecte la alimentación o detenga otros procesos de secado antes de empezar."
msgid "AMS is busy"
msgstr "El AMS está ocupado"
msgid " AMS is calibrating | reading RFID | loading/unloading material, please wait."
msgstr " El AMS está calibrando | leyendo RFID | cargando/descargando material, espere."
msgid "Filament in AMS outlet"
msgstr "Filamento en la salida del AMS"
msgid " The high drying temperature may cause AMS blockage, please unload first."
msgstr " La alta temperatura de secado puede provocar un bloqueo del AMS; descargue primero."
msgid "Initiating AMS drying"
msgstr "Iniciando el secado del AMS"
msgid "Not supported in 2D mode"
msgstr "No compatible en modo 2D"
msgid "Task in progress"
msgstr "Tarea en curso"
msgid " The AMS might be in use during Task."
msgstr " El AMS podría estar en uso durante la tarea."
msgid " Firmware update in progress, please wait..."
msgstr " Actualización de firmware en curso, espere..."
msgid " Please plug in the power and then use the drying function."
msgstr " Conecte la alimentación y luego utilice la función de secado."
msgid " The high drying temperature may cause AMS blockage. Please unload the filament manually before proceeding."
msgstr " La alta temperatura de secado puede provocar un bloqueo del AMS. Descargue el filamento manualmente antes de continuar."
msgid "System is busy"
msgstr "El sistema está ocupado"
msgid " Initiating other drying processes, please wait a few seconds..."
msgstr " Iniciando otros procesos de secado, espere unos segundos..."
msgid "For better drying results, remove the filament and allow it to rotate."
msgstr "Para obtener mejores resultados de secado, retire el filamento y permita que rote."
msgid "The AMS will automatically rotate the stored filament slots to enhance the drying performance."
msgstr "El AMS rotará automáticamente las ranuras de filamento almacenadas para mejorar el rendimiento del secado."
msgid "Alternatively, you can dry the filament without removing it."
msgstr "Como alternativa, puede secar el filamento sin retirarlo."
msgid "Unknown filaments will be treated as PLA."
msgstr "Los filamentos desconocidos se tratarán como PLA."
msgid "Please store the filament marked with an exclamation mark."
msgstr "Almacene el filamento marcado con un signo de exclamación."
msgid "Filament left in the feeder during drying may soften because the drying temperature exceeds the softening point of materials like PLA and TPU."
msgstr "El filamento que quede en el alimentador durante el secado puede ablandarse porque la temperatura de secado supera el punto de reblandecimiento de materiales como el PLA y el TPU."
msgid "Starting: Checking adapter connection"
msgstr "Iniciando: comprobando la conexión del adaptador"
msgid "Starting: Checking filament status"
msgstr "Iniciando: comprobando el estado del filamento"
msgid "Starting: Checking drying presets"
msgstr "Iniciando: comprobando los perfiles de secado"
msgid "Starting: Checking filament location"
msgstr "Iniciando: comprobando la ubicación del filamento"
msgid "Starting: Checking air intake"
msgstr "Iniciando: comprobando la entrada de aire"
msgid "Starting: Checking air vent"
msgstr "Iniciando: comprobando la salida de aire"
msgid "The filament may not be compatible with the current machine settings. Generic filament presets will be used."
msgstr "Es posible que el filamento no sea compatible con la configuración de la máquina. Se utilizará una configuración de filamento genérico."
@@ -20169,6 +20453,26 @@ msgstr ""
"Evita la deformación\n"
"¿Sabías que al imprimir materiales propensos a la deformación como el ABS, aumentar adecuadamente la temperatura de la cama térmica puede reducir la probabilidad de deformaciones?"
#~ msgid "°C"
#~ msgstr "°C"
#~ msgid "%"
#~ msgstr "%"
#~ msgid "Anisotropic surfaces"
#~ msgstr "Superficies anisótropas"
#~ msgid ""
#~ "Anisotropic patterns on the top and bottom surfaces.\n"
#~ "Co-directional printing mode will be applied. For certain patterns, omni-directional filling provides color dispersion when using multi-colored or silk plastics.\n"
#~ "This option disable the gap fill.\n"
#~ "This option can increase a printing time."
#~ msgstr ""
#~ "Patrones anisótropos en las superficies superior e inferior.\n"
#~ "Se aplicará el modo de impresión codireccional. Para ciertos patrones, el relleno omnidireccional proporciona dispersión del color al usar plásticos multicolor o de tipo seda.\n"
#~ "Esta opción desactiva el relleno de huecos.\n"
#~ "Esta opción puede aumentar el tiempo de impresión."
#~ msgid "Renders cast shadows on the plate in realistic view."
#~ msgstr "Los objetos renderizados proyectan sombras sobre la cama en la vista realista."

File diff suppressed because it is too large Load Diff

View File

@@ -6,7 +6,7 @@ msgid ""
msgstr ""
"Project-Id-Version: Orca Slicer\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-07-13 16:24-0300\n"
"POT-Creation-Date: 2026-07-17 15:13-0300\n"
"PO-Revision-Date: \n"
"Last-Translator: \n"
"Language-Team: Guislain Cyril, Thomas Lété\n"
@@ -1970,6 +1970,17 @@ msgstr "Il s'agit de la version la plus récente."
msgid "Info"
msgstr "Info"
msgid "Loading Plugins"
msgstr ""
#, c-format, boost-format
msgid "Plugin %s is no longer available."
msgstr ""
#, c-format, boost-format
msgid "Plugin %s access is unauthorized."
msgstr ""
msgid "Loading printer & filament profiles"
msgstr "Chargement des profils dimprimante et de filament"
@@ -2098,6 +2109,18 @@ msgstr ""
msgid "Resolve cloud sync conflict"
msgstr "Résoudre le conflit de synchronisation cloud"
msgid "Syncing your account…"
msgstr ""
msgid "Migrating presets…"
msgstr ""
msgid "Fetching plugins…"
msgstr ""
msgid "Loading user presets…"
msgstr ""
msgid "Retrieving printer information, please try again later."
msgstr "Récupération des informations de l'imprimante, veuillez réessayer plus tard."
@@ -2230,6 +2253,21 @@ msgstr "Orca Slicer — Échec du changement de langue"
msgid "*"
msgstr "*"
msgid "Plugins"
msgstr ""
#, c-format, boost-format
msgid ""
"Failed to open the Plugins dialog:\n"
"%s"
msgstr ""
msgid "Failed to open the Plugins dialog (unknown error)."
msgstr ""
msgid "Plugin Terminal"
msgstr ""
msgid "Changing application language"
msgstr "Changer la langue de l'application"
@@ -4960,6 +4998,28 @@ msgstr "Format invalide. Format vectoriel attendu : \"%1%\""
msgid "N/A"
msgstr "N/A"
msgid "System agents"
msgstr ""
msgid "No plugin selected"
msgstr ""
msgid "Add plugin"
msgstr ""
msgid "Select plugin"
msgstr ""
msgid "Remove plugin"
msgstr ""
msgid "Configure"
msgstr ""
#, c-format, boost-format
msgid "Configure (%d)"
msgstr ""
msgid "Pick"
msgstr "Sélectionner"
@@ -5125,9 +5185,6 @@ msgstr "Débit"
msgid "Fan speed"
msgstr "Vitesse du ventilateur"
msgid "°C"
msgstr "°C"
msgid "Time"
msgstr "Durée"
@@ -7130,6 +7187,14 @@ msgctxt "Layers"
msgid "Bottom"
msgstr "Du bas"
msgid "Plugin Selection"
msgstr ""
msgid ""
"No plugins capabilities available for this type.\n"
"Enable or install some to use."
msgstr ""
msgid "Enable detection of build plate position"
msgstr "Activation de la détection de la position du plateau"
@@ -8005,6 +8070,40 @@ msgstr "Page appareil"
msgid "Synchronize AMS Filament Information"
msgstr "Synchroniser les informations de filament AMS"
msgid "OrcaCloud plugins required by the current preset are not installed:"
msgstr ""
msgid "Install Plugins"
msgstr ""
msgid "Local plugins required by the current preset are missing:"
msgstr ""
msgid "Find on OrcaCloud"
msgstr ""
msgid "Plugins required by the current preset are not activated:"
msgstr ""
msgid "Activate Now"
msgstr ""
msgid "The installed plugin does not provide the required capability — it may be outdated:"
msgstr ""
msgid "Preparing to install plugins..."
msgstr ""
msgid "Installing plugins"
msgstr ""
msgid "Cancelling — finishing the current plugin..."
msgstr ""
#, boost-format
msgid "Installing %1%..."
msgstr ""
msgid "Plate Settings"
msgstr "Paramètres de la plaque"
@@ -9074,6 +9173,9 @@ msgstr "Multicolore avec bobine externe"
msgid "Your filament grouping method in the sliced file is not optimal."
msgstr "Votre méthode de regroupement des filaments dans le fichier tranché n'est pas optimale."
msgid "To ensure print quality, the drying temperature will be lowered during printing."
msgstr ""
msgid "Auto Bed Leveling"
msgstr "Nivellement automatique du plateau"
@@ -9791,6 +9893,12 @@ msgstr "G-code de changement du rôle de lextrusion"
msgid "Post-processing Scripts"
msgstr "Scripts de post-traitement"
msgid "Slicing Pipeline Plugin"
msgstr ""
msgid "Plugin Configuration"
msgstr ""
msgid "Notes"
msgstr "Notes"
@@ -10925,6 +11033,9 @@ msgstr "Basculer létat imprimable de lobjet/de la pièce"
msgid "Switch between Prepare/Preview"
msgstr "Basculer entre Préparer/Aperçu"
msgid "Open actions speed dial"
msgstr ""
msgid "Plater"
msgstr "Plateau"
@@ -11760,6 +11871,9 @@ msgstr "Clé API"
msgid "HTTP digest"
msgstr "Résumé HTTP"
msgid "Configuration for the plugin capabilities this preset uses, overriding the global Capabilities configuration. Stored as a raw JSON array and edited through the dialog behind the button, never typed in directly."
msgstr ""
msgid "Avoid crossing walls"
msgstr "Évitez de traverser les parois"
@@ -12763,6 +12877,24 @@ msgstr ""
"Densité de la couche de surface inférieure. Destiné à des fins esthétiques ou fonctionnelles, pas pour corriger des problèmes comme la surextrusion.\n"
"ATTENTION : Réduire cette valeur peut affecter négativement l'adhérence au plateau."
msgid "Top surface fill order"
msgstr ""
msgid ""
"Direction in which top surfaces are filled when using a center-based pattern (Concentric, Archimedean Chords, Octagram Spiral).\n"
"Outward starts at the center of the surface, so any excess material is pushed towards the edge where it is least visible. Inward starts at the edge and ends with the tight curves at the center.\n"
"Default uses shortest-path ordering, which may run in either direction."
msgstr ""
msgid "Bottom surface fill order"
msgstr ""
msgid ""
"Direction in which bottom surfaces are filled when using a center-based pattern (Concentric, Archimedean Chords, Octagram Spiral).\n"
"Inward starts each surface with the wider outer curves, which improves first layer adhesion on build plates where the tight curves at the center may not stick. Outward starts at the center, pushing any excess material towards the edge.\n"
"Default uses shortest-path ordering, which may run in either direction."
msgstr ""
msgid "Internal solid infill pattern"
msgstr "Motif de remplissage plein interne"
@@ -14005,9 +14137,6 @@ msgstr ""
"Si votre firmware désactive déjà le ventilateur en dessous dun seuil (par exemple, le [fan] off_below: 0.10 de Klipper éteint le ventilateur dès que le rapport cyclique commandé est inférieur à 10 %), cette option et le seuil du firmware devraient idéalement être réglés sur la même valeur. Les faire correspondre (par exemple off_below: 0.10 dans Klipper et 10 % ici) garantit que le slicer német jamais une valeur non nulle que le firmware abandonnerait silencieusement, et que le ventilateur ne reçoit jamais une valeur inférieure à celle à laquelle vous savez quil peut réellement démarrer.\n"
"Réglez sur 0 pour désactiver."
msgid "%"
msgstr "%"
msgid "Time cost"
msgstr "Coût horaire"
@@ -14697,6 +14826,9 @@ msgstr ""
"Pour désactiver la mise en forme du signal, utilisez le type « Disable ».\n"
"RRF : les valeurs X et Y sont identiques."
msgid "Hz"
msgstr "Hz"
msgid "Y"
msgstr "Y"
@@ -14978,6 +15110,15 @@ msgstr "G-code de changement du rôle de lextrusion (traitement)"
msgid "This G-code is inserted when the extrusion role is changed. It runs after the machine and filament extrusion role G-code."
msgstr "Ce G-code est inséré lorsque le rôle de lextrusion change. Il sexécute après le G-code de changement de rôle dextrusion de la machine et du filament."
msgid "Plugins Used"
msgstr ""
msgid "Plugin capabilities referenced by this preset, stored as name;uuid;capability."
msgstr ""
msgid "Python plugin(s) invoked at each slicing pipeline step to read and modify intermediate slicing data, including a final G-code post-processing step. Research/experimental."
msgstr ""
msgid "Printer type"
msgstr "Type dimprimante"
@@ -15038,6 +15179,15 @@ msgstr "Quantité de rétraction avant essuyage"
msgid "This is the length of fast retraction before a wipe, relative to retraction length."
msgstr "La longueur de la rétraction rapide avant lessuyage, par rapport à la longueur de la rétraction"
msgid "Retract amount after wipe"
msgstr ""
#, c-format
msgid ""
"The length of fast retraction after wipe, relative to retraction length.\n"
"The value will be clamped by 100% minus the retract amount before the wipe value."
msgstr ""
msgid "Retract on layer change"
msgstr "Rétracter lors de changement de couche"
@@ -16022,16 +16172,6 @@ msgstr "Épaisseur de la coque supérieure"
msgid "The number of top solid layers is increased when slicing if the thickness calculated by top shell layers is thinner than this value. This can avoid having too thin a shell when layer height is small. 0 means that this setting is disabled and thickness of top shell is determined simply by the number of top shell layers."
msgstr "Le nombre de couches solides supérieures est augmenté lors du découpage si l'épaisseur calculée par les couches de coque supérieures est inférieure à cette valeur. Cela peut éviter d'avoir une coque trop fine lorsque la hauteur de couche est faible. 0 signifie que ce paramètre est désactivé et que l'épaisseur de la coque supérieure est simplement déterminée par le nombre de couches de coque supérieures."
msgid "Anisotropic surfaces"
msgstr ""
msgid ""
"Anisotropic patterns on the top and bottom surfaces.\n"
"Co-directional printing mode will be applied. For certain patterns, omni-directional filling provides color dispersion when using multi-colored or silk plastics.\n"
"This option disable the gap fill.\n"
"This option can increase a printing time."
msgstr ""
msgid "Separated infills"
msgstr ""
@@ -17832,9 +17972,6 @@ msgstr "Début / Fin"
msgid "Frequency settings"
msgstr "Paramètres de fréquence"
msgid "Hz"
msgstr "Hz"
msgid "RepRap firmware uses the same frequency range for both axes."
msgstr "Le firmware RepRap utilise la même plage de fréquence pour les deux axes."
@@ -19814,6 +19951,145 @@ msgstr "Aperçu de larchive"
msgid "Open File"
msgstr "Ouvrir un fichier"
msgid "AMS Dryness Control"
msgstr ""
msgid "Filament Drying Settings"
msgstr ""
msgid "Stopping"
msgstr ""
msgid "Unable to dry temporarily due to ..."
msgstr ""
msgid "Drying Error"
msgstr ""
msgid "Please check the Assistant for troubleshooting"
msgstr ""
msgid "Please remove and store the filament (as shown)."
msgstr ""
msgid "The AMS can rotate the filament which is properly stored, providing better drying results."
msgstr ""
msgid "Rotate spool when drying"
msgstr ""
msgctxt "amsdrying"
msgid "Back"
msgstr ""
msgid "Drying-Heating"
msgstr ""
msgid "Drying-Dehumidifying"
msgstr ""
msgid " maximum drying temperature is "
msgstr ""
msgid " minimum drying temperature is "
msgstr ""
msgid "This filament may not be completely dried."
msgstr ""
msgid "This AMS is currently printing. To ensure print quality, the drying temperature cannot exceed the recommended drying temperature."
msgstr ""
msgid "The temperature shall not exceed the filament's heat distortion temperature"
msgstr ""
msgid "Minimum time value cannot be less than 1."
msgstr ""
msgid "Maximum time value cannot be greater than 24."
msgstr ""
msgid "Insufficient power"
msgstr ""
msgid " Too many AMS drying simultaneously. Please plug in the power or stop other drying processes before starting."
msgstr ""
msgid "AMS is busy"
msgstr ""
msgid " AMS is calibrating | reading RFID | loading/unloading material, please wait."
msgstr ""
msgid "Filament in AMS outlet"
msgstr ""
msgid " The high drying temperature may cause AMS blockage, please unload first."
msgstr ""
msgid "Initiating AMS drying"
msgstr ""
msgid "Not supported in 2D mode"
msgstr ""
msgid "Task in progress"
msgstr ""
msgid " The AMS might be in use during Task."
msgstr ""
msgid " Firmware update in progress, please wait..."
msgstr ""
msgid " Please plug in the power and then use the drying function."
msgstr ""
msgid " The high drying temperature may cause AMS blockage. Please unload the filament manually before proceeding."
msgstr ""
msgid "System is busy"
msgstr ""
msgid " Initiating other drying processes, please wait a few seconds..."
msgstr ""
msgid "For better drying results, remove the filament and allow it to rotate."
msgstr ""
msgid "The AMS will automatically rotate the stored filament slots to enhance the drying performance."
msgstr ""
msgid "Alternatively, you can dry the filament without removing it."
msgstr ""
msgid "Unknown filaments will be treated as PLA."
msgstr ""
msgid "Please store the filament marked with an exclamation mark."
msgstr ""
msgid "Filament left in the feeder during drying may soften because the drying temperature exceeds the softening point of materials like PLA and TPU."
msgstr ""
msgid "Starting: Checking adapter connection"
msgstr ""
msgid "Starting: Checking filament status"
msgstr ""
msgid "Starting: Checking drying presets"
msgstr ""
msgid "Starting: Checking filament location"
msgstr ""
msgid "Starting: Checking air intake"
msgstr ""
msgid "Starting: Checking air vent"
msgstr ""
msgid "The filament may not be compatible with the current machine settings. Generic filament presets will be used."
msgstr "Le filament peut ne pas être compatible avec les paramètres actuels de la machine. Les préréglages de filament génériques seront utilisés."
@@ -20129,6 +20405,12 @@ msgstr ""
"Éviter la déformation\n"
"Saviez-vous que lors de limpression de matériaux susceptibles de se déformer, tels que lABS, une augmentation appropriée de la température du plateau chauffant peut réduire la probabilité de déformation?"
#~ msgid "°C"
#~ msgstr "°C"
#~ msgid "%"
#~ msgstr "%"
#~ msgid "Renders cast shadows on the plate in realistic view."
#~ msgstr "Affiche les ombres portées sur la plaque dans la vue réaliste."

View File

@@ -3,7 +3,7 @@ msgid ""
msgstr ""
"Project-Id-Version: Orca Slicer\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-07-13 16:24-0300\n"
"POT-Creation-Date: 2026-07-17 15:13-0300\n"
"Language: hu\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
@@ -1978,6 +1978,17 @@ msgstr "Ez a legújabb verzió."
msgid "Info"
msgstr "Infó"
msgid "Loading Plugins"
msgstr ""
#, c-format, boost-format
msgid "Plugin %s is no longer available."
msgstr ""
#, c-format, boost-format
msgid "Plugin %s access is unauthorized."
msgstr ""
msgid "Loading printer & filament profiles"
msgstr "Nyomtató- és filamentprofilok betöltése"
@@ -2095,6 +2106,18 @@ msgstr ""
msgid "Resolve cloud sync conflict"
msgstr ""
msgid "Syncing your account…"
msgstr ""
msgid "Migrating presets…"
msgstr ""
msgid "Fetching plugins…"
msgstr ""
msgid "Loading user presets…"
msgstr ""
msgid "Retrieving printer information, please try again later."
msgstr "Nyomtatóinformációk lekérése folyamatban, próbáld újra később."
@@ -2225,6 +2248,21 @@ msgstr ""
msgid "*"
msgstr "*"
msgid "Plugins"
msgstr ""
#, c-format, boost-format
msgid ""
"Failed to open the Plugins dialog:\n"
"%s"
msgstr ""
msgid "Failed to open the Plugins dialog (unknown error)."
msgstr ""
msgid "Plugin Terminal"
msgstr ""
msgid "Changing application language"
msgstr "Alkalmazás nyelvének megváltoztatása"
@@ -5048,6 +5086,28 @@ msgstr "Érvénytelen formátum. Elvárt vektor formátum: \"%1%\""
msgid "N/A"
msgstr ""
msgid "System agents"
msgstr ""
msgid "No plugin selected"
msgstr ""
msgid "Add plugin"
msgstr ""
msgid "Select plugin"
msgstr ""
msgid "Remove plugin"
msgstr ""
msgid "Configure"
msgstr ""
#, c-format, boost-format
msgid "Configure (%d)"
msgstr ""
msgid "Pick"
msgstr "Kiválasztás"
@@ -5213,9 +5273,6 @@ msgstr "Anyagáramlás"
msgid "Fan speed"
msgstr "Ventilátor fordulatszám"
msgid "°C"
msgstr "°C"
msgid "Time"
msgstr "Idő"
@@ -7251,6 +7308,14 @@ msgctxt "Layers"
msgid "Bottom"
msgstr "Alsó"
msgid "Plugin Selection"
msgstr ""
msgid ""
"No plugins capabilities available for this type.\n"
"Enable or install some to use."
msgstr ""
msgid "Enable detection of build plate position"
msgstr "Nyomtatótálca helyzetének érzékelése"
@@ -8149,6 +8214,40 @@ msgstr "Eszköz oldal"
msgid "Synchronize AMS Filament Information"
msgstr "AMS filament információk szinkronizálása"
msgid "OrcaCloud plugins required by the current preset are not installed:"
msgstr ""
msgid "Install Plugins"
msgstr ""
msgid "Local plugins required by the current preset are missing:"
msgstr ""
msgid "Find on OrcaCloud"
msgstr ""
msgid "Plugins required by the current preset are not activated:"
msgstr ""
msgid "Activate Now"
msgstr ""
msgid "The installed plugin does not provide the required capability — it may be outdated:"
msgstr ""
msgid "Preparing to install plugins..."
msgstr ""
msgid "Installing plugins"
msgstr ""
msgid "Cancelling — finishing the current plugin..."
msgstr ""
#, boost-format
msgid "Installing %1%..."
msgstr ""
msgid "Plate Settings"
msgstr "Tálca beállítások"
@@ -9224,6 +9323,9 @@ msgstr "Többszínű nyomtatás külső tekercssel"
msgid "Your filament grouping method in the sliced file is not optimal."
msgstr "A szeletelt fájlban használt filamentcsoportosítás nem optimális."
msgid "To ensure print quality, the drying temperature will be lowered during printing."
msgstr ""
msgid "Auto Bed Leveling"
msgstr "Automatikus asztalszintezés"
@@ -9951,6 +10053,12 @@ msgstr "Extrudálási szerep váltása G-kód"
msgid "Post-processing Scripts"
msgstr "Utófeldolgozó szkriptek"
msgid "Slicing Pipeline Plugin"
msgstr ""
msgid "Plugin Configuration"
msgstr ""
msgid "Notes"
msgstr "Megjegyzések"
@@ -11101,6 +11209,9 @@ msgstr "Nyomtathatóság váltása objektumhoz/alkatrészhez"
msgid "Switch between Prepare/Preview"
msgstr "Váltás előkészítés/előnézet között"
msgid "Open actions speed dial"
msgstr ""
msgid "Plater"
msgstr "Tálca"
@@ -11965,6 +12076,9 @@ msgstr "API-kulcs"
msgid "HTTP digest"
msgstr ""
msgid "Configuration for the plugin capabilities this preset uses, overriding the global Capabilities configuration. Stored as a raw JSON array and edited through the dialog behind the button, never typed in directly."
msgstr ""
msgid "Avoid crossing walls"
msgstr "Kerülje a falak keresztezését"
@@ -12947,6 +13061,24 @@ msgstr ""
"Az alsó felületi réteg sűrűsége. Esztétikai vagy funkcionális célokra szolgál, nem pedig olyan problémák javítására, mint a túlextrudálás.\n"
"FIGYELMEZTETÉS: Ennek az értéknek a csökkentése kedvezőtlenül befolyásolhatja a tárgyasztalhoz való tapadást."
msgid "Top surface fill order"
msgstr ""
msgid ""
"Direction in which top surfaces are filled when using a center-based pattern (Concentric, Archimedean Chords, Octagram Spiral).\n"
"Outward starts at the center of the surface, so any excess material is pushed towards the edge where it is least visible. Inward starts at the edge and ends with the tight curves at the center.\n"
"Default uses shortest-path ordering, which may run in either direction."
msgstr ""
msgid "Bottom surface fill order"
msgstr ""
msgid ""
"Direction in which bottom surfaces are filled when using a center-based pattern (Concentric, Archimedean Chords, Octagram Spiral).\n"
"Inward starts each surface with the wider outer curves, which improves first layer adhesion on build plates where the tight curves at the center may not stick. Outward starts at the center, pushing any excess material towards the edge.\n"
"Default uses shortest-path ordering, which may run in either direction."
msgstr ""
msgid "Internal solid infill pattern"
msgstr "Belső tömör kitöltés mintája"
@@ -14203,9 +14335,6 @@ msgstr ""
"Ha a firmware már letiltja a ventilátort egy küszöbérték alatt (például a Klipper [fan] off_below: 0.10 értéke kikapcsolja a ventilátort, ha a parancsolt munkaciklus 10% alatt van), akkor ezt az opciót és a firmware küszöbértékét ideális esetben ugyanarra az értékre kell állítani. Ezek megfeleltetése (pl. off_below: 0,10 a Klipperben és 10% itt) garantálja, hogy a szeletelő soha nem ad ki olyan nullától eltérő értéket, amelyet a firmware csendben ejtene, és a ventilátor soha nem kap olyan értéket, amely alacsonyabb, mint amiről tudod, hogy ténylegesen képes forogni.\n"
"A deaktiváláshoz állítsd 0-ra."
msgid "%"
msgstr "%"
msgid "Time cost"
msgstr "Időköltség"
@@ -14907,6 +15036,9 @@ msgstr ""
"A rezgéskompenzáció letiltásához használd a Letiltás típust.\n"
"RRF: X és Y értékek egyenlőek."
msgid "Hz"
msgstr "Hz"
msgid "Y"
msgstr "Y"
@@ -15195,6 +15327,15 @@ msgstr "Extrudálási szerepkör G-kód módosítása (folyamat)"
msgid "This G-code is inserted when the extrusion role is changed. It runs after the machine and filament extrusion role G-code."
msgstr "Ez a G-kód akkor kerül beillesztésre, amikor az extrudálási szerep megváltozik. A gép és a filament extrudálási szerepkör G-kódja után fut."
msgid "Plugins Used"
msgstr ""
msgid "Plugin capabilities referenced by this preset, stored as name;uuid;capability."
msgstr ""
msgid "Python plugin(s) invoked at each slicing pipeline step to read and modify intermediate slicing data, including a final G-code post-processing step. Research/experimental."
msgstr ""
msgid "Printer type"
msgstr "Nyomtató típusa"
@@ -15263,6 +15404,15 @@ msgstr "Visszahúzott mennyiség törlés előtt"
msgid "This is the length of fast retraction before a wipe, relative to retraction length."
msgstr "Ez a törlés előtti gyors visszahúzás hossza a visszahúzási hosszhoz viszonyítva."
msgid "Retract amount after wipe"
msgstr ""
#, c-format
msgid ""
"The length of fast retraction after wipe, relative to retraction length.\n"
"The value will be clamped by 100% minus the retract amount before the wipe value."
msgstr ""
# TODO: Review, changed by lang refactor. PR 14254
msgid "Retract on layer change"
msgstr "Visszahúzás rétegváltáskor"
@@ -16277,16 +16427,6 @@ msgstr "Felső héj vastagság"
msgid "The number of top solid layers is increased when slicing if the thickness calculated by top shell layers is thinner than this value. This can avoid having too thin a shell when layer height is small. 0 means that this setting is disabled and thickness of top shell is determined simply by the number of top shell layers."
msgstr "A felső szilárd rétegek száma szeleteléskor megnő, ha a felső héjrétegekből számított vastagság kisebb ennél az értéknél. Ezzel elkerülhető, hogy túl vékony legyen a héj kis rétegmagasságnál. A 0 azt jelenti, hogy ez a beállítás ki van kapcsolva, és a felső héj vastagságát egyszerűen a felső héjrétegek száma határozza meg."
msgid "Anisotropic surfaces"
msgstr ""
msgid ""
"Anisotropic patterns on the top and bottom surfaces.\n"
"Co-directional printing mode will be applied. For certain patterns, omni-directional filling provides color dispersion when using multi-colored or silk plastics.\n"
"This option disable the gap fill.\n"
"This option can increase a printing time."
msgstr ""
msgid "Separated infills"
msgstr ""
@@ -18120,9 +18260,6 @@ msgstr "Kezdés / Vég"
msgid "Frequency settings"
msgstr "Frekvenciabeállítások"
msgid "Hz"
msgstr "Hz"
msgid "RepRap firmware uses the same frequency range for both axes."
msgstr "A RepRap firmware mindkét tengelyhez ugyanazt a frekvenciatartományt használja."
@@ -20098,6 +20235,145 @@ msgstr ""
msgid "Open File"
msgstr ""
msgid "AMS Dryness Control"
msgstr ""
msgid "Filament Drying Settings"
msgstr ""
msgid "Stopping"
msgstr ""
msgid "Unable to dry temporarily due to ..."
msgstr ""
msgid "Drying Error"
msgstr ""
msgid "Please check the Assistant for troubleshooting"
msgstr ""
msgid "Please remove and store the filament (as shown)."
msgstr ""
msgid "The AMS can rotate the filament which is properly stored, providing better drying results."
msgstr ""
msgid "Rotate spool when drying"
msgstr ""
msgctxt "amsdrying"
msgid "Back"
msgstr ""
msgid "Drying-Heating"
msgstr ""
msgid "Drying-Dehumidifying"
msgstr ""
msgid " maximum drying temperature is "
msgstr ""
msgid " minimum drying temperature is "
msgstr ""
msgid "This filament may not be completely dried."
msgstr ""
msgid "This AMS is currently printing. To ensure print quality, the drying temperature cannot exceed the recommended drying temperature."
msgstr ""
msgid "The temperature shall not exceed the filament's heat distortion temperature"
msgstr ""
msgid "Minimum time value cannot be less than 1."
msgstr ""
msgid "Maximum time value cannot be greater than 24."
msgstr ""
msgid "Insufficient power"
msgstr ""
msgid " Too many AMS drying simultaneously. Please plug in the power or stop other drying processes before starting."
msgstr ""
msgid "AMS is busy"
msgstr ""
msgid " AMS is calibrating | reading RFID | loading/unloading material, please wait."
msgstr ""
msgid "Filament in AMS outlet"
msgstr ""
msgid " The high drying temperature may cause AMS blockage, please unload first."
msgstr ""
msgid "Initiating AMS drying"
msgstr ""
msgid "Not supported in 2D mode"
msgstr ""
msgid "Task in progress"
msgstr ""
msgid " The AMS might be in use during Task."
msgstr ""
msgid " Firmware update in progress, please wait..."
msgstr ""
msgid " Please plug in the power and then use the drying function."
msgstr ""
msgid " The high drying temperature may cause AMS blockage. Please unload the filament manually before proceeding."
msgstr ""
msgid "System is busy"
msgstr ""
msgid " Initiating other drying processes, please wait a few seconds..."
msgstr ""
msgid "For better drying results, remove the filament and allow it to rotate."
msgstr ""
msgid "The AMS will automatically rotate the stored filament slots to enhance the drying performance."
msgstr ""
msgid "Alternatively, you can dry the filament without removing it."
msgstr ""
msgid "Unknown filaments will be treated as PLA."
msgstr ""
msgid "Please store the filament marked with an exclamation mark."
msgstr ""
msgid "Filament left in the feeder during drying may soften because the drying temperature exceeds the softening point of materials like PLA and TPU."
msgstr ""
msgid "Starting: Checking adapter connection"
msgstr ""
msgid "Starting: Checking filament status"
msgstr ""
msgid "Starting: Checking drying presets"
msgstr ""
msgid "Starting: Checking filament location"
msgstr ""
msgid "Starting: Checking air intake"
msgstr ""
msgid "Starting: Checking air vent"
msgstr ""
msgid "The filament may not be compatible with the current machine settings. Generic filament presets will be used."
msgstr "Előfordulhat, hogy a filament nem kompatibilis az aktuális gépbeállításokkal. Általános filamentbeállítások lesznek használva."
@@ -20423,6 +20699,12 @@ msgstr ""
"Kunkorodás elkerülése\n"
"Tudtad, hogy a kunkorodásra hajlamos anyagok (például ABS) nyomtatásakor a tárgyasztal hőmérsékletének növelése csökkentheti a kunkorodás valószínűségét?"
#~ msgid "°C"
#~ msgstr "°C"
#~ msgid "%"
#~ msgstr "%"
#~ msgid "Continue to sync filaments"
#~ msgstr "Filamentek szinkronizálásának folytatása"

View File

@@ -3,7 +3,7 @@ msgid ""
msgstr ""
"Project-Id-Version: Orca Slicer\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-07-13 16:24-0300\n"
"POT-Creation-Date: 2026-07-17 15:13-0300\n"
"PO-Revision-Date: \n"
"Last-Translator: \n"
"Language-Team: \n"
@@ -1980,6 +1980,17 @@ msgstr "Hai la versione più recente."
msgid "Info"
msgstr "Informazioni"
msgid "Loading Plugins"
msgstr ""
#, c-format, boost-format
msgid "Plugin %s is no longer available."
msgstr ""
#, c-format, boost-format
msgid "Plugin %s access is unauthorized."
msgstr ""
msgid "Loading printer & filament profiles"
msgstr ""
@@ -2097,6 +2108,18 @@ msgstr ""
msgid "Resolve cloud sync conflict"
msgstr ""
msgid "Syncing your account…"
msgstr ""
msgid "Migrating presets…"
msgstr ""
msgid "Fetching plugins…"
msgstr ""
msgid "Loading user presets…"
msgstr ""
msgid "Retrieving printer information, please try again later."
msgstr "Recupero delle informazioni della stampante, riprovare più tardi."
@@ -2227,6 +2250,21 @@ msgstr ""
msgid "*"
msgstr "*"
msgid "Plugins"
msgstr ""
#, c-format, boost-format
msgid ""
"Failed to open the Plugins dialog:\n"
"%s"
msgstr ""
msgid "Failed to open the Plugins dialog (unknown error)."
msgstr ""
msgid "Plugin Terminal"
msgstr ""
msgid "Changing application language"
msgstr "Modifica lingua applicazione"
@@ -5049,6 +5087,28 @@ msgstr "Formato non valido. Formato vettoriale previsto: \"%1%\""
msgid "N/A"
msgstr "N/D"
msgid "System agents"
msgstr ""
msgid "No plugin selected"
msgstr ""
msgid "Add plugin"
msgstr ""
msgid "Select plugin"
msgstr ""
msgid "Remove plugin"
msgstr ""
msgid "Configure"
msgstr ""
#, c-format, boost-format
msgid "Configure (%d)"
msgstr ""
msgid "Pick"
msgstr "Seleziona"
@@ -5214,9 +5274,6 @@ msgstr "Flusso di stampa"
msgid "Fan speed"
msgstr "Velocità ventola"
msgid "°C"
msgstr "°C"
msgid "Time"
msgstr "Tempo"
@@ -7252,6 +7309,14 @@ msgctxt "Layers"
msgid "Bottom"
msgstr "Inferiore"
msgid "Plugin Selection"
msgstr ""
msgid ""
"No plugins capabilities available for this type.\n"
"Enable or install some to use."
msgstr ""
msgid "Enable detection of build plate position"
msgstr "Abilita rilevamento posizione del piatto"
@@ -8156,6 +8221,40 @@ msgstr "Pagina dispositivo"
msgid "Synchronize AMS Filament Information"
msgstr "Sincronizza informazioni filamento AMS"
msgid "OrcaCloud plugins required by the current preset are not installed:"
msgstr ""
msgid "Install Plugins"
msgstr ""
msgid "Local plugins required by the current preset are missing:"
msgstr ""
msgid "Find on OrcaCloud"
msgstr ""
msgid "Plugins required by the current preset are not activated:"
msgstr ""
msgid "Activate Now"
msgstr ""
msgid "The installed plugin does not provide the required capability — it may be outdated:"
msgstr ""
msgid "Preparing to install plugins..."
msgstr ""
msgid "Installing plugins"
msgstr ""
msgid "Cancelling — finishing the current plugin..."
msgstr ""
#, boost-format
msgid "Installing %1%..."
msgstr ""
msgid "Plate Settings"
msgstr "Impostazioni Piatto"
@@ -9214,6 +9313,9 @@ msgstr "Multicolore con esterno"
msgid "Your filament grouping method in the sliced file is not optimal."
msgstr "Il metodo di raggruppamento filamenti nel file di slicing non è ottimale."
msgid "To ensure print quality, the drying temperature will be lowered during printing."
msgstr ""
msgid "Auto Bed Leveling"
msgstr "Livellamento automatico del piatto"
@@ -9944,6 +10046,12 @@ msgstr "G-code cambio ruolo di estrusione"
msgid "Post-processing Scripts"
msgstr "Script di post-elaborazione"
msgid "Slicing Pipeline Plugin"
msgstr ""
msgid "Plugin Configuration"
msgstr ""
msgid "Notes"
msgstr "Note"
@@ -11083,6 +11191,9 @@ msgstr "Attiva/disattiva stampa per oggetto/parte"
msgid "Switch between Prepare/Preview"
msgstr "Passa tra Prepara e Anteprima"
msgid "Open actions speed dial"
msgstr ""
msgid "Plater"
msgstr "Piatto"
@@ -11947,6 +12058,9 @@ msgstr "Chiave API"
msgid "HTTP digest"
msgstr "Autenticazione sicura HTTP"
msgid "Configuration for the plugin capabilities this preset uses, overriding the global Capabilities configuration. Stored as a raw JSON array and edited through the dialog behind the button, never typed in directly."
msgstr ""
msgid "Avoid crossing walls"
msgstr "Evita di attraversare le pareti"
@@ -12930,6 +13044,24 @@ msgstr ""
"Densità dello strato superficiale inferiore. Destinato a scopi estetici o funzionali, non per risolvere problemi come la sovraestrusione.\n"
"ATTENZIONE: la riduzione di questo valore potrebbe influire negativamente sull'adesione al piatto."
msgid "Top surface fill order"
msgstr ""
msgid ""
"Direction in which top surfaces are filled when using a center-based pattern (Concentric, Archimedean Chords, Octagram Spiral).\n"
"Outward starts at the center of the surface, so any excess material is pushed towards the edge where it is least visible. Inward starts at the edge and ends with the tight curves at the center.\n"
"Default uses shortest-path ordering, which may run in either direction."
msgstr ""
msgid "Bottom surface fill order"
msgstr ""
msgid ""
"Direction in which bottom surfaces are filled when using a center-based pattern (Concentric, Archimedean Chords, Octagram Spiral).\n"
"Inward starts each surface with the wider outer curves, which improves first layer adhesion on build plates where the tight curves at the center may not stick. Outward starts at the center, pushing any excess material towards the edge.\n"
"Default uses shortest-path ordering, which may run in either direction."
msgstr ""
msgid "Internal solid infill pattern"
msgstr "Motivo riempimento solido interno"
@@ -14182,9 +14314,6 @@ msgid ""
"Set to 0 to deactivate."
msgstr ""
msgid "%"
msgstr "%"
msgid "Time cost"
msgstr "Costo orario"
@@ -14884,6 +15013,9 @@ msgstr ""
"Per disabilitare la compensazione della risonanza, selezionare il tipo \"Disabilita\".\n"
"RRF: i valori X e Y sono uguali."
msgid "Hz"
msgstr "Hz"
msgid "Y"
msgstr "Y"
@@ -15169,6 +15301,15 @@ msgstr "Modifica G-code ruolo di estrusione (processo)"
msgid "This G-code is inserted when the extrusion role is changed. It runs after the machine and filament extrusion role G-code."
msgstr "Questo G-code viene inserito quando si effettua il cambio del ruolo di estrusione. Viene eseguito dopo il G-code della macchina e del ruolo di estrusione del filamento."
msgid "Plugins Used"
msgstr ""
msgid "Plugin capabilities referenced by this preset, stored as name;uuid;capability."
msgstr ""
msgid "Python plugin(s) invoked at each slicing pipeline step to read and modify intermediate slicing data, including a final G-code post-processing step. Research/experimental."
msgstr ""
msgid "Printer type"
msgstr "Tipo stampante"
@@ -15237,6 +15378,15 @@ msgstr "Quantità di retrazione prima di spurgo"
msgid "This is the length of fast retraction before a wipe, relative to retraction length."
msgstr "Indica la lunghezza della retrazione veloce prima di uno spurgo, rispetto alla lunghezza di retrazione."
msgid "Retract amount after wipe"
msgstr ""
#, c-format
msgid ""
"The length of fast retraction after wipe, relative to retraction length.\n"
"The value will be clamped by 100% minus the retract amount before the wipe value."
msgstr ""
# TODO: Review, changed by lang refactor. PR 14254
msgid "Retract on layer change"
msgstr "Ritrai al cambio di strato"
@@ -16245,16 +16395,6 @@ msgstr "Spessore guscio superiore"
msgid "The number of top solid layers is increased when slicing if the thickness calculated by top shell layers is thinner than this value. This can avoid having too thin a shell when layer height is small. 0 means that this setting is disabled and thickness of top shell is determined simply by the number of top shell layers."
msgstr "Il numero di strati solidi superiori viene aumentato durante l'elaborazione se lo spessore calcolato dagli strati del guscio superiore è più sottile di questo valore. In questo modo si evita di avere un guscio troppo sottile quando l'altezza degli strati è piccola. Il valore 0 indica che questa impostazione è disattivata e che lo spessore del guscio superiore è determinato in modo assoluto dagli strati del guscio superiore."
msgid "Anisotropic surfaces"
msgstr ""
msgid ""
"Anisotropic patterns on the top and bottom surfaces.\n"
"Co-directional printing mode will be applied. For certain patterns, omni-directional filling provides color dispersion when using multi-colored or silk plastics.\n"
"This option disable the gap fill.\n"
"This option can increase a printing time."
msgstr ""
msgid "Separated infills"
msgstr ""
@@ -18086,9 +18226,6 @@ msgstr "Inizio / Fine"
msgid "Frequency settings"
msgstr "Impostazioni frequenza"
msgid "Hz"
msgstr "Hz"
msgid "RepRap firmware uses the same frequency range for both axes."
msgstr "Il firmware RepRap utilizza lo stesso intervallo di frequenza per entrambi gli assi."
@@ -20081,6 +20218,145 @@ msgstr ""
msgid "Open File"
msgstr ""
msgid "AMS Dryness Control"
msgstr ""
msgid "Filament Drying Settings"
msgstr ""
msgid "Stopping"
msgstr ""
msgid "Unable to dry temporarily due to ..."
msgstr ""
msgid "Drying Error"
msgstr ""
msgid "Please check the Assistant for troubleshooting"
msgstr ""
msgid "Please remove and store the filament (as shown)."
msgstr ""
msgid "The AMS can rotate the filament which is properly stored, providing better drying results."
msgstr ""
msgid "Rotate spool when drying"
msgstr ""
msgctxt "amsdrying"
msgid "Back"
msgstr ""
msgid "Drying-Heating"
msgstr ""
msgid "Drying-Dehumidifying"
msgstr ""
msgid " maximum drying temperature is "
msgstr ""
msgid " minimum drying temperature is "
msgstr ""
msgid "This filament may not be completely dried."
msgstr ""
msgid "This AMS is currently printing. To ensure print quality, the drying temperature cannot exceed the recommended drying temperature."
msgstr ""
msgid "The temperature shall not exceed the filament's heat distortion temperature"
msgstr ""
msgid "Minimum time value cannot be less than 1."
msgstr ""
msgid "Maximum time value cannot be greater than 24."
msgstr ""
msgid "Insufficient power"
msgstr ""
msgid " Too many AMS drying simultaneously. Please plug in the power or stop other drying processes before starting."
msgstr ""
msgid "AMS is busy"
msgstr ""
msgid " AMS is calibrating | reading RFID | loading/unloading material, please wait."
msgstr ""
msgid "Filament in AMS outlet"
msgstr ""
msgid " The high drying temperature may cause AMS blockage, please unload first."
msgstr ""
msgid "Initiating AMS drying"
msgstr ""
msgid "Not supported in 2D mode"
msgstr ""
msgid "Task in progress"
msgstr ""
msgid " The AMS might be in use during Task."
msgstr ""
msgid " Firmware update in progress, please wait..."
msgstr ""
msgid " Please plug in the power and then use the drying function."
msgstr ""
msgid " The high drying temperature may cause AMS blockage. Please unload the filament manually before proceeding."
msgstr ""
msgid "System is busy"
msgstr ""
msgid " Initiating other drying processes, please wait a few seconds..."
msgstr ""
msgid "For better drying results, remove the filament and allow it to rotate."
msgstr ""
msgid "The AMS will automatically rotate the stored filament slots to enhance the drying performance."
msgstr ""
msgid "Alternatively, you can dry the filament without removing it."
msgstr ""
msgid "Unknown filaments will be treated as PLA."
msgstr ""
msgid "Please store the filament marked with an exclamation mark."
msgstr ""
msgid "Filament left in the feeder during drying may soften because the drying temperature exceeds the softening point of materials like PLA and TPU."
msgstr ""
msgid "Starting: Checking adapter connection"
msgstr ""
msgid "Starting: Checking filament status"
msgstr ""
msgid "Starting: Checking drying presets"
msgstr ""
msgid "Starting: Checking filament location"
msgstr ""
msgid "Starting: Checking air intake"
msgstr ""
msgid "Starting: Checking air vent"
msgstr ""
msgid "The filament may not be compatible with the current machine settings. Generic filament presets will be used."
msgstr "Il filamento potrebbe non essere compatibile con le impostazioni correnti della macchina. Verranno utilizzati i profili di filamento generici."
@@ -20403,6 +20679,12 @@ msgstr ""
"Evita le deformazioni\n"
"Sapevi che quando si stampano materiali soggetti a deformazioni come l'ABS, aumentare in modo appropriato la temperatura del piano riscaldato può ridurre la probabilità di deformazione?"
#~ msgid "°C"
#~ msgstr "°C"
#~ msgid "%"
#~ msgstr "%"
#~ msgid "Continue to sync filaments"
#~ msgstr "Continua la sincronizzazione dei filamenti"

View File

@@ -3,7 +3,7 @@ msgid ""
msgstr ""
"Project-Id-Version: Orca Slicer\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-07-13 16:24-0300\n"
"POT-Creation-Date: 2026-07-17 15:13-0300\n"
"PO-Revision-Date: \n"
"Last-Translator: \n"
"Language-Team: \n"
@@ -1979,6 +1979,17 @@ msgstr "最新バージョンです。"
msgid "Info"
msgstr "情報"
msgid "Loading Plugins"
msgstr ""
#, c-format, boost-format
msgid "Plugin %s is no longer available."
msgstr ""
#, c-format, boost-format
msgid "Plugin %s access is unauthorized."
msgstr ""
msgid "Loading printer & filament profiles"
msgstr ""
@@ -2096,6 +2107,18 @@ msgstr ""
msgid "Resolve cloud sync conflict"
msgstr ""
msgid "Syncing your account…"
msgstr ""
msgid "Migrating presets…"
msgstr ""
msgid "Fetching plugins…"
msgstr ""
msgid "Loading user presets…"
msgstr ""
msgid "Retrieving printer information, please try again later."
msgstr "プリンター情報を取得中です。後でもう一度お試しください。"
@@ -2221,6 +2244,21 @@ msgstr ""
msgid "*"
msgstr "*"
msgid "Plugins"
msgstr ""
#, c-format, boost-format
msgid ""
"Failed to open the Plugins dialog:\n"
"%s"
msgstr ""
msgid "Failed to open the Plugins dialog (unknown error)."
msgstr ""
msgid "Plugin Terminal"
msgstr ""
msgid "Changing application language"
msgstr "言語を変更"
@@ -5022,6 +5060,28 @@ msgstr "無効なフォーマット、%1%であるはずです。"
msgid "N/A"
msgstr ""
msgid "System agents"
msgstr ""
msgid "No plugin selected"
msgstr ""
msgid "Add plugin"
msgstr ""
msgid "Select plugin"
msgstr ""
msgid "Remove plugin"
msgstr ""
msgid "Configure"
msgstr ""
#, c-format, boost-format
msgid "Configure (%d)"
msgstr ""
msgid "Pick"
msgstr "ピック"
@@ -5187,9 +5247,6 @@ msgstr "フロー率"
msgid "Fan speed"
msgstr "回転速度"
msgid "°C"
msgstr "°C"
msgid "Time"
msgstr "時間"
@@ -7205,6 +7262,14 @@ msgctxt "Layers"
msgid "Bottom"
msgstr "底面"
msgid "Plugin Selection"
msgstr ""
msgid ""
"No plugins capabilities available for this type.\n"
"Enable or install some to use."
msgstr ""
msgid "Enable detection of build plate position"
msgstr "プレート位置検出を有効"
@@ -8114,6 +8179,40 @@ msgstr "デバイスページ"
msgid "Synchronize AMS Filament Information"
msgstr "AMSフィラメント情報を同期"
msgid "OrcaCloud plugins required by the current preset are not installed:"
msgstr ""
msgid "Install Plugins"
msgstr ""
msgid "Local plugins required by the current preset are missing:"
msgstr ""
msgid "Find on OrcaCloud"
msgstr ""
msgid "Plugins required by the current preset are not activated:"
msgstr ""
msgid "Activate Now"
msgstr ""
msgid "The installed plugin does not provide the required capability — it may be outdated:"
msgstr ""
msgid "Preparing to install plugins..."
msgstr ""
msgid "Installing plugins"
msgstr ""
msgid "Cancelling — finishing the current plugin..."
msgstr ""
#, boost-format
msgid "Installing %1%..."
msgstr ""
msgid "Plate Settings"
msgstr "プレート設定"
@@ -9175,6 +9274,9 @@ msgstr "外部スプールでマルチカラー"
msgid "Your filament grouping method in the sliced file is not optimal."
msgstr "スライスファイルのフィラメントグルーピング方法は最適ではありません。"
msgid "To ensure print quality, the drying temperature will be lowered during printing."
msgstr ""
msgid "Auto Bed Leveling"
msgstr "自動ベッドレベリング"
@@ -9903,6 +10005,12 @@ msgstr "押出ロール変更G-code"
msgid "Post-processing Scripts"
msgstr "ポストプロセッシングスクリプト"
msgid "Slicing Pipeline Plugin"
msgstr ""
msgid "Plugin Configuration"
msgstr ""
msgid "Notes"
msgstr "メモ"
@@ -11016,6 +11124,9 @@ msgstr ""
msgid "Switch between Prepare/Preview"
msgstr "準備/プレビュー間の切り替え"
msgid "Open actions speed dial"
msgstr ""
msgid "Plater"
msgstr "準備"
@@ -11862,6 +11973,9 @@ msgstr "APIキー"
msgid "HTTP digest"
msgstr ""
msgid "Configuration for the plugin capabilities this preset uses, overriding the global Capabilities configuration. Stored as a raw JSON array and edited through the dialog behind the button, never typed in directly."
msgstr ""
msgid "Avoid crossing walls"
msgstr "壁上の移動を迂回"
@@ -12733,6 +12847,24 @@ msgid ""
"WARNING: Lowering this value may negatively affect bed adhesion."
msgstr ""
msgid "Top surface fill order"
msgstr ""
msgid ""
"Direction in which top surfaces are filled when using a center-based pattern (Concentric, Archimedean Chords, Octagram Spiral).\n"
"Outward starts at the center of the surface, so any excess material is pushed towards the edge where it is least visible. Inward starts at the edge and ends with the tight curves at the center.\n"
"Default uses shortest-path ordering, which may run in either direction."
msgstr ""
msgid "Bottom surface fill order"
msgstr ""
msgid ""
"Direction in which bottom surfaces are filled when using a center-based pattern (Concentric, Archimedean Chords, Octagram Spiral).\n"
"Inward starts each surface with the wider outer curves, which improves first layer adhesion on build plates where the tight curves at the center may not stick. Outward starts at the center, pushing any excess material towards the edge.\n"
"Default uses shortest-path ordering, which may run in either direction."
msgstr ""
msgid "Internal solid infill pattern"
msgstr "内部ソリッドインフィルパターン"
@@ -13900,9 +14032,6 @@ msgid ""
"Set to 0 to deactivate."
msgstr ""
msgid "%"
msgstr "%"
msgid "Time cost"
msgstr ""
@@ -14568,6 +14697,9 @@ msgid ""
"RRF: X and Y values are equal."
msgstr ""
msgid "Hz"
msgstr "Hz"
msgid "Y"
msgstr "Y"
@@ -14817,6 +14949,15 @@ msgstr ""
msgid "This G-code is inserted when the extrusion role is changed. It runs after the machine and filament extrusion role G-code."
msgstr ""
msgid "Plugins Used"
msgstr ""
msgid "Plugin capabilities referenced by this preset, stored as name;uuid;capability."
msgstr ""
msgid "Python plugin(s) invoked at each slicing pipeline step to read and modify intermediate slicing data, including a final G-code post-processing step. Research/experimental."
msgstr ""
msgid "Printer type"
msgstr "プリンタータイプ"
@@ -14885,6 +15026,15 @@ msgstr "拭き上げ前のリトラクション量"
msgid "This is the length of fast retraction before a wipe, relative to retraction length."
msgstr "拭き上げ前のリトラクション量です、通常のリトラクション量の比率で指定します。"
msgid "Retract amount after wipe"
msgstr ""
#, c-format
msgid ""
"The length of fast retraction after wipe, relative to retraction length.\n"
"The value will be clamped by 100% minus the retract amount before the wipe value."
msgstr ""
# TODO: Review, changed by lang refactor. PR 14254
msgid "Retract on layer change"
msgstr "積層変更時のリトラクション"
@@ -15858,16 +16008,6 @@ msgstr "トップ面厚さ"
msgid "The number of top solid layers is increased when slicing if the thickness calculated by top shell layers is thinner than this value. This can avoid having too thin a shell when layer height is small. 0 means that this setting is disabled and thickness of top shell is determined simply by the number of top shell layers."
msgstr "トップ面の厚さです、トップ面層数で決まった厚みがこの値より小さい場合、層数を増やします。この値が0にする場合、この設定が無効となり、設定した層数で造形します。"
msgid "Anisotropic surfaces"
msgstr ""
msgid ""
"Anisotropic patterns on the top and bottom surfaces.\n"
"Co-directional printing mode will be applied. For certain patterns, omni-directional filling provides color dispersion when using multi-colored or silk plastics.\n"
"This option disable the gap fill.\n"
"This option can increase a printing time."
msgstr ""
msgid "Separated infills"
msgstr ""
@@ -17627,9 +17767,6 @@ msgstr "開始/終了"
msgid "Frequency settings"
msgstr "周波数設定"
msgid "Hz"
msgstr "Hz"
msgid "RepRap firmware uses the same frequency range for both axes."
msgstr ""
@@ -19572,6 +19709,145 @@ msgstr ""
msgid "Open File"
msgstr ""
msgid "AMS Dryness Control"
msgstr ""
msgid "Filament Drying Settings"
msgstr ""
msgid "Stopping"
msgstr ""
msgid "Unable to dry temporarily due to ..."
msgstr ""
msgid "Drying Error"
msgstr ""
msgid "Please check the Assistant for troubleshooting"
msgstr ""
msgid "Please remove and store the filament (as shown)."
msgstr ""
msgid "The AMS can rotate the filament which is properly stored, providing better drying results."
msgstr ""
msgid "Rotate spool when drying"
msgstr ""
msgctxt "amsdrying"
msgid "Back"
msgstr ""
msgid "Drying-Heating"
msgstr ""
msgid "Drying-Dehumidifying"
msgstr ""
msgid " maximum drying temperature is "
msgstr ""
msgid " minimum drying temperature is "
msgstr ""
msgid "This filament may not be completely dried."
msgstr ""
msgid "This AMS is currently printing. To ensure print quality, the drying temperature cannot exceed the recommended drying temperature."
msgstr ""
msgid "The temperature shall not exceed the filament's heat distortion temperature"
msgstr ""
msgid "Minimum time value cannot be less than 1."
msgstr ""
msgid "Maximum time value cannot be greater than 24."
msgstr ""
msgid "Insufficient power"
msgstr ""
msgid " Too many AMS drying simultaneously. Please plug in the power or stop other drying processes before starting."
msgstr ""
msgid "AMS is busy"
msgstr ""
msgid " AMS is calibrating | reading RFID | loading/unloading material, please wait."
msgstr ""
msgid "Filament in AMS outlet"
msgstr ""
msgid " The high drying temperature may cause AMS blockage, please unload first."
msgstr ""
msgid "Initiating AMS drying"
msgstr ""
msgid "Not supported in 2D mode"
msgstr ""
msgid "Task in progress"
msgstr ""
msgid " The AMS might be in use during Task."
msgstr ""
msgid " Firmware update in progress, please wait..."
msgstr ""
msgid " Please plug in the power and then use the drying function."
msgstr ""
msgid " The high drying temperature may cause AMS blockage. Please unload the filament manually before proceeding."
msgstr ""
msgid "System is busy"
msgstr ""
msgid " Initiating other drying processes, please wait a few seconds..."
msgstr ""
msgid "For better drying results, remove the filament and allow it to rotate."
msgstr ""
msgid "The AMS will automatically rotate the stored filament slots to enhance the drying performance."
msgstr ""
msgid "Alternatively, you can dry the filament without removing it."
msgstr ""
msgid "Unknown filaments will be treated as PLA."
msgstr ""
msgid "Please store the filament marked with an exclamation mark."
msgstr ""
msgid "Filament left in the feeder during drying may soften because the drying temperature exceeds the softening point of materials like PLA and TPU."
msgstr ""
msgid "Starting: Checking adapter connection"
msgstr ""
msgid "Starting: Checking filament status"
msgstr ""
msgid "Starting: Checking drying presets"
msgstr ""
msgid "Starting: Checking filament location"
msgstr ""
msgid "Starting: Checking air intake"
msgstr ""
msgid "Starting: Checking air vent"
msgstr ""
msgid "The filament may not be compatible with the current machine settings. Generic filament presets will be used."
msgstr "フィラメントが現在のマシン設定と互換性がない可能性があります。ジェネリックフィラメントプリセットが使用されます。"
@@ -19871,6 +20147,12 @@ msgstr ""
"反りを避ける\n"
"ABSのような反りやすい素材を印刷する場合、ヒートベッドの温度を適切に上げることで、反りが発生する確率を下げることができることをご存知ですか"
#~ msgid "°C"
#~ msgstr "°C"
#~ msgid "%"
#~ msgstr "%"
#~ msgid "Continue to sync filaments"
#~ msgstr "フィラメントの同期を続行"

View File

@@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: Orca Slicer\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-07-13 16:24-0300\n"
"POT-Creation-Date: 2026-07-17 15:13-0300\n"
"PO-Revision-Date: 2025-06-02 17:12+0900\n"
"Last-Translator: crwusiz <crwusiz@gmail.com>\n"
"Language-Team: \n"
@@ -1985,6 +1985,17 @@ msgstr "최신 버전입니다."
msgid "Info"
msgstr "정보"
msgid "Loading Plugins"
msgstr ""
#, c-format, boost-format
msgid "Plugin %s is no longer available."
msgstr ""
#, c-format, boost-format
msgid "Plugin %s access is unauthorized."
msgstr ""
msgid "Loading printer & filament profiles"
msgstr ""
@@ -2102,6 +2113,18 @@ msgstr ""
msgid "Resolve cloud sync conflict"
msgstr ""
msgid "Syncing your account…"
msgstr ""
msgid "Migrating presets…"
msgstr ""
msgid "Fetching plugins…"
msgstr ""
msgid "Loading user presets…"
msgstr ""
msgid "Retrieving printer information, please try again later."
msgstr "프린터 정보를 가져오는 중입니다. 나중에 다시 시도하세요."
@@ -2227,6 +2250,21 @@ msgstr ""
msgid "*"
msgstr "*"
msgid "Plugins"
msgstr ""
#, c-format, boost-format
msgid ""
"Failed to open the Plugins dialog:\n"
"%s"
msgstr ""
msgid "Failed to open the Plugins dialog (unknown error)."
msgstr ""
msgid "Plugin Terminal"
msgstr ""
msgid "Changing application language"
msgstr "응용 프로그램 언어 변경"
@@ -5048,6 +5086,28 @@ msgstr "잘못된 형식입니다. 필요한 벡터 형식: \"%1%\""
msgid "N/A"
msgstr ""
msgid "System agents"
msgstr ""
msgid "No plugin selected"
msgstr ""
msgid "Add plugin"
msgstr ""
msgid "Select plugin"
msgstr ""
msgid "Remove plugin"
msgstr ""
msgid "Configure"
msgstr ""
#, c-format, boost-format
msgid "Configure (%d)"
msgstr ""
msgid "Pick"
msgstr "선택"
@@ -5213,9 +5273,6 @@ msgstr "압출량"
msgid "Fan speed"
msgstr "팬 속도"
msgid "°C"
msgstr "°C"
msgid "Time"
msgstr "시간"
@@ -7241,6 +7298,14 @@ msgctxt "Layers"
msgid "Bottom"
msgstr "하부"
msgid "Plugin Selection"
msgstr ""
msgid ""
"No plugins capabilities available for this type.\n"
"Enable or install some to use."
msgstr ""
msgid "Enable detection of build plate position"
msgstr "빌드 플레이트 위치 감지 활성화"
@@ -8146,6 +8211,40 @@ msgstr "디바이스 페이지"
msgid "Synchronize AMS Filament Information"
msgstr "AMS 필라멘트 정보 동기화"
msgid "OrcaCloud plugins required by the current preset are not installed:"
msgstr ""
msgid "Install Plugins"
msgstr ""
msgid "Local plugins required by the current preset are missing:"
msgstr ""
msgid "Find on OrcaCloud"
msgstr ""
msgid "Plugins required by the current preset are not activated:"
msgstr ""
msgid "Activate Now"
msgstr ""
msgid "The installed plugin does not provide the required capability — it may be outdated:"
msgstr ""
msgid "Preparing to install plugins..."
msgstr ""
msgid "Installing plugins"
msgstr ""
msgid "Cancelling — finishing the current plugin..."
msgstr ""
#, boost-format
msgid "Installing %1%..."
msgstr ""
msgid "Plate Settings"
msgstr "플레이트 설정"
@@ -9197,6 +9296,9 @@ msgstr "외부 멀티 컬러"
msgid "Your filament grouping method in the sliced file is not optimal."
msgstr "슬라이스된 파일의 필라멘트 그룹화 방법이 최적이 아닙니다."
msgid "To ensure print quality, the drying temperature will be lowered during printing."
msgstr ""
msgid "Auto Bed Leveling"
msgstr "자동 베드 레벨링"
@@ -9925,6 +10027,12 @@ msgstr "압출 역할 Gcode 변경"
msgid "Post-processing Scripts"
msgstr "후처리 스크립트"
msgid "Slicing Pipeline Plugin"
msgstr ""
msgid "Plugin Configuration"
msgstr ""
msgid "Notes"
msgstr "메모"
@@ -11049,6 +11157,9 @@ msgstr ""
msgid "Switch between Prepare/Preview"
msgstr "준비 하기/미리 보기 전환"
msgid "Open actions speed dial"
msgstr ""
msgid "Plater"
msgstr "출력판"
@@ -11906,6 +12017,9 @@ msgstr "API 키"
msgid "HTTP digest"
msgstr "HTTP 다이제스트"
msgid "Configuration for the plugin capabilities this preset uses, overriding the global Capabilities configuration. Stored as a raw JSON array and edited through the dialog behind the button, never typed in directly."
msgstr ""
msgid "Avoid crossing walls"
msgstr "벽 가로지름 방지"
@@ -12856,6 +12970,24 @@ msgid ""
"WARNING: Lowering this value may negatively affect bed adhesion."
msgstr ""
msgid "Top surface fill order"
msgstr ""
msgid ""
"Direction in which top surfaces are filled when using a center-based pattern (Concentric, Archimedean Chords, Octagram Spiral).\n"
"Outward starts at the center of the surface, so any excess material is pushed towards the edge where it is least visible. Inward starts at the edge and ends with the tight curves at the center.\n"
"Default uses shortest-path ordering, which may run in either direction."
msgstr ""
msgid "Bottom surface fill order"
msgstr ""
msgid ""
"Direction in which bottom surfaces are filled when using a center-based pattern (Concentric, Archimedean Chords, Octagram Spiral).\n"
"Inward starts each surface with the wider outer curves, which improves first layer adhesion on build plates where the tight curves at the center may not stick. Outward starts at the center, pushing any excess material towards the edge.\n"
"Default uses shortest-path ordering, which may run in either direction."
msgstr ""
msgid "Internal solid infill pattern"
msgstr "꽉찬 내부 채우기 패턴"
@@ -14070,9 +14202,6 @@ msgid ""
"Set to 0 to deactivate."
msgstr ""
msgid "%"
msgstr "%"
msgid "Time cost"
msgstr "시간비용"
@@ -14760,6 +14889,9 @@ msgid ""
"RRF: X and Y values are equal."
msgstr ""
msgid "Hz"
msgstr "Hz"
msgid "Y"
msgstr "Y"
@@ -15034,6 +15166,15 @@ msgstr ""
msgid "This G-code is inserted when the extrusion role is changed. It runs after the machine and filament extrusion role G-code."
msgstr ""
msgid "Plugins Used"
msgstr ""
msgid "Plugin capabilities referenced by this preset, stored as name;uuid;capability."
msgstr ""
msgid "Python plugin(s) invoked at each slicing pipeline step to read and modify intermediate slicing data, including a final G-code post-processing step. Research/experimental."
msgstr ""
msgid "Printer type"
msgstr "프린터 유형"
@@ -15102,6 +15243,15 @@ msgstr "노즐 청소 전 후퇴량"
msgid "This is the length of fast retraction before a wipe, relative to retraction length."
msgstr "후퇴 길이에 비례한 노즐 청소 전 후퇴량(노즐 청소를 시작하기 전에 일부 필라멘트를 후퇴시키면 노즐 끝에 녹아있는 소량의 필라멘트만 남게되어 추가 누수 위험이 줄어들 수 있습니다)"
msgid "Retract amount after wipe"
msgstr ""
#, c-format
msgid ""
"The length of fast retraction after wipe, relative to retraction length.\n"
"The value will be clamped by 100% minus the retract amount before the wipe value."
msgstr ""
# TODO: Review, changed by lang refactor. PR 14254
msgid "Retract on layer change"
msgstr "레이어 변경 시 후퇴"
@@ -16107,16 +16257,6 @@ msgstr "상단 쉘 두께"
msgid "The number of top solid layers is increased when slicing if the thickness calculated by top shell layers is thinner than this value. This can avoid having too thin a shell when layer height is small. 0 means that this setting is disabled and thickness of top shell is determined simply by the number of top shell layers."
msgstr "상단 쉘 레이어로 계산된 두께가 이 값보다 얇은 경우 슬라이싱할 때 상단 꽉찬 레이어의 수가 증가합니다. 이렇게 하면 레이어 높이가 작을 때 쉘이 너무 얇아지는 것을 방지할 수 있습니다. 0은 이 설정이 비활성화되고 상단 쉘의 두께가 절대적으로 상단 쉘 레이어에 의해 결정됨을 의미합니다"
msgid "Anisotropic surfaces"
msgstr ""
msgid ""
"Anisotropic patterns on the top and bottom surfaces.\n"
"Co-directional printing mode will be applied. For certain patterns, omni-directional filling provides color dispersion when using multi-colored or silk plastics.\n"
"This option disable the gap fill.\n"
"This option can increase a printing time."
msgstr ""
msgid "Separated infills"
msgstr ""
@@ -17944,9 +18084,6 @@ msgstr ""
msgid "Frequency settings"
msgstr ""
msgid "Hz"
msgstr "Hz"
msgid "RepRap firmware uses the same frequency range for both axes."
msgstr ""
@@ -19917,6 +20054,145 @@ msgstr ""
msgid "Open File"
msgstr ""
msgid "AMS Dryness Control"
msgstr ""
msgid "Filament Drying Settings"
msgstr ""
msgid "Stopping"
msgstr ""
msgid "Unable to dry temporarily due to ..."
msgstr ""
msgid "Drying Error"
msgstr ""
msgid "Please check the Assistant for troubleshooting"
msgstr ""
msgid "Please remove and store the filament (as shown)."
msgstr ""
msgid "The AMS can rotate the filament which is properly stored, providing better drying results."
msgstr ""
msgid "Rotate spool when drying"
msgstr ""
msgctxt "amsdrying"
msgid "Back"
msgstr ""
msgid "Drying-Heating"
msgstr ""
msgid "Drying-Dehumidifying"
msgstr ""
msgid " maximum drying temperature is "
msgstr ""
msgid " minimum drying temperature is "
msgstr ""
msgid "This filament may not be completely dried."
msgstr ""
msgid "This AMS is currently printing. To ensure print quality, the drying temperature cannot exceed the recommended drying temperature."
msgstr ""
msgid "The temperature shall not exceed the filament's heat distortion temperature"
msgstr ""
msgid "Minimum time value cannot be less than 1."
msgstr ""
msgid "Maximum time value cannot be greater than 24."
msgstr ""
msgid "Insufficient power"
msgstr ""
msgid " Too many AMS drying simultaneously. Please plug in the power or stop other drying processes before starting."
msgstr ""
msgid "AMS is busy"
msgstr ""
msgid " AMS is calibrating | reading RFID | loading/unloading material, please wait."
msgstr ""
msgid "Filament in AMS outlet"
msgstr ""
msgid " The high drying temperature may cause AMS blockage, please unload first."
msgstr ""
msgid "Initiating AMS drying"
msgstr ""
msgid "Not supported in 2D mode"
msgstr ""
msgid "Task in progress"
msgstr ""
msgid " The AMS might be in use during Task."
msgstr ""
msgid " Firmware update in progress, please wait..."
msgstr ""
msgid " Please plug in the power and then use the drying function."
msgstr ""
msgid " The high drying temperature may cause AMS blockage. Please unload the filament manually before proceeding."
msgstr ""
msgid "System is busy"
msgstr ""
msgid " Initiating other drying processes, please wait a few seconds..."
msgstr ""
msgid "For better drying results, remove the filament and allow it to rotate."
msgstr ""
msgid "The AMS will automatically rotate the stored filament slots to enhance the drying performance."
msgstr ""
msgid "Alternatively, you can dry the filament without removing it."
msgstr ""
msgid "Unknown filaments will be treated as PLA."
msgstr ""
msgid "Please store the filament marked with an exclamation mark."
msgstr ""
msgid "Filament left in the feeder during drying may soften because the drying temperature exceeds the softening point of materials like PLA and TPU."
msgstr ""
msgid "Starting: Checking adapter connection"
msgstr ""
msgid "Starting: Checking filament status"
msgstr ""
msgid "Starting: Checking drying presets"
msgstr ""
msgid "Starting: Checking filament location"
msgstr ""
msgid "Starting: Checking air intake"
msgstr ""
msgid "Starting: Checking air vent"
msgstr ""
msgid "The filament may not be compatible with the current machine settings. Generic filament presets will be used."
msgstr "필라멘트가 현재 기계 설정과 호환되지 않을 수 있습니다. 일반 필라멘트 사전 설정이 사용됩니다."
@@ -20239,6 +20515,12 @@ msgstr ""
"뒤틀림 방지\n"
"ABS와 같이 뒤틀림이 발생하기 쉬운 소재를 출력할 때, 히트베드 온도를 적절하게 높이면 뒤틀림 가능성을 줄일 수 있다는 사실을 알고 계셨나요?"
#~ msgid "°C"
#~ msgstr "°C"
#~ msgid "%"
#~ msgstr "%"
#~ msgid "Continue to sync filaments"
#~ msgstr "필라멘트 동기화 계속하기"

File diff suppressed because it is too large Load Diff

View File

@@ -3,7 +3,7 @@ msgid ""
msgstr ""
"Project-Id-Version: Orca Slicer\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-07-13 16:24-0300\n"
"POT-Creation-Date: 2026-07-17 15:13-0300\n"
"PO-Revision-Date: \n"
"Last-Translator: \n"
"Language-Team: \n"
@@ -1966,6 +1966,17 @@ msgstr "Dit is de nieuwste versie."
msgid "Info"
msgstr "Informatie"
msgid "Loading Plugins"
msgstr ""
#, c-format, boost-format
msgid "Plugin %s is no longer available."
msgstr ""
#, c-format, boost-format
msgid "Plugin %s access is unauthorized."
msgstr ""
msgid "Loading printer & filament profiles"
msgstr ""
@@ -2080,6 +2091,18 @@ msgstr ""
msgid "Resolve cloud sync conflict"
msgstr ""
msgid "Syncing your account…"
msgstr ""
msgid "Migrating presets…"
msgstr ""
msgid "Fetching plugins…"
msgstr ""
msgid "Loading user presets…"
msgstr ""
msgid "Retrieving printer information, please try again later."
msgstr ""
@@ -2198,6 +2221,21 @@ msgstr ""
msgid "*"
msgstr "*"
msgid "Plugins"
msgstr ""
#, c-format, boost-format
msgid ""
"Failed to open the Plugins dialog:\n"
"%s"
msgstr ""
msgid "Failed to open the Plugins dialog (unknown error)."
msgstr ""
msgid "Plugin Terminal"
msgstr ""
msgid "Changing application language"
msgstr "Taal van de applicatie wijzigen"
@@ -4993,6 +5031,28 @@ msgstr "Onjuist formaat. Het Vector formaat wordt verwacht: \"%1%\""
msgid "N/A"
msgstr "N/B"
msgid "System agents"
msgstr ""
msgid "No plugin selected"
msgstr ""
msgid "Add plugin"
msgstr ""
msgid "Select plugin"
msgstr ""
msgid "Remove plugin"
msgstr ""
msgid "Configure"
msgstr ""
#, c-format, boost-format
msgid "Configure (%d)"
msgstr ""
msgid "Pick"
msgstr "Selecteren"
@@ -5158,9 +5218,6 @@ msgstr "Flowrate"
msgid "Fan speed"
msgstr "Ventilator snelheid"
msgid "°C"
msgstr "°C"
msgid "Time"
msgstr "Tijd"
@@ -7171,6 +7228,14 @@ msgctxt "Layers"
msgid "Bottom"
msgstr "Onderste"
msgid "Plugin Selection"
msgstr ""
msgid ""
"No plugins capabilities available for this type.\n"
"Enable or install some to use."
msgstr ""
msgid "Enable detection of build plate position"
msgstr "Detectie van de positie van de printplaat inschakelen"
@@ -8069,6 +8134,40 @@ msgstr ""
msgid "Synchronize AMS Filament Information"
msgstr ""
msgid "OrcaCloud plugins required by the current preset are not installed:"
msgstr ""
msgid "Install Plugins"
msgstr ""
msgid "Local plugins required by the current preset are missing:"
msgstr ""
msgid "Find on OrcaCloud"
msgstr ""
msgid "Plugins required by the current preset are not activated:"
msgstr ""
msgid "Activate Now"
msgstr ""
msgid "The installed plugin does not provide the required capability — it may be outdated:"
msgstr ""
msgid "Preparing to install plugins..."
msgstr ""
msgid "Installing plugins"
msgstr ""
msgid "Cancelling — finishing the current plugin..."
msgstr ""
#, boost-format
msgid "Installing %1%..."
msgstr ""
msgid "Plate Settings"
msgstr "Plaatinstellingen"
@@ -9113,6 +9212,9 @@ msgstr ""
msgid "Your filament grouping method in the sliced file is not optimal."
msgstr ""
msgid "To ensure print quality, the drying temperature will be lowered during printing."
msgstr ""
msgid "Auto Bed Leveling"
msgstr "Automatische bednivellering"
@@ -9830,6 +9932,12 @@ msgstr ""
msgid "Post-processing Scripts"
msgstr ""
msgid "Slicing Pipeline Plugin"
msgstr ""
msgid "Plugin Configuration"
msgstr ""
msgid "Notes"
msgstr "Opmerkingen"
@@ -10943,6 +11051,9 @@ msgstr ""
msgid "Switch between Prepare/Preview"
msgstr ""
msgid "Open actions speed dial"
msgstr ""
msgid "Plater"
msgstr "Plaat"
@@ -11791,6 +11902,9 @@ msgstr "API sleutel"
msgid "HTTP digest"
msgstr "HTTP samenvatting"
msgid "Configuration for the plugin capabilities this preset uses, overriding the global Capabilities configuration. Stored as a raw JSON array and edited through the dialog behind the button, never typed in directly."
msgstr ""
msgid "Avoid crossing walls"
msgstr "Vermijd het oversteken van walls"
@@ -12665,6 +12779,24 @@ msgid ""
"WARNING: Lowering this value may negatively affect bed adhesion."
msgstr ""
msgid "Top surface fill order"
msgstr ""
msgid ""
"Direction in which top surfaces are filled when using a center-based pattern (Concentric, Archimedean Chords, Octagram Spiral).\n"
"Outward starts at the center of the surface, so any excess material is pushed towards the edge where it is least visible. Inward starts at the edge and ends with the tight curves at the center.\n"
"Default uses shortest-path ordering, which may run in either direction."
msgstr ""
msgid "Bottom surface fill order"
msgstr ""
msgid ""
"Direction in which bottom surfaces are filled when using a center-based pattern (Concentric, Archimedean Chords, Octagram Spiral).\n"
"Inward starts each surface with the wider outer curves, which improves first layer adhesion on build plates where the tight curves at the center may not stick. Outward starts at the center, pushing any excess material towards the edge.\n"
"Default uses shortest-path ordering, which may run in either direction."
msgstr ""
msgid "Internal solid infill pattern"
msgstr "Intern massief invulpatroon"
@@ -13825,9 +13957,6 @@ msgid ""
"Set to 0 to deactivate."
msgstr ""
msgid "%"
msgstr "%"
msgid "Time cost"
msgstr ""
@@ -14494,6 +14623,9 @@ msgid ""
"RRF: X and Y values are equal."
msgstr ""
msgid "Hz"
msgstr "Hz"
msgid "Y"
msgstr "Y"
@@ -14743,6 +14875,15 @@ msgstr ""
msgid "This G-code is inserted when the extrusion role is changed. It runs after the machine and filament extrusion role G-code."
msgstr ""
msgid "Plugins Used"
msgstr ""
msgid "Plugin capabilities referenced by this preset, stored as name;uuid;capability."
msgstr ""
msgid "Python plugin(s) invoked at each slicing pipeline step to read and modify intermediate slicing data, including a final G-code post-processing step. Research/experimental."
msgstr ""
msgid "Printer type"
msgstr "Printertype"
@@ -14811,6 +14952,15 @@ msgstr "Terugtrek (retract) hoeveelheid voor schoonvegen"
msgid "This is the length of fast retraction before a wipe, relative to retraction length."
msgstr "Dit is de lengte van snel intrekken (retraction) vóór een wipe, in verhouding tot de retraction lengte."
msgid "Retract amount after wipe"
msgstr ""
#, c-format
msgid ""
"The length of fast retraction after wipe, relative to retraction length.\n"
"The value will be clamped by 100% minus the retract amount before the wipe value."
msgstr ""
# TODO: Review, changed by lang refactor. PR 14254
msgid "Retract on layer change"
msgstr "Terugtrekken (retract) bij wisselen van laag"
@@ -15785,16 +15935,6 @@ msgstr "Dikte bovenkant"
msgid "The number of top solid layers is increased when slicing if the thickness calculated by top shell layers is thinner than this value. This can avoid having too thin a shell when layer height is small. 0 means that this setting is disabled and thickness of top shell is determined simply by the number of top shell layers."
msgstr "Het aantal bovenste solide lagen wordt verhoogd tijdens het slicen als de totale dikte van de bovenste lagen lager is dan deze waarde. Dit zorgt ervoor dat de schaal niet te dun is bij een lage laaghoogte. 0 betekend dat deze instelling niet actief is en dat de dikte van de bovenkant bepaald wordt door het aantal bodem lagen."
msgid "Anisotropic surfaces"
msgstr ""
msgid ""
"Anisotropic patterns on the top and bottom surfaces.\n"
"Co-directional printing mode will be applied. For certain patterns, omni-directional filling provides color dispersion when using multi-colored or silk plastics.\n"
"This option disable the gap fill.\n"
"This option can increase a printing time."
msgstr ""
msgid "Separated infills"
msgstr ""
@@ -17559,9 +17699,6 @@ msgstr ""
msgid "Frequency settings"
msgstr ""
msgid "Hz"
msgstr "Hz"
msgid "RepRap firmware uses the same frequency range for both axes."
msgstr ""
@@ -19504,6 +19641,145 @@ msgstr ""
msgid "Open File"
msgstr ""
msgid "AMS Dryness Control"
msgstr ""
msgid "Filament Drying Settings"
msgstr ""
msgid "Stopping"
msgstr ""
msgid "Unable to dry temporarily due to ..."
msgstr ""
msgid "Drying Error"
msgstr ""
msgid "Please check the Assistant for troubleshooting"
msgstr ""
msgid "Please remove and store the filament (as shown)."
msgstr ""
msgid "The AMS can rotate the filament which is properly stored, providing better drying results."
msgstr ""
msgid "Rotate spool when drying"
msgstr ""
msgctxt "amsdrying"
msgid "Back"
msgstr ""
msgid "Drying-Heating"
msgstr ""
msgid "Drying-Dehumidifying"
msgstr ""
msgid " maximum drying temperature is "
msgstr ""
msgid " minimum drying temperature is "
msgstr ""
msgid "This filament may not be completely dried."
msgstr ""
msgid "This AMS is currently printing. To ensure print quality, the drying temperature cannot exceed the recommended drying temperature."
msgstr ""
msgid "The temperature shall not exceed the filament's heat distortion temperature"
msgstr ""
msgid "Minimum time value cannot be less than 1."
msgstr ""
msgid "Maximum time value cannot be greater than 24."
msgstr ""
msgid "Insufficient power"
msgstr ""
msgid " Too many AMS drying simultaneously. Please plug in the power or stop other drying processes before starting."
msgstr ""
msgid "AMS is busy"
msgstr ""
msgid " AMS is calibrating | reading RFID | loading/unloading material, please wait."
msgstr ""
msgid "Filament in AMS outlet"
msgstr ""
msgid " The high drying temperature may cause AMS blockage, please unload first."
msgstr ""
msgid "Initiating AMS drying"
msgstr ""
msgid "Not supported in 2D mode"
msgstr ""
msgid "Task in progress"
msgstr ""
msgid " The AMS might be in use during Task."
msgstr ""
msgid " Firmware update in progress, please wait..."
msgstr ""
msgid " Please plug in the power and then use the drying function."
msgstr ""
msgid " The high drying temperature may cause AMS blockage. Please unload the filament manually before proceeding."
msgstr ""
msgid "System is busy"
msgstr ""
msgid " Initiating other drying processes, please wait a few seconds..."
msgstr ""
msgid "For better drying results, remove the filament and allow it to rotate."
msgstr ""
msgid "The AMS will automatically rotate the stored filament slots to enhance the drying performance."
msgstr ""
msgid "Alternatively, you can dry the filament without removing it."
msgstr ""
msgid "Unknown filaments will be treated as PLA."
msgstr ""
msgid "Please store the filament marked with an exclamation mark."
msgstr ""
msgid "Filament left in the feeder during drying may soften because the drying temperature exceeds the softening point of materials like PLA and TPU."
msgstr ""
msgid "Starting: Checking adapter connection"
msgstr ""
msgid "Starting: Checking filament status"
msgstr ""
msgid "Starting: Checking drying presets"
msgstr ""
msgid "Starting: Checking filament location"
msgstr ""
msgid "Starting: Checking air intake"
msgstr ""
msgid "Starting: Checking air vent"
msgstr ""
msgid "The filament may not be compatible with the current machine settings. Generic filament presets will be used."
msgstr ""
@@ -19826,6 +20102,12 @@ msgstr ""
"Kromtrekken voorkomen\n"
"Wist je dat bij het printen van materialen die gevoelig zijn voor kromtrekken, zoals ABS, een juiste verhoging van de temperatuur van het warmtebed de kans op kromtrekken kan verkleinen?"
#~ msgid "°C"
#~ msgstr "°C"
#~ msgid "%"
#~ msgstr "%"
#~ msgctxt "Sync_Nozzle_AMS"
#~ msgid "Cancel"
#~ msgstr "Annuleren"

View File

@@ -3,7 +3,7 @@ msgid ""
msgstr ""
"Project-Id-Version: OrcaSlicer 2.3.0-rc\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-07-13 16:24-0300\n"
"POT-Creation-Date: 2026-07-17 15:13-0300\n"
"PO-Revision-Date: \n"
"Last-Translator: Krzysztof Morga <<tlumaczeniebs@gmail.com>>\n"
"Language-Team: \n"
@@ -1986,6 +1986,17 @@ msgstr "To jest najnowsza wersja."
msgid "Info"
msgstr "Informacja"
msgid "Loading Plugins"
msgstr ""
#, c-format, boost-format
msgid "Plugin %s is no longer available."
msgstr ""
#, c-format, boost-format
msgid "Plugin %s access is unauthorized."
msgstr ""
msgid "Loading printer & filament profiles"
msgstr ""
@@ -2103,6 +2114,18 @@ msgstr ""
msgid "Resolve cloud sync conflict"
msgstr ""
msgid "Syncing your account…"
msgstr ""
msgid "Migrating presets…"
msgstr ""
msgid "Fetching plugins…"
msgstr ""
msgid "Loading user presets…"
msgstr ""
msgid "Retrieving printer information, please try again later."
msgstr "Pobieranie informacji o drukarce, spróbuj ponownie później."
@@ -2221,6 +2244,21 @@ msgstr ""
msgid "*"
msgstr "*"
msgid "Plugins"
msgstr ""
#, c-format, boost-format
msgid ""
"Failed to open the Plugins dialog:\n"
"%s"
msgstr ""
msgid "Failed to open the Plugins dialog (unknown error)."
msgstr ""
msgid "Plugin Terminal"
msgstr ""
msgid "Changing application language"
msgstr "Zmiana języka aplikacji"
@@ -5045,6 +5083,28 @@ msgstr "Nieprawidłowy format. Oczekiwano formatu wektorowego: „%1%”"
msgid "N/A"
msgstr ""
msgid "System agents"
msgstr ""
msgid "No plugin selected"
msgstr ""
msgid "Add plugin"
msgstr ""
msgid "Select plugin"
msgstr ""
msgid "Remove plugin"
msgstr ""
msgid "Configure"
msgstr ""
#, c-format, boost-format
msgid "Configure (%d)"
msgstr ""
msgid "Pick"
msgstr ""
@@ -5210,9 +5270,6 @@ msgstr "Natężenie przepływu"
msgid "Fan speed"
msgstr "Prędkość wentylatora"
msgid "°C"
msgstr "°C"
msgid "Time"
msgstr "Czas"
@@ -7254,6 +7311,14 @@ msgctxt "Layers"
msgid "Bottom"
msgstr "Dół"
msgid "Plugin Selection"
msgstr ""
msgid ""
"No plugins capabilities available for this type.\n"
"Enable or install some to use."
msgstr ""
msgid "Enable detection of build plate position"
msgstr "Włącz wykrywanie położenia płyty roboczej"
@@ -8156,6 +8221,40 @@ msgstr "Strona Urządzenia"
msgid "Synchronize AMS Filament Information"
msgstr "Synchronizuj informacje o filamentach w AMS"
msgid "OrcaCloud plugins required by the current preset are not installed:"
msgstr ""
msgid "Install Plugins"
msgstr ""
msgid "Local plugins required by the current preset are missing:"
msgstr ""
msgid "Find on OrcaCloud"
msgstr ""
msgid "Plugins required by the current preset are not activated:"
msgstr ""
msgid "Activate Now"
msgstr ""
msgid "The installed plugin does not provide the required capability — it may be outdated:"
msgstr ""
msgid "Preparing to install plugins..."
msgstr ""
msgid "Installing plugins"
msgstr ""
msgid "Cancelling — finishing the current plugin..."
msgstr ""
#, boost-format
msgid "Installing %1%..."
msgstr ""
msgid "Plate Settings"
msgstr "Ustawienia stołu"
@@ -9204,6 +9303,9 @@ msgstr "Druk wielokolorowy za pomocą zewnętrznej szpuli"
msgid "Your filament grouping method in the sliced file is not optimal."
msgstr "Twoja metoda grupowania filamentów w pliku cięcia nie jest optymalna."
msgid "To ensure print quality, the drying temperature will be lowered during printing."
msgstr ""
msgid "Auto Bed Leveling"
msgstr "Automatyczne poziomowanie stołu"
@@ -9932,6 +10034,12 @@ msgstr "G-code zmieniający tryb ekstruzji"
msgid "Post-processing Scripts"
msgstr "Skrypty post-processingu"
msgid "Slicing Pipeline Plugin"
msgstr ""
msgid "Plugin Configuration"
msgstr ""
msgid "Notes"
msgstr "Notatki"
@@ -11066,6 +11174,9 @@ msgstr ""
msgid "Switch between Prepare/Preview"
msgstr "Przełączanie między przygotowaniem/podglądem"
msgid "Open actions speed dial"
msgstr ""
msgid "Plater"
msgstr "Płyta"
@@ -11921,6 +12032,9 @@ msgstr "Klucz API"
msgid "HTTP digest"
msgstr ""
msgid "Configuration for the plugin capabilities this preset uses, overriding the global Capabilities configuration. Stored as a raw JSON array and edited through the dialog behind the button, never typed in directly."
msgstr ""
msgid "Avoid crossing walls"
msgstr "Unikanie ruchów nad obrysami"
@@ -12875,6 +12989,24 @@ msgid ""
"WARNING: Lowering this value may negatively affect bed adhesion."
msgstr ""
msgid "Top surface fill order"
msgstr ""
msgid ""
"Direction in which top surfaces are filled when using a center-based pattern (Concentric, Archimedean Chords, Octagram Spiral).\n"
"Outward starts at the center of the surface, so any excess material is pushed towards the edge where it is least visible. Inward starts at the edge and ends with the tight curves at the center.\n"
"Default uses shortest-path ordering, which may run in either direction."
msgstr ""
msgid "Bottom surface fill order"
msgstr ""
msgid ""
"Direction in which bottom surfaces are filled when using a center-based pattern (Concentric, Archimedean Chords, Octagram Spiral).\n"
"Inward starts each surface with the wider outer curves, which improves first layer adhesion on build plates where the tight curves at the center may not stick. Outward starts at the center, pushing any excess material towards the edge.\n"
"Default uses shortest-path ordering, which may run in either direction."
msgstr ""
msgid "Internal solid infill pattern"
msgstr "Wzór wewnętrznego pełnego wypełnienia"
@@ -14086,9 +14218,6 @@ msgid ""
"Set to 0 to deactivate."
msgstr ""
msgid "%"
msgstr "%"
msgid "Time cost"
msgstr "Koszt czasu"
@@ -14776,6 +14905,9 @@ msgid ""
"RRF: X and Y values are equal."
msgstr ""
msgid "Hz"
msgstr "Hz"
msgid "Y"
msgstr "Y"
@@ -15052,6 +15184,15 @@ msgstr ""
msgid "This G-code is inserted when the extrusion role is changed. It runs after the machine and filament extrusion role G-code."
msgstr ""
msgid "Plugins Used"
msgstr ""
msgid "Plugin capabilities referenced by this preset, stored as name;uuid;capability."
msgstr ""
msgid "Python plugin(s) invoked at each slicing pipeline step to read and modify intermediate slicing data, including a final G-code post-processing step. Research/experimental."
msgstr ""
msgid "Printer type"
msgstr "Typ drukarki"
@@ -15120,6 +15261,15 @@ msgstr "Długość retrakcji przed wytarciem dyszy"
msgid "This is the length of fast retraction before a wipe, relative to retraction length."
msgstr "Długość szybkiej retrakcji przed wytarciem dyszy, w stosunku do długości retrakcji."
msgid "Retract amount after wipe"
msgstr ""
#, c-format
msgid ""
"The length of fast retraction after wipe, relative to retraction length.\n"
"The value will be clamped by 100% minus the retract amount before the wipe value."
msgstr ""
# TODO: Review, changed by lang refactor. PR 14254
msgid "Retract on layer change"
msgstr "Retrakcja przy zmianie warstwy"
@@ -16124,16 +16274,6 @@ msgstr "Grubość górnej powłoki"
msgid "The number of top solid layers is increased when slicing if the thickness calculated by top shell layers is thinner than this value. This can avoid having too thin a shell when layer height is small. 0 means that this setting is disabled and thickness of top shell is determined simply by the number of top shell layers."
msgstr "Liczba górnych zwartych warstw jest zwiększana podczas cięcia, jeśli grubość obliczona przez górną warstwe powłoki jest cieńsza niż ta wartość. Można w ten sposób uniknąć zbyt cienkiej powłoki, gdy wysokość warstwy jest mała. 0 oznacza, że to ustawienie jest wyłączone, a grubość górnej powłoki jest absolutnie określona przez górne warstwy powłoki"
msgid "Anisotropic surfaces"
msgstr ""
msgid ""
"Anisotropic patterns on the top and bottom surfaces.\n"
"Co-directional printing mode will be applied. For certain patterns, omni-directional filling provides color dispersion when using multi-colored or silk plastics.\n"
"This option disable the gap fill.\n"
"This option can increase a printing time."
msgstr ""
msgid "Separated infills"
msgstr ""
@@ -17953,9 +18093,6 @@ msgstr ""
msgid "Frequency settings"
msgstr ""
msgid "Hz"
msgstr "Hz"
msgid "RepRap firmware uses the same frequency range for both axes."
msgstr ""
@@ -19931,6 +20068,145 @@ msgstr ""
msgid "Open File"
msgstr ""
msgid "AMS Dryness Control"
msgstr ""
msgid "Filament Drying Settings"
msgstr ""
msgid "Stopping"
msgstr ""
msgid "Unable to dry temporarily due to ..."
msgstr ""
msgid "Drying Error"
msgstr ""
msgid "Please check the Assistant for troubleshooting"
msgstr ""
msgid "Please remove and store the filament (as shown)."
msgstr ""
msgid "The AMS can rotate the filament which is properly stored, providing better drying results."
msgstr ""
msgid "Rotate spool when drying"
msgstr ""
msgctxt "amsdrying"
msgid "Back"
msgstr ""
msgid "Drying-Heating"
msgstr ""
msgid "Drying-Dehumidifying"
msgstr ""
msgid " maximum drying temperature is "
msgstr ""
msgid " minimum drying temperature is "
msgstr ""
msgid "This filament may not be completely dried."
msgstr ""
msgid "This AMS is currently printing. To ensure print quality, the drying temperature cannot exceed the recommended drying temperature."
msgstr ""
msgid "The temperature shall not exceed the filament's heat distortion temperature"
msgstr ""
msgid "Minimum time value cannot be less than 1."
msgstr ""
msgid "Maximum time value cannot be greater than 24."
msgstr ""
msgid "Insufficient power"
msgstr ""
msgid " Too many AMS drying simultaneously. Please plug in the power or stop other drying processes before starting."
msgstr ""
msgid "AMS is busy"
msgstr ""
msgid " AMS is calibrating | reading RFID | loading/unloading material, please wait."
msgstr ""
msgid "Filament in AMS outlet"
msgstr ""
msgid " The high drying temperature may cause AMS blockage, please unload first."
msgstr ""
msgid "Initiating AMS drying"
msgstr ""
msgid "Not supported in 2D mode"
msgstr ""
msgid "Task in progress"
msgstr ""
msgid " The AMS might be in use during Task."
msgstr ""
msgid " Firmware update in progress, please wait..."
msgstr ""
msgid " Please plug in the power and then use the drying function."
msgstr ""
msgid " The high drying temperature may cause AMS blockage. Please unload the filament manually before proceeding."
msgstr ""
msgid "System is busy"
msgstr ""
msgid " Initiating other drying processes, please wait a few seconds..."
msgstr ""
msgid "For better drying results, remove the filament and allow it to rotate."
msgstr ""
msgid "The AMS will automatically rotate the stored filament slots to enhance the drying performance."
msgstr ""
msgid "Alternatively, you can dry the filament without removing it."
msgstr ""
msgid "Unknown filaments will be treated as PLA."
msgstr ""
msgid "Please store the filament marked with an exclamation mark."
msgstr ""
msgid "Filament left in the feeder during drying may soften because the drying temperature exceeds the softening point of materials like PLA and TPU."
msgstr ""
msgid "Starting: Checking adapter connection"
msgstr ""
msgid "Starting: Checking filament status"
msgstr ""
msgid "Starting: Checking drying presets"
msgstr ""
msgid "Starting: Checking filament location"
msgstr ""
msgid "Starting: Checking air intake"
msgstr ""
msgid "Starting: Checking air vent"
msgstr ""
msgid "The filament may not be compatible with the current machine settings. Generic filament presets will be used."
msgstr "Filament może być niekompatybilny z obecnymi ustawieniami maszyny. Domyślny profil filamentu zostanie użyty."
@@ -20253,6 +20529,12 @@ msgstr ""
"Unikaj odkształceń\n"
"Czy wiesz, że podczas drukowania filamentami podatnymi na odkształcenia, takimi jak ABS, odpowiednie zwiększenie temperatury podgrzewanej płyty może zmniejszyć prawdopodobieństwo odkształceń?"
#~ msgid "°C"
#~ msgstr "°C"
#~ msgid "%"
#~ msgstr "%"
#~ msgid "Continue to sync filaments"
#~ msgstr "Kontynuuj aby zsynchronizować filamenty"

View File

@@ -3,7 +3,7 @@ msgid ""
msgstr ""
"Project-Id-Version: Orca Slicer\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-07-13 16:24-0300\n"
"POT-Creation-Date: 2026-07-17 15:13-0300\n"
"PO-Revision-Date: 2026-07-04 11:51-0300\n"
"Last-Translator: Alexandre Folle de Menezes\n"
"Language-Team: Portuguese, Brazilian\n"
@@ -1969,6 +1969,17 @@ msgstr "Esta é a versão mais recente."
msgid "Info"
msgstr "Informações"
msgid "Loading Plugins"
msgstr ""
#, c-format, boost-format
msgid "Plugin %s is no longer available."
msgstr ""
#, c-format, boost-format
msgid "Plugin %s access is unauthorized."
msgstr ""
msgid "Loading printer & filament profiles"
msgstr "Carregando perfis de impressora e filamento"
@@ -2087,6 +2098,18 @@ msgstr ""
msgid "Resolve cloud sync conflict"
msgstr "Resolver o conflito de sincronização de nuvem"
msgid "Syncing your account…"
msgstr ""
msgid "Migrating presets…"
msgstr ""
msgid "Fetching plugins…"
msgstr ""
msgid "Loading user presets…"
msgstr ""
msgid "Retrieving printer information, please try again later."
msgstr "Obtendo informações da impressora, tente novamente mais tarde."
@@ -2216,6 +2239,21 @@ msgstr ""
msgid "*"
msgstr "*"
msgid "Plugins"
msgstr ""
#, c-format, boost-format
msgid ""
"Failed to open the Plugins dialog:\n"
"%s"
msgstr ""
msgid "Failed to open the Plugins dialog (unknown error)."
msgstr ""
msgid "Plugin Terminal"
msgstr ""
msgid "Changing application language"
msgstr "Alterando o idioma do aplicativo"
@@ -4968,6 +5006,28 @@ msgstr "Formato inválido. Formato de vetor esperado: \"%1%\""
msgid "N/A"
msgstr "N/D"
msgid "System agents"
msgstr ""
msgid "No plugin selected"
msgstr ""
msgid "Add plugin"
msgstr ""
msgid "Select plugin"
msgstr ""
msgid "Remove plugin"
msgstr ""
msgid "Configure"
msgstr ""
#, c-format, boost-format
msgid "Configure (%d)"
msgstr ""
msgid "Pick"
msgstr "Escolher"
@@ -5133,9 +5193,6 @@ msgstr "Taxa de fluxo"
msgid "Fan speed"
msgstr "Velocidade do ventilador"
msgid "°C"
msgstr "℃"
msgid "Time"
msgstr "Tempo"
@@ -7152,6 +7209,14 @@ msgctxt "Layers"
msgid "Bottom"
msgstr "Inferior"
msgid "Plugin Selection"
msgstr ""
msgid ""
"No plugins capabilities available for this type.\n"
"Enable or install some to use."
msgstr ""
msgid "Enable detection of build plate position"
msgstr "Ativar detecção da posição da placa de impressão"
@@ -8049,6 +8114,40 @@ msgstr "Página do Dispositivo"
msgid "Synchronize AMS Filament Information"
msgstr "Sincronizar informações de filamento AMS"
msgid "OrcaCloud plugins required by the current preset are not installed:"
msgstr ""
msgid "Install Plugins"
msgstr ""
msgid "Local plugins required by the current preset are missing:"
msgstr ""
msgid "Find on OrcaCloud"
msgstr ""
msgid "Plugins required by the current preset are not activated:"
msgstr ""
msgid "Activate Now"
msgstr ""
msgid "The installed plugin does not provide the required capability — it may be outdated:"
msgstr ""
msgid "Preparing to install plugins..."
msgstr ""
msgid "Installing plugins"
msgstr ""
msgid "Cancelling — finishing the current plugin..."
msgstr ""
#, boost-format
msgid "Installing %1%..."
msgstr ""
msgid "Plate Settings"
msgstr "Configurações de Placa"
@@ -9118,6 +9217,9 @@ msgstr "Multicor com externo"
msgid "Your filament grouping method in the sliced file is not optimal."
msgstr "Seu método de agrupamento de filamentos no arquivo fatiado não é o ideal."
msgid "To ensure print quality, the drying temperature will be lowered during printing."
msgstr ""
msgid "Auto Bed Leveling"
msgstr "Nivelamento Automático da Mesa"
@@ -9842,6 +9944,12 @@ msgstr "G-code de mudança de tipo de extrusão"
msgid "Post-processing Scripts"
msgstr "Scripts de pós-processamento"
msgid "Slicing Pipeline Plugin"
msgstr ""
msgid "Plugin Configuration"
msgstr ""
msgid "Notes"
msgstr "Notas"
@@ -10979,6 +11087,9 @@ msgstr "Alternar modo de impressão para objeto/peça"
msgid "Switch between Prepare/Preview"
msgstr "Alternar entre Preparar/Pré-visualizar"
msgid "Open actions speed dial"
msgstr ""
msgid "Plater"
msgstr "Mesa"
@@ -11827,6 +11938,9 @@ msgstr "API Key"
msgid "HTTP digest"
msgstr "Digest HTTP"
msgid "Configuration for the plugin capabilities this preset uses, overriding the global Capabilities configuration. Stored as a raw JSON array and edited through the dialog behind the button, never typed in directly."
msgstr ""
msgid "Avoid crossing walls"
msgstr "Evitar atravessar paredes"
@@ -12802,6 +12916,24 @@ msgid ""
"WARNING: Lowering this value may negatively affect bed adhesion."
msgstr ""
msgid "Top surface fill order"
msgstr ""
msgid ""
"Direction in which top surfaces are filled when using a center-based pattern (Concentric, Archimedean Chords, Octagram Spiral).\n"
"Outward starts at the center of the surface, so any excess material is pushed towards the edge where it is least visible. Inward starts at the edge and ends with the tight curves at the center.\n"
"Default uses shortest-path ordering, which may run in either direction."
msgstr ""
msgid "Bottom surface fill order"
msgstr ""
msgid ""
"Direction in which bottom surfaces are filled when using a center-based pattern (Concentric, Archimedean Chords, Octagram Spiral).\n"
"Inward starts each surface with the wider outer curves, which improves first layer adhesion on build plates where the tight curves at the center may not stick. Outward starts at the center, pushing any excess material towards the edge.\n"
"Default uses shortest-path ordering, which may run in either direction."
msgstr ""
msgid "Internal solid infill pattern"
msgstr "Padrão de preenchimento sólido interno"
@@ -14041,9 +14173,6 @@ msgstr ""
"Se o seu firmware já desativa a ventoinha abaixo de um limite (por exemplo, [fan] off_below: 0.10 do Klipper desliga a ventoinha sempre que o ciclo de trabalho comandado for inferior a 10%), esta opção e o limite do firmware devem idealmente ser definidos com o mesmo valor. A correspondência entre eles (por exemplo, off_below: 0.10 no Klipper e 10% aqui) garante que o fatiador nunca emita um valor diferente de zero que o firmware emitiria a velocidade cai silenciosamente e a ventoinha nunca recebe um valor abaixo daquele que você sabe que ela pode realmente atingir.\n"
"Defina como 0 para desativar."
msgid "%"
msgstr "%"
msgid "Time cost"
msgstr "Custo de tempo"
@@ -14745,6 +14874,9 @@ msgstr ""
"Para desativar o modelador de entrada, use o tipo Desativar.\n"
"RRF: Os valores de X e Y são iguais."
msgid "Hz"
msgstr "Hz"
msgid "Y"
msgstr "Y"
@@ -15035,6 +15167,15 @@ msgstr "G-code de mudança de tipo de extrusão (processo)"
msgid "This G-code is inserted when the extrusion role is changed. It runs after the machine and filament extrusion role G-code."
msgstr "Este G-code é inserido quando a função de extrusão é trocada. Ele é executado após o G-code de máquina e do tipo de extrusão de filamento."
msgid "Plugins Used"
msgstr ""
msgid "Plugin capabilities referenced by this preset, stored as name;uuid;capability."
msgstr ""
msgid "Python plugin(s) invoked at each slicing pipeline step to read and modify intermediate slicing data, including a final G-code post-processing step. Research/experimental."
msgstr ""
msgid "Printer type"
msgstr "Tipo de impressora"
@@ -15103,6 +15244,15 @@ msgstr "Quantidade de retração antes da limpeza"
msgid "This is the length of fast retraction before a wipe, relative to retraction length."
msgstr "O comprimento da retração rápida antes da limpeza, em relação ao comprimento da retração."
msgid "Retract amount after wipe"
msgstr ""
#, c-format
msgid ""
"The length of fast retraction after wipe, relative to retraction length.\n"
"The value will be clamped by 100% minus the retract amount before the wipe value."
msgstr ""
# TODO: Review, changed by lang refactor. PR 14254
msgid "Retract on layer change"
msgstr "Retrair ao mudar de camada"
@@ -16098,16 +16248,6 @@ msgstr "Espessura da casca do topo"
msgid "The number of top solid layers is increased when slicing if the thickness calculated by top shell layers is thinner than this value. This can avoid having too thin a shell when layer height is small. 0 means that this setting is disabled and thickness of top shell is determined simply by the number of top shell layers."
msgstr "O número de camadas sólidas superiores é aumentado ao fatiar se a espessura calculada pelas camadas da casca do topo for menor do que este valor. Isso pode evitar que a casca seja muito fina quando a altura da camada é pequena. 0 significa que esta configuração está desativada e a espessura da casca do topo é determinada apenas pelo número de camadas da casca do topo."
msgid "Anisotropic surfaces"
msgstr ""
msgid ""
"Anisotropic patterns on the top and bottom surfaces.\n"
"Co-directional printing mode will be applied. For certain patterns, omni-directional filling provides color dispersion when using multi-colored or silk plastics.\n"
"This option disable the gap fill.\n"
"This option can increase a printing time."
msgstr ""
msgid "Separated infills"
msgstr ""
@@ -17907,9 +18047,6 @@ msgstr "Inicial / Final"
msgid "Frequency settings"
msgstr "Configurações de frequência"
msgid "Hz"
msgstr "Hz"
msgid "RepRap firmware uses the same frequency range for both axes."
msgstr "O firmware RepRap usa a mesma faixa de frequência para ambos os eixos."
@@ -19884,6 +20021,145 @@ msgstr "Arquivar pré-visualização"
msgid "Open File"
msgstr "Abrir Arquivo"
msgid "AMS Dryness Control"
msgstr ""
msgid "Filament Drying Settings"
msgstr ""
msgid "Stopping"
msgstr ""
msgid "Unable to dry temporarily due to ..."
msgstr ""
msgid "Drying Error"
msgstr ""
msgid "Please check the Assistant for troubleshooting"
msgstr ""
msgid "Please remove and store the filament (as shown)."
msgstr ""
msgid "The AMS can rotate the filament which is properly stored, providing better drying results."
msgstr ""
msgid "Rotate spool when drying"
msgstr ""
msgctxt "amsdrying"
msgid "Back"
msgstr ""
msgid "Drying-Heating"
msgstr ""
msgid "Drying-Dehumidifying"
msgstr ""
msgid " maximum drying temperature is "
msgstr ""
msgid " minimum drying temperature is "
msgstr ""
msgid "This filament may not be completely dried."
msgstr ""
msgid "This AMS is currently printing. To ensure print quality, the drying temperature cannot exceed the recommended drying temperature."
msgstr ""
msgid "The temperature shall not exceed the filament's heat distortion temperature"
msgstr ""
msgid "Minimum time value cannot be less than 1."
msgstr ""
msgid "Maximum time value cannot be greater than 24."
msgstr ""
msgid "Insufficient power"
msgstr ""
msgid " Too many AMS drying simultaneously. Please plug in the power or stop other drying processes before starting."
msgstr ""
msgid "AMS is busy"
msgstr ""
msgid " AMS is calibrating | reading RFID | loading/unloading material, please wait."
msgstr ""
msgid "Filament in AMS outlet"
msgstr ""
msgid " The high drying temperature may cause AMS blockage, please unload first."
msgstr ""
msgid "Initiating AMS drying"
msgstr ""
msgid "Not supported in 2D mode"
msgstr ""
msgid "Task in progress"
msgstr ""
msgid " The AMS might be in use during Task."
msgstr ""
msgid " Firmware update in progress, please wait..."
msgstr ""
msgid " Please plug in the power and then use the drying function."
msgstr ""
msgid " The high drying temperature may cause AMS blockage. Please unload the filament manually before proceeding."
msgstr ""
msgid "System is busy"
msgstr ""
msgid " Initiating other drying processes, please wait a few seconds..."
msgstr ""
msgid "For better drying results, remove the filament and allow it to rotate."
msgstr ""
msgid "The AMS will automatically rotate the stored filament slots to enhance the drying performance."
msgstr ""
msgid "Alternatively, you can dry the filament without removing it."
msgstr ""
msgid "Unknown filaments will be treated as PLA."
msgstr ""
msgid "Please store the filament marked with an exclamation mark."
msgstr ""
msgid "Filament left in the feeder during drying may soften because the drying temperature exceeds the softening point of materials like PLA and TPU."
msgstr ""
msgid "Starting: Checking adapter connection"
msgstr ""
msgid "Starting: Checking filament status"
msgstr ""
msgid "Starting: Checking drying presets"
msgstr ""
msgid "Starting: Checking filament location"
msgstr ""
msgid "Starting: Checking air intake"
msgstr ""
msgid "Starting: Checking air vent"
msgstr ""
msgid "The filament may not be compatible with the current machine settings. Generic filament presets will be used."
msgstr "O filamento pode não ser compatível com as configurações atuais da máquina. Serão usadas predefinições genéricas de filamento."
@@ -20199,6 +20475,12 @@ msgstr ""
"Evitar empenamento\n"
"Você sabia que ao imprimir materiais propensos ao empenamento como ABS, aumentar adequadamente a temperatura da mesa aquecida pode reduzir a probabilidade de empenamento?"
#~ msgid "°C"
#~ msgstr "℃"
#~ msgid "%"
#~ msgstr "%"
#~ msgid "Renders cast shadows on the plate in realistic view."
#~ msgstr "Renderiza sombras na placa em uma visualização realista."

View File

@@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: OrcaSlicer V2.5.0\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-07-13 16:24-0300\n"
"POT-Creation-Date: 2026-07-17 15:13-0300\n"
"PO-Revision-Date: 2026-02-25 13:38+0300\n"
"Last-Translator: Felix14_v2\n"
"Language-Team: Felix14_v2 (ДС/ТГ: @felix14_v2, почта: aleks111001@list.ru), Andylg <andylg@yandex.ru>\n"
@@ -2030,6 +2030,17 @@ msgstr "Установлена последняя версия программ
msgid "Info"
msgstr "Информация"
msgid "Loading Plugins"
msgstr ""
#, c-format, boost-format
msgid "Plugin %s is no longer available."
msgstr ""
#, c-format, boost-format
msgid "Plugin %s access is unauthorized."
msgstr ""
msgid "Loading printer & filament profiles"
msgstr "Загрузка профилей принтеров и материалов"
@@ -2163,6 +2174,18 @@ msgstr ""
msgid "Resolve cloud sync conflict"
msgstr "Решение проблем синхронизации"
msgid "Syncing your account…"
msgstr ""
msgid "Migrating presets…"
msgstr ""
msgid "Fetching plugins…"
msgstr ""
msgid "Loading user presets…"
msgstr ""
msgid "Retrieving printer information, please try again later."
msgstr "Получение информации о принтере, попробуйте позднее."
@@ -2294,6 +2317,21 @@ msgstr ""
msgid "*"
msgstr "*"
msgid "Plugins"
msgstr ""
#, c-format, boost-format
msgid ""
"Failed to open the Plugins dialog:\n"
"%s"
msgstr ""
msgid "Failed to open the Plugins dialog (unknown error)."
msgstr ""
msgid "Plugin Terminal"
msgstr ""
msgid "Changing application language"
msgstr "Изменение языка приложения"
@@ -5101,6 +5139,28 @@ msgstr "Недопустимый формат. Ожидаемый векторн
msgid "N/A"
msgstr ""
msgid "System agents"
msgstr ""
msgid "No plugin selected"
msgstr ""
msgid "Add plugin"
msgstr ""
msgid "Select plugin"
msgstr ""
msgid "Remove plugin"
msgstr ""
msgid "Configure"
msgstr ""
#, c-format, boost-format
msgid "Configure (%d)"
msgstr ""
msgid "Pick"
msgstr "Выбрать"
@@ -5279,9 +5339,6 @@ msgstr "Расход"
msgid "Fan speed"
msgstr "Обдув"
msgid "°C"
msgstr "°C"
msgid "Time"
msgstr "Время"
@@ -7360,6 +7417,14 @@ msgctxt "Layers"
msgid "Bottom"
msgstr "Снизу"
msgid "Plugin Selection"
msgstr ""
msgid ""
"No plugins capabilities available for this type.\n"
"Enable or install some to use."
msgstr ""
msgid "Enable detection of build plate position"
msgstr "Определение положения покрытия"
@@ -8266,6 +8331,40 @@ msgstr "«Принтер»"
msgid "Synchronize AMS Filament Information"
msgstr "Синхронизировать материалы в AMS"
msgid "OrcaCloud plugins required by the current preset are not installed:"
msgstr ""
msgid "Install Plugins"
msgstr ""
msgid "Local plugins required by the current preset are missing:"
msgstr ""
msgid "Find on OrcaCloud"
msgstr ""
msgid "Plugins required by the current preset are not activated:"
msgstr ""
msgid "Activate Now"
msgstr ""
msgid "The installed plugin does not provide the required capability — it may be outdated:"
msgstr ""
msgid "Preparing to install plugins..."
msgstr ""
msgid "Installing plugins"
msgstr ""
msgid "Cancelling — finishing the current plugin..."
msgstr ""
#, boost-format
msgid "Installing %1%..."
msgstr ""
msgid "Plate Settings"
msgstr "Настройки стола"
@@ -9365,6 +9464,9 @@ msgstr "Многоцветная печать с внешней катушкой
msgid "Your filament grouping method in the sliced file is not optimal."
msgstr "Группировка материалов в файле печати не оптимальна."
msgid "To ensure print quality, the drying temperature will be lowered during printing."
msgstr ""
msgid "Auto Bed Leveling"
msgstr "Автоматическое выравнивание стола"
@@ -10101,6 +10203,12 @@ msgstr "G-код при смене типа линии"
msgid "Post-processing Scripts"
msgstr "Скрипты постобработки"
msgid "Slicing Pipeline Plugin"
msgstr ""
msgid "Plugin Configuration"
msgstr ""
msgid "Notes"
msgstr "Заметки"
@@ -11273,6 +11381,9 @@ msgstr "Переключить печать модели"
msgid "Switch between Prepare/Preview"
msgstr "Переключение между подготовкой и просмотром нарезки"
msgid "Open actions speed dial"
msgstr ""
# Plater это название библиотеки. Используется в меню горячих клавиш в качестве заголовка сочетаний клавиш, которые работают внутри пространства Plater. Как минимум на Windows не отображается.
msgid "Plater"
msgstr ""
@@ -12112,6 +12223,9 @@ msgstr "API-ключ"
msgid "HTTP digest"
msgstr "HTTP digest-авторизация"
msgid "Configuration for the plugin capabilities this preset uses, overriding the global Capabilities configuration. Stored as a raw JSON array and edited through the dialog behind the button, never typed in directly."
msgstr ""
# Логическая ошибка; пересекаются не периметры, а траектория холостого
# перемещения со стенкой модели
msgid "Avoid crossing walls"
@@ -13186,6 +13300,24 @@ msgstr ""
"Плотность нижней поверхности. Эта функция предназначена для улучшения внешнего вида или функциональности объекта, а не для решения проблем, таких как чрезмерная экструзия.\n"
"Внимание: уменьшение этого значения может негативно повлиять на адгезию к печатной платформе."
msgid "Top surface fill order"
msgstr ""
msgid ""
"Direction in which top surfaces are filled when using a center-based pattern (Concentric, Archimedean Chords, Octagram Spiral).\n"
"Outward starts at the center of the surface, so any excess material is pushed towards the edge where it is least visible. Inward starts at the edge and ends with the tight curves at the center.\n"
"Default uses shortest-path ordering, which may run in either direction."
msgstr ""
msgid "Bottom surface fill order"
msgstr ""
msgid ""
"Direction in which bottom surfaces are filled when using a center-based pattern (Concentric, Archimedean Chords, Octagram Spiral).\n"
"Inward starts each surface with the wider outer curves, which improves first layer adhesion on build plates where the tight curves at the center may not stick. Outward starts at the center, pushing any excess material towards the edge.\n"
"Default uses shortest-path ordering, which may run in either direction."
msgstr ""
msgid "Internal solid infill pattern"
msgstr "Шаблон сплошного заполнения"
@@ -14583,9 +14715,6 @@ msgstr ""
"\n"
"Примечание: ограничение запуска в некоторых прошивках (например, [fan] off_below в Klipper) может автоматически занулять слишком низкие значения. В таком случае рекомендуется указать минимальный процент, который не сбрасывается прошивкой."
msgid "%"
msgstr "%"
msgid "Time cost"
msgstr "Стоимость часа печати"
@@ -15323,6 +15452,9 @@ msgstr ""
"\n"
"Примечание: прошивка RepRap не поддерживает раздельную настройку осей."
msgid "Hz"
msgstr "Гц"
msgid "Y"
msgstr "Y"
@@ -15628,6 +15760,15 @@ msgstr "G-код при смене типа линии (настройки пе
msgid "This G-code is inserted when the extrusion role is changed. It runs after the machine and filament extrusion role G-code."
msgstr "Команды в G-коде, которые выполняются между печатью разных элементов структуры (например, при переходе от периметра к заполнению). Выполняются после команд смены типа линии из настроек принтера и материала."
msgid "Plugins Used"
msgstr ""
msgid "Plugin capabilities referenced by this preset, stored as name;uuid;capability."
msgstr ""
msgid "Python plugin(s) invoked at each slicing pipeline step to read and modify intermediate slicing data, including a final G-code post-processing step. Research/experimental."
msgstr ""
msgid "Printer type"
msgstr "Тип принтера"
@@ -15695,6 +15836,15 @@ msgstr ""
"\n"
"Примечание: значение не может быть меньше 25% или больше 100% и будет скорректировано автоматически при нарезке."
msgid "Retract amount after wipe"
msgstr ""
#, c-format
msgid ""
"The length of fast retraction after wipe, relative to retraction length.\n"
"The value will be clamped by 100% minus the retract amount before the wipe value."
msgstr ""
msgid "Retract on layer change"
msgstr "Откат при смене слоя"
@@ -16838,16 +16988,6 @@ msgstr "Толщина оболочки сверху"
msgid "The number of top solid layers is increased when slicing if the thickness calculated by top shell layers is thinner than this value. This can avoid having too thin a shell when layer height is small. 0 means that this setting is disabled and thickness of top shell is determined simply by the number of top shell layers."
msgstr "Минимальная толщина оболочки сверху в мм. Если толщина оболочки, рассчитанная по количеству сплошных слоёв сверху, меньше этого значения, количество сплошных слоёв сверху будет автоматически увеличено при нарезке, для удовлетворения минимальной толщины оболочки. Это позволяет избежать слишком тонкой оболочки при небольшой высоте слоя. 0 означает, что этот параметр отключён, а толщина оболочки сверху задаётся количеством сплошных слоёв сверху."
msgid "Anisotropic surfaces"
msgstr ""
msgid ""
"Anisotropic patterns on the top and bottom surfaces.\n"
"Co-directional printing mode will be applied. For certain patterns, omni-directional filling provides color dispersion when using multi-colored or silk plastics.\n"
"This option disable the gap fill.\n"
"This option can increase a printing time."
msgstr ""
msgid "Separated infills"
msgstr ""
@@ -18767,9 +18907,6 @@ msgstr "(начало/конец)"
msgid "Frequency settings"
msgstr "Настройка частоты"
msgid "Hz"
msgstr "Гц"
msgid "RepRap firmware uses the same frequency range for both axes."
msgstr "Прошивка RepRap использует общий диапазон частот для обеих осей."
@@ -20798,6 +20935,145 @@ msgstr "Просмотр архива"
msgid "Open File"
msgstr "Открыть файл"
msgid "AMS Dryness Control"
msgstr ""
msgid "Filament Drying Settings"
msgstr ""
msgid "Stopping"
msgstr ""
msgid "Unable to dry temporarily due to ..."
msgstr ""
msgid "Drying Error"
msgstr ""
msgid "Please check the Assistant for troubleshooting"
msgstr ""
msgid "Please remove and store the filament (as shown)."
msgstr ""
msgid "The AMS can rotate the filament which is properly stored, providing better drying results."
msgstr ""
msgid "Rotate spool when drying"
msgstr ""
msgctxt "amsdrying"
msgid "Back"
msgstr ""
msgid "Drying-Heating"
msgstr ""
msgid "Drying-Dehumidifying"
msgstr ""
msgid " maximum drying temperature is "
msgstr ""
msgid " minimum drying temperature is "
msgstr ""
msgid "This filament may not be completely dried."
msgstr ""
msgid "This AMS is currently printing. To ensure print quality, the drying temperature cannot exceed the recommended drying temperature."
msgstr ""
msgid "The temperature shall not exceed the filament's heat distortion temperature"
msgstr ""
msgid "Minimum time value cannot be less than 1."
msgstr ""
msgid "Maximum time value cannot be greater than 24."
msgstr ""
msgid "Insufficient power"
msgstr ""
msgid " Too many AMS drying simultaneously. Please plug in the power or stop other drying processes before starting."
msgstr ""
msgid "AMS is busy"
msgstr ""
msgid " AMS is calibrating | reading RFID | loading/unloading material, please wait."
msgstr ""
msgid "Filament in AMS outlet"
msgstr ""
msgid " The high drying temperature may cause AMS blockage, please unload first."
msgstr ""
msgid "Initiating AMS drying"
msgstr ""
msgid "Not supported in 2D mode"
msgstr ""
msgid "Task in progress"
msgstr ""
msgid " The AMS might be in use during Task."
msgstr ""
msgid " Firmware update in progress, please wait..."
msgstr ""
msgid " Please plug in the power and then use the drying function."
msgstr ""
msgid " The high drying temperature may cause AMS blockage. Please unload the filament manually before proceeding."
msgstr ""
msgid "System is busy"
msgstr ""
msgid " Initiating other drying processes, please wait a few seconds..."
msgstr ""
msgid "For better drying results, remove the filament and allow it to rotate."
msgstr ""
msgid "The AMS will automatically rotate the stored filament slots to enhance the drying performance."
msgstr ""
msgid "Alternatively, you can dry the filament without removing it."
msgstr ""
msgid "Unknown filaments will be treated as PLA."
msgstr ""
msgid "Please store the filament marked with an exclamation mark."
msgstr ""
msgid "Filament left in the feeder during drying may soften because the drying temperature exceeds the softening point of materials like PLA and TPU."
msgstr ""
msgid "Starting: Checking adapter connection"
msgstr ""
msgid "Starting: Checking filament status"
msgstr ""
msgid "Starting: Checking drying presets"
msgstr ""
msgid "Starting: Checking filament location"
msgstr ""
msgid "Starting: Checking air intake"
msgstr ""
msgid "Starting: Checking air vent"
msgstr ""
msgid "The filament may not be compatible with the current machine settings. Generic filament presets will be used."
msgstr "Материал может быть несовместим с текущими настройками принтера. Будет использоваться базовый профиль материала."
@@ -21123,6 +21399,12 @@ msgstr ""
"Предотвращение коробления материала\n"
"Знаете ли вы, что при печати материалами, склонными к короблению, таких как ABS, повышение температуры подогреваемого стола может снизить эту вероятность?"
#~ msgid "°C"
#~ msgstr "°C"
#~ msgid "%"
#~ msgstr "%"
#~ msgid "Renders cast shadows on the plate in realistic view."
#~ msgstr "Отрисовывать тени в режиме продвинутой графики."

View File

@@ -3,7 +3,7 @@ msgid ""
msgstr ""
"Project-Id-Version: Orca Slicer\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-07-13 16:24-0300\n"
"POT-Creation-Date: 2026-07-17 15:13-0300\n"
"Language: sv\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
@@ -1955,6 +1955,17 @@ msgstr "Det är den senaste versionen."
msgid "Info"
msgstr ""
msgid "Loading Plugins"
msgstr ""
#, c-format, boost-format
msgid "Plugin %s is no longer available."
msgstr ""
#, c-format, boost-format
msgid "Plugin %s access is unauthorized."
msgstr ""
msgid "Loading printer & filament profiles"
msgstr ""
@@ -2069,6 +2080,18 @@ msgstr ""
msgid "Resolve cloud sync conflict"
msgstr ""
msgid "Syncing your account…"
msgstr ""
msgid "Migrating presets…"
msgstr ""
msgid "Fetching plugins…"
msgstr ""
msgid "Loading user presets…"
msgstr ""
msgid "Retrieving printer information, please try again later."
msgstr ""
@@ -2187,6 +2210,21 @@ msgstr ""
msgid "*"
msgstr "*"
msgid "Plugins"
msgstr ""
#, c-format, boost-format
msgid ""
"Failed to open the Plugins dialog:\n"
"%s"
msgstr ""
msgid "Failed to open the Plugins dialog (unknown error)."
msgstr ""
msgid "Plugin Terminal"
msgstr ""
msgid "Changing application language"
msgstr "Byter språk"
@@ -4983,6 +5021,28 @@ msgstr "Ogiltligt format. Förväntat vector format: \"%1%\""
msgid "N/A"
msgstr ""
msgid "System agents"
msgstr ""
msgid "No plugin selected"
msgstr ""
msgid "Add plugin"
msgstr ""
msgid "Select plugin"
msgstr ""
msgid "Remove plugin"
msgstr ""
msgid "Configure"
msgstr ""
#, c-format, boost-format
msgid "Configure (%d)"
msgstr ""
msgid "Pick"
msgstr "Välj"
@@ -5148,9 +5208,6 @@ msgstr "Flödeshastighet"
msgid "Fan speed"
msgstr "Fläkt hastighet"
msgid "°C"
msgstr "° C"
msgid "Time"
msgstr "Tid"
@@ -7161,6 +7218,14 @@ msgctxt "Layers"
msgid "Bottom"
msgstr "Bottenlager"
msgid "Plugin Selection"
msgstr ""
msgid ""
"No plugins capabilities available for this type.\n"
"Enable or install some to use."
msgstr ""
msgid "Enable detection of build plate position"
msgstr "Aktivera detektering av byggplattans position"
@@ -8058,6 +8123,40 @@ msgstr ""
msgid "Synchronize AMS Filament Information"
msgstr ""
msgid "OrcaCloud plugins required by the current preset are not installed:"
msgstr ""
msgid "Install Plugins"
msgstr ""
msgid "Local plugins required by the current preset are missing:"
msgstr ""
msgid "Find on OrcaCloud"
msgstr ""
msgid "Plugins required by the current preset are not activated:"
msgstr ""
msgid "Activate Now"
msgstr ""
msgid "The installed plugin does not provide the required capability — it may be outdated:"
msgstr ""
msgid "Preparing to install plugins..."
msgstr ""
msgid "Installing plugins"
msgstr ""
msgid "Cancelling — finishing the current plugin..."
msgstr ""
#, boost-format
msgid "Installing %1%..."
msgstr ""
msgid "Plate Settings"
msgstr "Inställningar för platta"
@@ -9098,6 +9197,9 @@ msgstr ""
msgid "Your filament grouping method in the sliced file is not optimal."
msgstr ""
msgid "To ensure print quality, the drying temperature will be lowered during printing."
msgstr ""
msgid "Auto Bed Leveling"
msgstr ""
@@ -9812,6 +9914,12 @@ msgstr ""
msgid "Post-processing Scripts"
msgstr "Skript för efterbehandling"
msgid "Slicing Pipeline Plugin"
msgstr ""
msgid "Plugin Configuration"
msgstr ""
msgid "Notes"
msgstr ""
@@ -10919,6 +11027,9 @@ msgstr ""
msgid "Switch between Prepare/Preview"
msgstr "Växla mellan Förbered/Förhandsgranska"
msgid "Open actions speed dial"
msgstr ""
msgid "Plater"
msgstr "Plätering/Förgyllning"
@@ -11767,6 +11878,9 @@ msgstr "API nyckel"
msgid "HTTP digest"
msgstr "HTTP sammandrag"
msgid "Configuration for the plugin capabilities this preset uses, overriding the global Capabilities configuration. Stored as a raw JSON array and edited through the dialog behind the button, never typed in directly."
msgstr ""
msgid "Avoid crossing walls"
msgstr "Undvik att korsa väggar"
@@ -12639,6 +12753,24 @@ msgid ""
"WARNING: Lowering this value may negatively affect bed adhesion."
msgstr ""
msgid "Top surface fill order"
msgstr ""
msgid ""
"Direction in which top surfaces are filled when using a center-based pattern (Concentric, Archimedean Chords, Octagram Spiral).\n"
"Outward starts at the center of the surface, so any excess material is pushed towards the edge where it is least visible. Inward starts at the edge and ends with the tight curves at the center.\n"
"Default uses shortest-path ordering, which may run in either direction."
msgstr ""
msgid "Bottom surface fill order"
msgstr ""
msgid ""
"Direction in which bottom surfaces are filled when using a center-based pattern (Concentric, Archimedean Chords, Octagram Spiral).\n"
"Inward starts each surface with the wider outer curves, which improves first layer adhesion on build plates where the tight curves at the center may not stick. Outward starts at the center, pushing any excess material towards the edge.\n"
"Default uses shortest-path ordering, which may run in either direction."
msgstr ""
msgid "Internal solid infill pattern"
msgstr "Invändigt mönster för fyllning av solida ytor"
@@ -13798,9 +13930,6 @@ msgid ""
"Set to 0 to deactivate."
msgstr ""
msgid "%"
msgstr "%"
msgid "Time cost"
msgstr ""
@@ -14467,6 +14596,9 @@ msgid ""
"RRF: X and Y values are equal."
msgstr ""
msgid "Hz"
msgstr "Hz"
msgid "Y"
msgstr "Y"
@@ -14716,6 +14848,15 @@ msgstr ""
msgid "This G-code is inserted when the extrusion role is changed. It runs after the machine and filament extrusion role G-code."
msgstr ""
msgid "Plugins Used"
msgstr ""
msgid "Plugin capabilities referenced by this preset, stored as name;uuid;capability."
msgstr ""
msgid "Python plugin(s) invoked at each slicing pipeline step to read and modify intermediate slicing data, including a final G-code post-processing step. Research/experimental."
msgstr ""
msgid "Printer type"
msgstr ""
@@ -14784,6 +14925,15 @@ msgstr "Retraktions mängd innan wipe"
msgid "This is the length of fast retraction before a wipe, relative to retraction length."
msgstr "Detta är längden av snabb retraktion före en wipe, i förhållande till retraktions längden"
msgid "Retract amount after wipe"
msgstr ""
#, c-format
msgid ""
"The length of fast retraction after wipe, relative to retraction length.\n"
"The value will be clamped by 100% minus the retract amount before the wipe value."
msgstr ""
# TODO: Review, changed by lang refactor. PR 14254
msgid "Retract on layer change"
msgstr "Retraktera vid lager byte"
@@ -15756,16 +15906,6 @@ msgstr "Övre skalets tjocklek"
msgid "The number of top solid layers is increased when slicing if the thickness calculated by top shell layers is thinner than this value. This can avoid having too thin a shell when layer height is small. 0 means that this setting is disabled and thickness of top shell is determined simply by the number of top shell layers."
msgstr "Antal solida övre lager ökas när tjockleken kalkyleras och övre skalet är tunnare än detta värde. Detta kan undvika att ha för tunt skal när lagerhöjden är liten. 0 betyder att den här inställningen är inaktiverad och tjockleken på det övre skalet bestäms av de övre skal lagerna"
msgid "Anisotropic surfaces"
msgstr ""
msgid ""
"Anisotropic patterns on the top and bottom surfaces.\n"
"Co-directional printing mode will be applied. For certain patterns, omni-directional filling provides color dispersion when using multi-colored or silk plastics.\n"
"This option disable the gap fill.\n"
"This option can increase a printing time."
msgstr ""
msgid "Separated infills"
msgstr ""
@@ -17531,9 +17671,6 @@ msgstr ""
msgid "Frequency settings"
msgstr ""
msgid "Hz"
msgstr "Hz"
msgid "RepRap firmware uses the same frequency range for both axes."
msgstr ""
@@ -19471,6 +19608,145 @@ msgstr ""
msgid "Open File"
msgstr ""
msgid "AMS Dryness Control"
msgstr ""
msgid "Filament Drying Settings"
msgstr ""
msgid "Stopping"
msgstr ""
msgid "Unable to dry temporarily due to ..."
msgstr ""
msgid "Drying Error"
msgstr ""
msgid "Please check the Assistant for troubleshooting"
msgstr ""
msgid "Please remove and store the filament (as shown)."
msgstr ""
msgid "The AMS can rotate the filament which is properly stored, providing better drying results."
msgstr ""
msgid "Rotate spool when drying"
msgstr ""
msgctxt "amsdrying"
msgid "Back"
msgstr ""
msgid "Drying-Heating"
msgstr ""
msgid "Drying-Dehumidifying"
msgstr ""
msgid " maximum drying temperature is "
msgstr ""
msgid " minimum drying temperature is "
msgstr ""
msgid "This filament may not be completely dried."
msgstr ""
msgid "This AMS is currently printing. To ensure print quality, the drying temperature cannot exceed the recommended drying temperature."
msgstr ""
msgid "The temperature shall not exceed the filament's heat distortion temperature"
msgstr ""
msgid "Minimum time value cannot be less than 1."
msgstr ""
msgid "Maximum time value cannot be greater than 24."
msgstr ""
msgid "Insufficient power"
msgstr ""
msgid " Too many AMS drying simultaneously. Please plug in the power or stop other drying processes before starting."
msgstr ""
msgid "AMS is busy"
msgstr ""
msgid " AMS is calibrating | reading RFID | loading/unloading material, please wait."
msgstr ""
msgid "Filament in AMS outlet"
msgstr ""
msgid " The high drying temperature may cause AMS blockage, please unload first."
msgstr ""
msgid "Initiating AMS drying"
msgstr ""
msgid "Not supported in 2D mode"
msgstr ""
msgid "Task in progress"
msgstr ""
msgid " The AMS might be in use during Task."
msgstr ""
msgid " Firmware update in progress, please wait..."
msgstr ""
msgid " Please plug in the power and then use the drying function."
msgstr ""
msgid " The high drying temperature may cause AMS blockage. Please unload the filament manually before proceeding."
msgstr ""
msgid "System is busy"
msgstr ""
msgid " Initiating other drying processes, please wait a few seconds..."
msgstr ""
msgid "For better drying results, remove the filament and allow it to rotate."
msgstr ""
msgid "The AMS will automatically rotate the stored filament slots to enhance the drying performance."
msgstr ""
msgid "Alternatively, you can dry the filament without removing it."
msgstr ""
msgid "Unknown filaments will be treated as PLA."
msgstr ""
msgid "Please store the filament marked with an exclamation mark."
msgstr ""
msgid "Filament left in the feeder during drying may soften because the drying temperature exceeds the softening point of materials like PLA and TPU."
msgstr ""
msgid "Starting: Checking adapter connection"
msgstr ""
msgid "Starting: Checking filament status"
msgstr ""
msgid "Starting: Checking drying presets"
msgstr ""
msgid "Starting: Checking filament location"
msgstr ""
msgid "Starting: Checking air intake"
msgstr ""
msgid "Starting: Checking air vent"
msgstr ""
msgid "The filament may not be compatible with the current machine settings. Generic filament presets will be used."
msgstr ""
@@ -19766,6 +20042,12 @@ msgstr ""
"Undvik vridning\n"
"Visste du att när du skriver ut material som är benägna att vrida, såsom ABS, kan en lämplig ökning av värmebäddens temperatur minska sannolikheten för vridning?"
#~ msgid "°C"
#~ msgstr "° C"
#~ msgid "%"
#~ msgstr "%"
#~ msgctxt "Sync_Nozzle_AMS"
#~ msgid "Cancel"
#~ msgstr "Avbryt"

View File

@@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: Orca Slicer\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-07-13 16:24-0300\n"
"POT-Creation-Date: 2026-07-17 15:13-0300\n"
"PO-Revision-Date: 2026-06-19 13:40+0700\n"
"Last-Translator: Icezaza\n"
"Language-Team: Thai\n"
@@ -1962,6 +1962,17 @@ msgstr "นี่เป็นเวอร์ชันใหม่ล่าสุ
msgid "Info"
msgstr "ข้อมูล"
msgid "Loading Plugins"
msgstr ""
#, c-format, boost-format
msgid "Plugin %s is no longer available."
msgstr ""
#, c-format, boost-format
msgid "Plugin %s access is unauthorized."
msgstr ""
msgid "Loading printer & filament profiles"
msgstr "กำลังโหลดโปรไฟล์เครื่องพิมพ์และฟิลาเมนต์"
@@ -2080,6 +2091,18 @@ msgstr ""
msgid "Resolve cloud sync conflict"
msgstr "แก้ไขความขัดแย้งการซิงค์คลาวด์"
msgid "Syncing your account…"
msgstr ""
msgid "Migrating presets…"
msgstr ""
msgid "Fetching plugins…"
msgstr ""
msgid "Loading user presets…"
msgstr ""
msgid "Retrieving printer information, please try again later."
msgstr "กำลังดึงข้อมูลเครื่องพิมพ์ โปรดลองอีกครั้งในภายหลัง"
@@ -2210,6 +2233,21 @@ msgstr ""
msgid "*"
msgstr "*"
msgid "Plugins"
msgstr ""
#, c-format, boost-format
msgid ""
"Failed to open the Plugins dialog:\n"
"%s"
msgstr ""
msgid "Failed to open the Plugins dialog (unknown error)."
msgstr ""
msgid "Plugin Terminal"
msgstr ""
msgid "Changing application language"
msgstr "การเปลี่ยนภาษาของแอปพลิเคชัน"
@@ -4935,6 +4973,28 @@ msgstr "รูปแบบไม่ถูกต้อง รูปแบบเ
msgid "N/A"
msgstr "ไม่มี"
msgid "System agents"
msgstr ""
msgid "No plugin selected"
msgstr ""
msgid "Add plugin"
msgstr ""
msgid "Select plugin"
msgstr ""
msgid "Remove plugin"
msgstr ""
msgid "Configure"
msgstr ""
#, c-format, boost-format
msgid "Configure (%d)"
msgstr ""
msgid "Pick"
msgstr "เลือก"
@@ -5100,9 +5160,6 @@ msgstr "อัตราการไหล"
msgid "Fan speed"
msgstr "ความเร็วพัดลม"
msgid "°C"
msgstr "°C"
msgid "Time"
msgstr "เวลา"
@@ -7095,6 +7152,14 @@ msgctxt "Layers"
msgid "Bottom"
msgstr "ล่าง"
msgid "Plugin Selection"
msgstr ""
msgid ""
"No plugins capabilities available for this type.\n"
"Enable or install some to use."
msgstr ""
msgid "Enable detection of build plate position"
msgstr "เปิดใช้งานการตรวจจับตำแหน่งฐานรองแท่นพิมพ์"
@@ -7970,6 +8035,40 @@ msgstr "หน้าอุปกรณ์"
msgid "Synchronize AMS Filament Information"
msgstr "ประสานข้อมูล AMS เส้นพลาสติก"
msgid "OrcaCloud plugins required by the current preset are not installed:"
msgstr ""
msgid "Install Plugins"
msgstr ""
msgid "Local plugins required by the current preset are missing:"
msgstr ""
msgid "Find on OrcaCloud"
msgstr ""
msgid "Plugins required by the current preset are not activated:"
msgstr ""
msgid "Activate Now"
msgstr ""
msgid "The installed plugin does not provide the required capability — it may be outdated:"
msgstr ""
msgid "Preparing to install plugins..."
msgstr ""
msgid "Installing plugins"
msgstr ""
msgid "Cancelling — finishing the current plugin..."
msgstr ""
#, boost-format
msgid "Installing %1%..."
msgstr ""
msgid "Plate Settings"
msgstr "การตั้งค่าฐานพิมพ์"
@@ -9028,6 +9127,9 @@ msgstr "หลากสีพร้อมภายนอก"
msgid "Your filament grouping method in the sliced file is not optimal."
msgstr "วิธีการจัดกลุ่มเส้นพลาสติกของคุณในไฟล์ที่แบ่งส่วนนั้นไม่เหมาะสมที่สุด"
msgid "To ensure print quality, the drying temperature will be lowered during printing."
msgstr ""
msgid "Auto Bed Leveling"
msgstr "ปรับระดับฐานพิมพ์อัตโนมัติ"
@@ -9745,6 +9847,12 @@ msgstr "เปลี่ยนบทบาทการอัดขึ้นรู
msgid "Post-processing Scripts"
msgstr "สคริปต์หลังการประมวลผล"
msgid "Slicing Pipeline Plugin"
msgstr ""
msgid "Plugin Configuration"
msgstr ""
msgid "Notes"
msgstr "หมายเหตุ"
@@ -10873,6 +10981,9 @@ msgstr "สลับการพิมพ์สำหรับวัตถุ/
msgid "Switch between Prepare/Preview"
msgstr "สลับระหว่างการเตรียม/ดูตัวอย่าง"
msgid "Open actions speed dial"
msgstr ""
msgid "Plater"
msgstr "เพลเตอร์"
@@ -11703,6 +11814,9 @@ msgstr "คีย์เอพีไอ"
msgid "HTTP digest"
msgstr "HTTP ไดเจสต์"
msgid "Configuration for the plugin capabilities this preset uses, overriding the global Capabilities configuration. Stored as a raw JSON array and edited through the dialog behind the button, never typed in directly."
msgstr ""
msgid "Avoid crossing walls"
msgstr "หลีกเลี่ยงการข้ามผนัง"
@@ -12706,6 +12820,24 @@ msgstr ""
"ความหนาแน่นของชั้นผิวด้านล่าง มีวัตถุประสงค์เพื่อความสวยงามหรือการใช้งาน ไม่ใช่เพื่อแก้ไขปัญหา เช่น การอัดขึ้นรูปมากเกินไป\n"
"คำเตือน: การลดค่านี้อาจส่งผลเสียต่อการยึดเกาะของฐานพิมพ์"
msgid "Top surface fill order"
msgstr ""
msgid ""
"Direction in which top surfaces are filled when using a center-based pattern (Concentric, Archimedean Chords, Octagram Spiral).\n"
"Outward starts at the center of the surface, so any excess material is pushed towards the edge where it is least visible. Inward starts at the edge and ends with the tight curves at the center.\n"
"Default uses shortest-path ordering, which may run in either direction."
msgstr ""
msgid "Bottom surface fill order"
msgstr ""
msgid ""
"Direction in which bottom surfaces are filled when using a center-based pattern (Concentric, Archimedean Chords, Octagram Spiral).\n"
"Inward starts each surface with the wider outer curves, which improves first layer adhesion on build plates where the tight curves at the center may not stick. Outward starts at the center, pushing any excess material towards the edge.\n"
"Default uses shortest-path ordering, which may run in either direction."
msgstr ""
msgid "Internal solid infill pattern"
msgstr "รูปแบบไส้ในของแข็งภายใน"
@@ -13928,9 +14060,6 @@ msgstr ""
"หากเฟิร์มแวร์ของคุณปิดใช้งานพัดลมที่ต่ำกว่าเกณฑ์อยู่แล้ว (เช่น [พัดลม] off_below ของ Klipper: 0.10 จะปิดพัดลมเมื่อใดก็ตามที่รอบการทำงานที่ได้รับคำสั่งต่ำกว่า 10%) ตัวเลือกนี้และเกณฑ์ของเฟิร์มแวร์ควรได้รับการตั้งค่าตามอุดมคติให้เป็นค่าเดียวกัน การจับคู่พวกมัน (เช่น off_below: 0.10 ใน Klipper และ 10% ที่นี่) รับประกันว่าตัวแบ่งส่วนข้อมูลจะไม่ปล่อยค่าที่ไม่ใช่ศูนย์ซึ่งเฟิร์มแวร์จะดรอปอย่างเงียบๆ และพัดลมจะไม่ได้รับค่าที่ต่ำกว่าค่าที่คุณรู้ว่าสามารถสปูลได้จริง\n"
"ตั้งค่าเป็น 0 เพื่อปิดใช้งาน"
msgid "%"
msgstr "%"
msgid "Time cost"
msgstr "ต้นทุนเวลา"
@@ -14620,6 +14749,9 @@ msgstr ""
"หากต้องการปิดใช้งานการสร้างอินพุต ให้ใช้ประเภทปิดใช้งาน\n"
"RRF: ค่า X และ Y เท่ากัน"
msgid "Hz"
msgstr "Hz"
msgid "Y"
msgstr "Y"
@@ -14901,6 +15033,15 @@ msgstr "เปลี่ยนบทบาทการอัดขึ้นรู
msgid "This G-code is inserted when the extrusion role is changed. It runs after the machine and filament extrusion role G-code."
msgstr "G-code นี้จะถูกแทรกเมื่อบทบาทการอัดขึ้นรูปมีการเปลี่ยนแปลง มันทำงานหลังจากบทบาทการอัดขึ้นรูปของเครื่องจักรและการอัดขึ้นรูปเส้นพลาสติก G-code"
msgid "Plugins Used"
msgstr ""
msgid "Plugin capabilities referenced by this preset, stored as name;uuid;capability."
msgstr ""
msgid "Python plugin(s) invoked at each slicing pipeline step to read and modify intermediate slicing data, including a final G-code post-processing step. Research/experimental."
msgstr ""
msgid "Printer type"
msgstr "ประเภทเครื่องพิมพ์"
@@ -14961,6 +15102,15 @@ msgstr "ถอนจำนวนก่อนเช็ด"
msgid "This is the length of fast retraction before a wipe, relative to retraction length."
msgstr "ความยาวของการดึงกลับอย่างรวดเร็วก่อนเช็ด สัมพันธ์กับความยาวการดึงกลับ"
msgid "Retract amount after wipe"
msgstr ""
#, c-format
msgid ""
"The length of fast retraction after wipe, relative to retraction length.\n"
"The value will be clamped by 100% minus the retract amount before the wipe value."
msgstr ""
msgid "Retract on layer change"
msgstr "ถอนออกเมื่อเปลี่ยนเลเยอร์"
@@ -15936,16 +16086,6 @@ msgstr "ความหนาผนังด้านบน"
msgid "The number of top solid layers is increased when slicing if the thickness calculated by top shell layers is thinner than this value. This can avoid having too thin a shell when layer height is small. 0 means that this setting is disabled and thickness of top shell is determined simply by the number of top shell layers."
msgstr "จำนวนชั้นทึบด้านบนจะเพิ่มขึ้นเมื่อสไลซ์หากความหนาที่คำนวณโดยชั้นเปลือกด้านบนบางกว่าค่านี้ วิธีนี้สามารถหลีกเลี่ยงไม่ให้เปลือกบางเกินไปเมื่อชั้นมีความสูงน้อย 0 หมายความว่าการตั้งค่านี้ถูกปิดใช้งาน และความหนาของเปลือกด้านบนถูกกำหนดโดยชั้นเปลือกด้านบนอย่างแน่นอน"
msgid "Anisotropic surfaces"
msgstr ""
msgid ""
"Anisotropic patterns on the top and bottom surfaces.\n"
"Co-directional printing mode will be applied. For certain patterns, omni-directional filling provides color dispersion when using multi-colored or silk plastics.\n"
"This option disable the gap fill.\n"
"This option can increase a printing time."
msgstr ""
msgid "Separated infills"
msgstr ""
@@ -17744,9 +17884,6 @@ msgstr "เริ่ม / สิ้นสุด"
msgid "Frequency settings"
msgstr "การตั้งค่าความถี่"
msgid "Hz"
msgstr "Hz"
msgid "RepRap firmware uses the same frequency range for both axes."
msgstr "เฟิร์มแวร์ RepRap ใช้ช่วงความถี่เดียวกันสำหรับทั้งสองแกน"
@@ -19720,6 +19857,145 @@ msgstr "ดูตัวอย่างไฟล์บีบอัด"
msgid "Open File"
msgstr "เปิดไฟล์"
msgid "AMS Dryness Control"
msgstr ""
msgid "Filament Drying Settings"
msgstr ""
msgid "Stopping"
msgstr ""
msgid "Unable to dry temporarily due to ..."
msgstr ""
msgid "Drying Error"
msgstr ""
msgid "Please check the Assistant for troubleshooting"
msgstr ""
msgid "Please remove and store the filament (as shown)."
msgstr ""
msgid "The AMS can rotate the filament which is properly stored, providing better drying results."
msgstr ""
msgid "Rotate spool when drying"
msgstr ""
msgctxt "amsdrying"
msgid "Back"
msgstr ""
msgid "Drying-Heating"
msgstr ""
msgid "Drying-Dehumidifying"
msgstr ""
msgid " maximum drying temperature is "
msgstr ""
msgid " minimum drying temperature is "
msgstr ""
msgid "This filament may not be completely dried."
msgstr ""
msgid "This AMS is currently printing. To ensure print quality, the drying temperature cannot exceed the recommended drying temperature."
msgstr ""
msgid "The temperature shall not exceed the filament's heat distortion temperature"
msgstr ""
msgid "Minimum time value cannot be less than 1."
msgstr ""
msgid "Maximum time value cannot be greater than 24."
msgstr ""
msgid "Insufficient power"
msgstr ""
msgid " Too many AMS drying simultaneously. Please plug in the power or stop other drying processes before starting."
msgstr ""
msgid "AMS is busy"
msgstr ""
msgid " AMS is calibrating | reading RFID | loading/unloading material, please wait."
msgstr ""
msgid "Filament in AMS outlet"
msgstr ""
msgid " The high drying temperature may cause AMS blockage, please unload first."
msgstr ""
msgid "Initiating AMS drying"
msgstr ""
msgid "Not supported in 2D mode"
msgstr ""
msgid "Task in progress"
msgstr ""
msgid " The AMS might be in use during Task."
msgstr ""
msgid " Firmware update in progress, please wait..."
msgstr ""
msgid " Please plug in the power and then use the drying function."
msgstr ""
msgid " The high drying temperature may cause AMS blockage. Please unload the filament manually before proceeding."
msgstr ""
msgid "System is busy"
msgstr ""
msgid " Initiating other drying processes, please wait a few seconds..."
msgstr ""
msgid "For better drying results, remove the filament and allow it to rotate."
msgstr ""
msgid "The AMS will automatically rotate the stored filament slots to enhance the drying performance."
msgstr ""
msgid "Alternatively, you can dry the filament without removing it."
msgstr ""
msgid "Unknown filaments will be treated as PLA."
msgstr ""
msgid "Please store the filament marked with an exclamation mark."
msgstr ""
msgid "Filament left in the feeder during drying may soften because the drying temperature exceeds the softening point of materials like PLA and TPU."
msgstr ""
msgid "Starting: Checking adapter connection"
msgstr ""
msgid "Starting: Checking filament status"
msgstr ""
msgid "Starting: Checking drying presets"
msgstr ""
msgid "Starting: Checking filament location"
msgstr ""
msgid "Starting: Checking air intake"
msgstr ""
msgid "Starting: Checking air vent"
msgstr ""
msgid "The filament may not be compatible with the current machine settings. Generic filament presets will be used."
msgstr "เส้นพลาสติกอาจไม่เข้ากันกับการตั้งค่าเครื่องปัจจุบัน จะใช้การตั้งค่าฟิลาเมนต์ทั่วไป"
@@ -20035,6 +20311,12 @@ msgstr ""
"หลีกเลี่ยงการบิดเบี้ยว\n"
"คุณรู้หรือไม่ว่าเมื่อพิมพ์วัสดุที่มีแนวโน้มที่จะเกิดการบิดเบี้ยว เช่น ABS การเพิ่มอุณหภูมิฐานพิมพ์อย่างเหมาะสมสามารถลดความน่าจะเป็นของการบิดเบี้ยวได้"
#~ msgid "°C"
#~ msgstr "°C"
#~ msgid "%"
#~ msgstr "%"
#~ msgid "Renders cast shadows on the plate in realistic view."
#~ msgstr "แสดงเงาแบบทอดบนเพลตในมุมมองแบบสมจริง"

View File

@@ -3,7 +3,7 @@ msgid ""
msgstr ""
"Project-Id-Version: Orca Slicer\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-07-13 16:24-0300\n"
"POT-Creation-Date: 2026-07-17 15:13-0300\n"
"PO-Revision-Date: 2026-04-08 23:59+0300\n"
"Last-Translator: GlauTech\n"
"Language-Team: \n"
@@ -1982,6 +1982,17 @@ msgstr "Bu en yeni versiyondur."
msgid "Info"
msgstr "Bilgi"
msgid "Loading Plugins"
msgstr ""
#, c-format, boost-format
msgid "Plugin %s is no longer available."
msgstr ""
#, c-format, boost-format
msgid "Plugin %s access is unauthorized."
msgstr ""
msgid "Loading printer & filament profiles"
msgstr ""
@@ -2099,6 +2110,18 @@ msgstr ""
msgid "Resolve cloud sync conflict"
msgstr ""
msgid "Syncing your account…"
msgstr ""
msgid "Migrating presets…"
msgstr ""
msgid "Fetching plugins…"
msgstr ""
msgid "Loading user presets…"
msgstr ""
msgid "Retrieving printer information, please try again later."
msgstr "Yazıcı bilgileri alınıyor, lütfen daha sonra tekrar deneyin."
@@ -2224,6 +2247,21 @@ msgstr ""
msgid "*"
msgstr "*"
msgid "Plugins"
msgstr ""
#, c-format, boost-format
msgid ""
"Failed to open the Plugins dialog:\n"
"%s"
msgstr ""
msgid "Failed to open the Plugins dialog (unknown error)."
msgstr ""
msgid "Plugin Terminal"
msgstr ""
msgid "Changing application language"
msgstr "Dil değiştiriliyor"
@@ -5049,6 +5087,28 @@ msgstr "Geçersiz format. Beklenen vektör formatı: \"%1%\""
msgid "N/A"
msgstr ""
msgid "System agents"
msgstr ""
msgid "No plugin selected"
msgstr ""
msgid "Add plugin"
msgstr ""
msgid "Select plugin"
msgstr ""
msgid "Remove plugin"
msgstr ""
msgid "Configure"
msgstr ""
#, c-format, boost-format
msgid "Configure (%d)"
msgstr ""
msgid "Pick"
msgstr "Seç"
@@ -5214,9 +5274,6 @@ msgstr "Akış hızı"
msgid "Fan speed"
msgstr "Fan hızı"
msgid "°C"
msgstr "°C"
msgid "Time"
msgstr "Zaman"
@@ -7245,6 +7302,14 @@ msgctxt "Layers"
msgid "Bottom"
msgstr "Alt"
msgid "Plugin Selection"
msgstr ""
msgid ""
"No plugins capabilities available for this type.\n"
"Enable or install some to use."
msgstr ""
msgid "Enable detection of build plate position"
msgstr "Yapı plakası konumunun algılanmasını etkinleştir"
@@ -8149,6 +8214,40 @@ msgstr "Cihaz Sayfası"
msgid "Synchronize AMS Filament Information"
msgstr "AMS Filament Bilgilerini Senkronize Etme"
msgid "OrcaCloud plugins required by the current preset are not installed:"
msgstr ""
msgid "Install Plugins"
msgstr ""
msgid "Local plugins required by the current preset are missing:"
msgstr ""
msgid "Find on OrcaCloud"
msgstr ""
msgid "Plugins required by the current preset are not activated:"
msgstr ""
msgid "Activate Now"
msgstr ""
msgid "The installed plugin does not provide the required capability — it may be outdated:"
msgstr ""
msgid "Preparing to install plugins..."
msgstr ""
msgid "Installing plugins"
msgstr ""
msgid "Cancelling — finishing the current plugin..."
msgstr ""
#, boost-format
msgid "Installing %1%..."
msgstr ""
msgid "Plate Settings"
msgstr "Plaka Ayarları"
@@ -9207,6 +9306,9 @@ msgstr "Çok renkli harici"
msgid "Your filament grouping method in the sliced file is not optimal."
msgstr "Dilimlenmiş dosyadaki filaman gruplama yönteminiz optimal değil."
msgid "To ensure print quality, the drying temperature will be lowered during printing."
msgstr ""
msgid "Auto Bed Leveling"
msgstr "Otomatik Yatak Tesviyesi"
@@ -9937,6 +10039,12 @@ msgstr "Ekstrüzyon Rolü G-kodu Değiştirme"
msgid "Post-processing Scripts"
msgstr "İşlem Sonrası Komut Dosyaları"
msgid "Slicing Pipeline Plugin"
msgstr ""
msgid "Plugin Configuration"
msgstr ""
msgid "Notes"
msgstr "Notlar"
@@ -11066,6 +11174,9 @@ msgstr ""
msgid "Switch between Prepare/Preview"
msgstr "Hazırlama/Önizleme arasında geçiş yap"
msgid "Open actions speed dial"
msgstr ""
msgid "Plater"
msgstr "Plakacı"
@@ -11926,6 +12037,9 @@ msgstr "API anahtarı"
msgid "HTTP digest"
msgstr "HTTP özeti"
msgid "Configuration for the plugin capabilities this preset uses, overriding the global Capabilities configuration. Stored as a raw JSON array and edited through the dialog behind the button, never typed in directly."
msgstr ""
msgid "Avoid crossing walls"
msgstr "Duvar geçişinden kaçın"
@@ -12899,6 +13013,24 @@ msgstr ""
"Alt yüzey katmanının yoğunluğu. Estetik veya işlevsel amaçlar için tasarlanmıştır, aşırı ekstrüzyon gibi sorunları gidermek için değildir.\n"
"UYARI: Bu değerin düşürülmesi, yatak yapışmasını olumsuz etkileyebilir."
msgid "Top surface fill order"
msgstr ""
msgid ""
"Direction in which top surfaces are filled when using a center-based pattern (Concentric, Archimedean Chords, Octagram Spiral).\n"
"Outward starts at the center of the surface, so any excess material is pushed towards the edge where it is least visible. Inward starts at the edge and ends with the tight curves at the center.\n"
"Default uses shortest-path ordering, which may run in either direction."
msgstr ""
msgid "Bottom surface fill order"
msgstr ""
msgid ""
"Direction in which bottom surfaces are filled when using a center-based pattern (Concentric, Archimedean Chords, Octagram Spiral).\n"
"Inward starts each surface with the wider outer curves, which improves first layer adhesion on build plates where the tight curves at the center may not stick. Outward starts at the center, pushing any excess material towards the edge.\n"
"Default uses shortest-path ordering, which may run in either direction."
msgstr ""
msgid "Internal solid infill pattern"
msgstr "İç katı dolgu deseni"
@@ -14129,9 +14261,6 @@ msgid ""
"Set to 0 to deactivate."
msgstr ""
msgid "%"
msgstr "%"
msgid "Time cost"
msgstr "Zaman maliyeti"
@@ -14818,6 +14947,9 @@ msgid ""
"RRF: X and Y values are equal."
msgstr ""
msgid "Hz"
msgstr "Hz."
msgid "Y"
msgstr "Y"
@@ -15091,6 +15223,15 @@ msgstr ""
msgid "This G-code is inserted when the extrusion role is changed. It runs after the machine and filament extrusion role G-code."
msgstr ""
msgid "Plugins Used"
msgstr ""
msgid "Plugin capabilities referenced by this preset, stored as name;uuid;capability."
msgstr ""
msgid "Python plugin(s) invoked at each slicing pipeline step to read and modify intermediate slicing data, including a final G-code post-processing step. Research/experimental."
msgstr ""
msgid "Printer type"
msgstr "Yazıcı türü"
@@ -15159,6 +15300,15 @@ msgstr "Temizleme işlemi öncesi geri çekme miktarı"
msgid "This is the length of fast retraction before a wipe, relative to retraction length."
msgstr "Geri çekme uzunluğuna göre, temizlemeden önce hızlı geri çekilmenin uzunluğu."
msgid "Retract amount after wipe"
msgstr ""
#, c-format
msgid ""
"The length of fast retraction after wipe, relative to retraction length.\n"
"The value will be clamped by 100% minus the retract amount before the wipe value."
msgstr ""
# TODO: Review, changed by lang refactor. PR 14254
msgid "Retract on layer change"
msgstr "Katman değişiminde geri çek"
@@ -16167,16 +16317,6 @@ msgstr "Üst katman kalınlığı"
msgid "The number of top solid layers is increased when slicing if the thickness calculated by top shell layers is thinner than this value. This can avoid having too thin a shell when layer height is small. 0 means that this setting is disabled and thickness of top shell is determined simply by the number of top shell layers."
msgstr "Üst kabuk katmanları tarafından hesaplanan kalınlık bu değerden daha ince ise dilimleme sırasında üst katı katmanların sayısı artırılır. Bu, katman yüksekliği küçük olduğunda kabuğun çok ince olmasını önleyebilir. 0, bu ayarın devre dışı olduğu ve üst kabuğun kalınlığının kesinlikle üst kabuk katmanları tarafından belirlendiği anlamına gelir."
msgid "Anisotropic surfaces"
msgstr ""
msgid ""
"Anisotropic patterns on the top and bottom surfaces.\n"
"Co-directional printing mode will be applied. For certain patterns, omni-directional filling provides color dispersion when using multi-colored or silk plastics.\n"
"This option disable the gap fill.\n"
"This option can increase a printing time."
msgstr ""
msgid "Separated infills"
msgstr ""
@@ -18007,9 +18147,6 @@ msgstr "Başlangıç / Bitiş"
msgid "Frequency settings"
msgstr "Frekans ayarları"
msgid "Hz"
msgstr "Hz."
msgid "RepRap firmware uses the same frequency range for both axes."
msgstr "RepRap ürün yazılımı her iki eksen için aynı frekans aralığını kullanır."
@@ -19999,6 +20136,145 @@ msgstr ""
msgid "Open File"
msgstr ""
msgid "AMS Dryness Control"
msgstr ""
msgid "Filament Drying Settings"
msgstr ""
msgid "Stopping"
msgstr ""
msgid "Unable to dry temporarily due to ..."
msgstr ""
msgid "Drying Error"
msgstr ""
msgid "Please check the Assistant for troubleshooting"
msgstr ""
msgid "Please remove and store the filament (as shown)."
msgstr ""
msgid "The AMS can rotate the filament which is properly stored, providing better drying results."
msgstr ""
msgid "Rotate spool when drying"
msgstr ""
msgctxt "amsdrying"
msgid "Back"
msgstr ""
msgid "Drying-Heating"
msgstr ""
msgid "Drying-Dehumidifying"
msgstr ""
msgid " maximum drying temperature is "
msgstr ""
msgid " minimum drying temperature is "
msgstr ""
msgid "This filament may not be completely dried."
msgstr ""
msgid "This AMS is currently printing. To ensure print quality, the drying temperature cannot exceed the recommended drying temperature."
msgstr ""
msgid "The temperature shall not exceed the filament's heat distortion temperature"
msgstr ""
msgid "Minimum time value cannot be less than 1."
msgstr ""
msgid "Maximum time value cannot be greater than 24."
msgstr ""
msgid "Insufficient power"
msgstr ""
msgid " Too many AMS drying simultaneously. Please plug in the power or stop other drying processes before starting."
msgstr ""
msgid "AMS is busy"
msgstr ""
msgid " AMS is calibrating | reading RFID | loading/unloading material, please wait."
msgstr ""
msgid "Filament in AMS outlet"
msgstr ""
msgid " The high drying temperature may cause AMS blockage, please unload first."
msgstr ""
msgid "Initiating AMS drying"
msgstr ""
msgid "Not supported in 2D mode"
msgstr ""
msgid "Task in progress"
msgstr ""
msgid " The AMS might be in use during Task."
msgstr ""
msgid " Firmware update in progress, please wait..."
msgstr ""
msgid " Please plug in the power and then use the drying function."
msgstr ""
msgid " The high drying temperature may cause AMS blockage. Please unload the filament manually before proceeding."
msgstr ""
msgid "System is busy"
msgstr ""
msgid " Initiating other drying processes, please wait a few seconds..."
msgstr ""
msgid "For better drying results, remove the filament and allow it to rotate."
msgstr ""
msgid "The AMS will automatically rotate the stored filament slots to enhance the drying performance."
msgstr ""
msgid "Alternatively, you can dry the filament without removing it."
msgstr ""
msgid "Unknown filaments will be treated as PLA."
msgstr ""
msgid "Please store the filament marked with an exclamation mark."
msgstr ""
msgid "Filament left in the feeder during drying may soften because the drying temperature exceeds the softening point of materials like PLA and TPU."
msgstr ""
msgid "Starting: Checking adapter connection"
msgstr ""
msgid "Starting: Checking filament status"
msgstr ""
msgid "Starting: Checking drying presets"
msgstr ""
msgid "Starting: Checking filament location"
msgstr ""
msgid "Starting: Checking air intake"
msgstr ""
msgid "Starting: Checking air vent"
msgstr ""
msgid "The filament may not be compatible with the current machine settings. Generic filament presets will be used."
msgstr "Filament mevcut makine ayarlarıyla uyumlu olmayabilir. Genel filament ön ayarları kullanılacaktır."
@@ -20321,6 +20597,12 @@ msgstr ""
"Eğilmeyi önleyin\n"
"ABS gibi bükülmeye yatkın malzemelere baskı yaparken, ısıtma yatağı sıcaklığının uygun şekilde arttırılmasının bükülme olasılığını azaltabileceğini biliyor muydunuz?"
#~ msgid "°C"
#~ msgstr "°C"
#~ msgid "%"
#~ msgstr "%"
#~ msgid "Continue to sync filaments"
#~ msgstr "Filamentleri senkronize etmeye devam edin"

File diff suppressed because it is too large Load Diff

View File

@@ -3,7 +3,7 @@ msgid ""
msgstr ""
"Project-Id-Version: Orca Slicer\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-07-13 16:24-0300\n"
"POT-Creation-Date: 2026-07-17 15:13-0300\n"
"PO-Revision-Date: 2025-10-02 17:43+0700\n"
"Last-Translator: \n"
"Language-Team: hainguyen.ts13@gmail.com\n"
@@ -1982,6 +1982,17 @@ msgstr "Đây là phiên bản mới nhất."
msgid "Info"
msgstr "Thông tin"
msgid "Loading Plugins"
msgstr ""
#, c-format, boost-format
msgid "Plugin %s is no longer available."
msgstr ""
#, c-format, boost-format
msgid "Plugin %s access is unauthorized."
msgstr ""
msgid "Loading printer & filament profiles"
msgstr ""
@@ -2099,6 +2110,18 @@ msgstr ""
msgid "Resolve cloud sync conflict"
msgstr ""
msgid "Syncing your account…"
msgstr ""
msgid "Migrating presets…"
msgstr ""
msgid "Fetching plugins…"
msgstr ""
msgid "Loading user presets…"
msgstr ""
msgid "Retrieving printer information, please try again later."
msgstr ""
@@ -2217,6 +2240,21 @@ msgstr ""
msgid "*"
msgstr "*"
msgid "Plugins"
msgstr ""
#, c-format, boost-format
msgid ""
"Failed to open the Plugins dialog:\n"
"%s"
msgstr ""
msgid "Failed to open the Plugins dialog (unknown error)."
msgstr ""
msgid "Plugin Terminal"
msgstr ""
msgid "Changing application language"
msgstr "Đang thay đổi ngôn ngữ ứng dụng"
@@ -5023,6 +5061,28 @@ msgstr "Định dạng không hợp lệ. Mong đợi định dạng vector: \"%
msgid "N/A"
msgstr ""
msgid "System agents"
msgstr ""
msgid "No plugin selected"
msgstr ""
msgid "Add plugin"
msgstr ""
msgid "Select plugin"
msgstr ""
msgid "Remove plugin"
msgstr ""
msgid "Configure"
msgstr ""
#, c-format, boost-format
msgid "Configure (%d)"
msgstr ""
msgid "Pick"
msgstr "Chọn"
@@ -5188,9 +5248,6 @@ msgstr ""
msgid "Fan speed"
msgstr "Tốc độ quạt"
msgid "°C"
msgstr "°C"
msgid "Time"
msgstr "Thời gian"
@@ -7211,6 +7268,14 @@ msgctxt "Layers"
msgid "Bottom"
msgstr "Dưới"
msgid "Plugin Selection"
msgstr ""
msgid ""
"No plugins capabilities available for this type.\n"
"Enable or install some to use."
msgstr ""
msgid "Enable detection of build plate position"
msgstr "Bật phát hiện vị trí bàn in"
@@ -8113,6 +8178,40 @@ msgstr ""
msgid "Synchronize AMS Filament Information"
msgstr ""
msgid "OrcaCloud plugins required by the current preset are not installed:"
msgstr ""
msgid "Install Plugins"
msgstr ""
msgid "Local plugins required by the current preset are missing:"
msgstr ""
msgid "Find on OrcaCloud"
msgstr ""
msgid "Plugins required by the current preset are not activated:"
msgstr ""
msgid "Activate Now"
msgstr ""
msgid "The installed plugin does not provide the required capability — it may be outdated:"
msgstr ""
msgid "Preparing to install plugins..."
msgstr ""
msgid "Installing plugins"
msgstr ""
msgid "Cancelling — finishing the current plugin..."
msgstr ""
#, boost-format
msgid "Installing %1%..."
msgstr ""
msgid "Plate Settings"
msgstr "Cài đặt bản"
@@ -9154,6 +9253,9 @@ msgstr ""
msgid "Your filament grouping method in the sliced file is not optimal."
msgstr ""
msgid "To ensure print quality, the drying temperature will be lowered during printing."
msgstr ""
msgid "Auto Bed Leveling"
msgstr ""
@@ -9873,6 +9975,12 @@ msgstr "G-code thay đổi vai trò đùn"
msgid "Post-processing Scripts"
msgstr "Script hậu xử lý"
msgid "Slicing Pipeline Plugin"
msgstr ""
msgid "Plugin Configuration"
msgstr ""
msgid "Notes"
msgstr "Ghi chú"
@@ -10989,6 +11097,9 @@ msgstr ""
msgid "Switch between Prepare/Preview"
msgstr "Chuyển đổi giữa Chuẩn bị/Xem trước"
msgid "Open actions speed dial"
msgstr ""
msgid "Plater"
msgstr "Bàn in"
@@ -11849,6 +11960,9 @@ msgstr "Khóa API"
msgid "HTTP digest"
msgstr ""
msgid "Configuration for the plugin capabilities this preset uses, overriding the global Capabilities configuration. Stored as a raw JSON array and edited through the dialog behind the button, never typed in directly."
msgstr ""
msgid "Avoid crossing walls"
msgstr "Tránh đi qua thành"
@@ -12795,6 +12909,24 @@ msgstr ""
"Mật độ lớp bề mặt dưới. Dành cho mục đích thẩm mỹ hoặc chức năng , không phải để sửa các vấn đề như đùn dư.\n"
"CẢNH BÁO: Giảm giá trị này có thể ảnh hưởng tiêu cực đến độ bám dính bàn in."
msgid "Top surface fill order"
msgstr ""
msgid ""
"Direction in which top surfaces are filled when using a center-based pattern (Concentric, Archimedean Chords, Octagram Spiral).\n"
"Outward starts at the center of the surface, so any excess material is pushed towards the edge where it is least visible. Inward starts at the edge and ends with the tight curves at the center.\n"
"Default uses shortest-path ordering, which may run in either direction."
msgstr ""
msgid "Bottom surface fill order"
msgstr ""
msgid ""
"Direction in which bottom surfaces are filled when using a center-based pattern (Concentric, Archimedean Chords, Octagram Spiral).\n"
"Inward starts each surface with the wider outer curves, which improves first layer adhesion on build plates where the tight curves at the center may not stick. Outward starts at the center, pushing any excess material towards the edge.\n"
"Default uses shortest-path ordering, which may run in either direction."
msgstr ""
msgid "Internal solid infill pattern"
msgstr "Mẫu infill đặc bên trong"
@@ -14021,9 +14153,6 @@ msgid ""
"Set to 0 to deactivate."
msgstr ""
msgid "%"
msgstr "%"
msgid "Time cost"
msgstr "Chi phí thời gian"
@@ -14709,6 +14838,9 @@ msgid ""
"RRF: X and Y values are equal."
msgstr ""
msgid "Hz"
msgstr "Hz"
msgid "Y"
msgstr "Y"
@@ -14983,6 +15115,15 @@ msgstr ""
msgid "This G-code is inserted when the extrusion role is changed. It runs after the machine and filament extrusion role G-code."
msgstr ""
msgid "Plugins Used"
msgstr ""
msgid "Plugin capabilities referenced by this preset, stored as name;uuid;capability."
msgstr ""
msgid "Python plugin(s) invoked at each slicing pipeline step to read and modify intermediate slicing data, including a final G-code post-processing step. Research/experimental."
msgstr ""
msgid "Printer type"
msgstr "Loại máy in"
@@ -15051,6 +15192,15 @@ msgstr "Lượng rút trước khi lau"
msgid "This is the length of fast retraction before a wipe, relative to retraction length."
msgstr "Độ dài của rút nhanh trước khi lau, tương đối với độ dài rút."
msgid "Retract amount after wipe"
msgstr ""
#, c-format
msgid ""
"The length of fast retraction after wipe, relative to retraction length.\n"
"The value will be clamped by 100% minus the retract amount before the wipe value."
msgstr ""
# TODO: Review, changed by lang refactor. PR 14254
msgid "Retract on layer change"
msgstr "Rút khi thay đổi lớp"
@@ -16055,16 +16205,6 @@ msgstr "Độ dày vỏ trên"
msgid "The number of top solid layers is increased when slicing if the thickness calculated by top shell layers is thinner than this value. This can avoid having too thin a shell when layer height is small. 0 means that this setting is disabled and thickness of top shell is determined simply by the number of top shell layers."
msgstr "Số lượng lớp đặc trên được tăng lên khi slice nếu độ dày được tính bởi lớp vỏ trên mỏng hơn giá trị này. Điều này có thể tránh vỏ quá mỏng khi chiều cao lớp nhỏ. 0 có nghĩa là cài đặt này bị tắt và độ dày vỏ trên được xác định tuyệt đối bởi lớp vỏ trên."
msgid "Anisotropic surfaces"
msgstr ""
msgid ""
"Anisotropic patterns on the top and bottom surfaces.\n"
"Co-directional printing mode will be applied. For certain patterns, omni-directional filling provides color dispersion when using multi-colored or silk plastics.\n"
"This option disable the gap fill.\n"
"This option can increase a printing time."
msgstr ""
msgid "Separated infills"
msgstr ""
@@ -17894,9 +18034,6 @@ msgstr "Bắt đầu / Kết thúc"
msgid "Frequency settings"
msgstr "Cài đặt tần số"
msgid "Hz"
msgstr "Hz"
msgid "RepRap firmware uses the same frequency range for both axes."
msgstr ""
@@ -19864,6 +20001,145 @@ msgstr ""
msgid "Open File"
msgstr ""
msgid "AMS Dryness Control"
msgstr ""
msgid "Filament Drying Settings"
msgstr ""
msgid "Stopping"
msgstr ""
msgid "Unable to dry temporarily due to ..."
msgstr ""
msgid "Drying Error"
msgstr ""
msgid "Please check the Assistant for troubleshooting"
msgstr ""
msgid "Please remove and store the filament (as shown)."
msgstr ""
msgid "The AMS can rotate the filament which is properly stored, providing better drying results."
msgstr ""
msgid "Rotate spool when drying"
msgstr ""
msgctxt "amsdrying"
msgid "Back"
msgstr ""
msgid "Drying-Heating"
msgstr ""
msgid "Drying-Dehumidifying"
msgstr ""
msgid " maximum drying temperature is "
msgstr ""
msgid " minimum drying temperature is "
msgstr ""
msgid "This filament may not be completely dried."
msgstr ""
msgid "This AMS is currently printing. To ensure print quality, the drying temperature cannot exceed the recommended drying temperature."
msgstr ""
msgid "The temperature shall not exceed the filament's heat distortion temperature"
msgstr ""
msgid "Minimum time value cannot be less than 1."
msgstr ""
msgid "Maximum time value cannot be greater than 24."
msgstr ""
msgid "Insufficient power"
msgstr ""
msgid " Too many AMS drying simultaneously. Please plug in the power or stop other drying processes before starting."
msgstr ""
msgid "AMS is busy"
msgstr ""
msgid " AMS is calibrating | reading RFID | loading/unloading material, please wait."
msgstr ""
msgid "Filament in AMS outlet"
msgstr ""
msgid " The high drying temperature may cause AMS blockage, please unload first."
msgstr ""
msgid "Initiating AMS drying"
msgstr ""
msgid "Not supported in 2D mode"
msgstr ""
msgid "Task in progress"
msgstr ""
msgid " The AMS might be in use during Task."
msgstr ""
msgid " Firmware update in progress, please wait..."
msgstr ""
msgid " Please plug in the power and then use the drying function."
msgstr ""
msgid " The high drying temperature may cause AMS blockage. Please unload the filament manually before proceeding."
msgstr ""
msgid "System is busy"
msgstr ""
msgid " Initiating other drying processes, please wait a few seconds..."
msgstr ""
msgid "For better drying results, remove the filament and allow it to rotate."
msgstr ""
msgid "The AMS will automatically rotate the stored filament slots to enhance the drying performance."
msgstr ""
msgid "Alternatively, you can dry the filament without removing it."
msgstr ""
msgid "Unknown filaments will be treated as PLA."
msgstr ""
msgid "Please store the filament marked with an exclamation mark."
msgstr ""
msgid "Filament left in the feeder during drying may soften because the drying temperature exceeds the softening point of materials like PLA and TPU."
msgstr ""
msgid "Starting: Checking adapter connection"
msgstr ""
msgid "Starting: Checking filament status"
msgstr ""
msgid "Starting: Checking drying presets"
msgstr ""
msgid "Starting: Checking filament location"
msgstr ""
msgid "Starting: Checking air intake"
msgstr ""
msgid "Starting: Checking air vent"
msgstr ""
msgid "The filament may not be compatible with the current machine settings. Generic filament presets will be used."
msgstr ""
@@ -20186,6 +20462,12 @@ msgstr ""
"Tránh cong vênh\n"
"Bạn có biết rằng khi in vật liệu dễ cong vênh như ABS, tăng nhiệt độ bàn nóng một cách thích hợp có thể giảm xác suất cong vênh không?"
#~ msgid "°C"
#~ msgstr "°C"
#~ msgid "%"
#~ msgstr "%"
#~ msgctxt "Sync_Nozzle_AMS"
#~ msgid "Cancel"
#~ msgstr "Hủy"

View File

@@ -6,7 +6,7 @@ msgid ""
msgstr ""
"Project-Id-Version: Slic3rPE\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-07-13 16:24-0300\n"
"POT-Creation-Date: 2026-07-17 15:13-0300\n"
"PO-Revision-Date: 2026-06-11 12:37-0300\n"
"Last-Translator: Handle <mail@bysb.net>\n"
"Language-Team: \n"
@@ -1980,6 +1980,17 @@ msgstr "已经是最新版本。"
msgid "Info"
msgstr "信息"
msgid "Loading Plugins"
msgstr ""
#, c-format, boost-format
msgid "Plugin %s is no longer available."
msgstr ""
#, c-format, boost-format
msgid "Plugin %s access is unauthorized."
msgstr ""
msgid "Loading printer & filament profiles"
msgstr "正在加载打印机和耗材配置文件"
@@ -2099,6 +2110,18 @@ msgstr ""
msgid "Resolve cloud sync conflict"
msgstr "解决云同步冲突"
msgid "Syncing your account…"
msgstr ""
msgid "Migrating presets…"
msgstr ""
msgid "Fetching plugins…"
msgstr ""
msgid "Loading user presets…"
msgstr ""
msgid "Retrieving printer information, please try again later."
msgstr "正在获取打印机信息,请稍后重试。"
@@ -2229,6 +2252,21 @@ msgstr ""
msgid "*"
msgstr "*"
msgid "Plugins"
msgstr ""
#, c-format, boost-format
msgid ""
"Failed to open the Plugins dialog:\n"
"%s"
msgstr ""
msgid "Failed to open the Plugins dialog (unknown error)."
msgstr ""
msgid "Plugin Terminal"
msgstr ""
msgid "Changing application language"
msgstr "正在为应用程序切换语言"
@@ -5036,6 +5074,28 @@ msgstr "无效格式,应该是\"%1%\"这种数组格式"
msgid "N/A"
msgstr "不适用"
msgid "System agents"
msgstr ""
msgid "No plugin selected"
msgstr ""
msgid "Add plugin"
msgstr ""
msgid "Select plugin"
msgstr ""
msgid "Remove plugin"
msgstr ""
msgid "Configure"
msgstr ""
#, c-format, boost-format
msgid "Configure (%d)"
msgstr ""
msgid "Pick"
msgstr "选择"
@@ -5201,9 +5261,6 @@ msgstr "流量"
msgid "Fan speed"
msgstr "风扇速度"
msgid "°C"
msgstr "°C"
msgid "Time"
msgstr "时间"
@@ -7225,6 +7282,14 @@ msgctxt "Layers"
msgid "Bottom"
msgstr "底部"
msgid "Plugin Selection"
msgstr ""
msgid ""
"No plugins capabilities available for this type.\n"
"Enable or install some to use."
msgstr ""
msgid "Enable detection of build plate position"
msgstr "启用打印板位置检测"
@@ -8123,6 +8188,40 @@ msgstr "设备页面"
msgid "Synchronize AMS Filament Information"
msgstr "同步 AMS 耗材丝信息"
msgid "OrcaCloud plugins required by the current preset are not installed:"
msgstr ""
msgid "Install Plugins"
msgstr ""
msgid "Local plugins required by the current preset are missing:"
msgstr ""
msgid "Find on OrcaCloud"
msgstr ""
msgid "Plugins required by the current preset are not activated:"
msgstr ""
msgid "Activate Now"
msgstr ""
msgid "The installed plugin does not provide the required capability — it may be outdated:"
msgstr ""
msgid "Preparing to install plugins..."
msgstr ""
msgid "Installing plugins"
msgstr ""
msgid "Cancelling — finishing the current plugin..."
msgstr ""
#, boost-format
msgid "Installing %1%..."
msgstr ""
msgid "Plate Settings"
msgstr "盘参数设置"
@@ -9190,6 +9289,9 @@ msgstr "多色外置"
msgid "Your filament grouping method in the sliced file is not optimal."
msgstr "您在切片文件中的耗材丝分组方法不是最佳的。"
msgid "To ensure print quality, the drying temperature will be lowered during printing."
msgstr ""
msgid "Auto Bed Leveling"
msgstr "自动床调平"
@@ -9920,6 +10022,12 @@ msgstr "挤出类型更换G-code"
msgid "Post-processing Scripts"
msgstr "后处理脚本"
msgid "Slicing Pipeline Plugin"
msgstr ""
msgid "Plugin Configuration"
msgstr ""
msgid "Notes"
msgstr "注释"
@@ -11070,6 +11178,9 @@ msgstr "切换对象/零件的可打印状态"
msgid "Switch between Prepare/Preview"
msgstr "准备/预览之间的切换"
msgid "Open actions speed dial"
msgstr ""
msgid "Plater"
msgstr "准备"
@@ -11937,6 +12048,9 @@ msgstr "API秘钥"
msgid "HTTP digest"
msgstr "HTTP摘要"
msgid "Configuration for the plugin capabilities this preset uses, overriding the global Capabilities configuration. Stored as a raw JSON array and edited through the dialog behind the button, never typed in directly."
msgstr ""
msgid "Avoid crossing walls"
msgstr "避免跨越外墙"
@@ -12940,6 +13054,24 @@ msgstr ""
"此功能是为了美观或功能性目的,而是为了解决过量挤出等问题。\n"
"警告:降低此值会对热床粘接力产生负面影响。"
msgid "Top surface fill order"
msgstr ""
msgid ""
"Direction in which top surfaces are filled when using a center-based pattern (Concentric, Archimedean Chords, Octagram Spiral).\n"
"Outward starts at the center of the surface, so any excess material is pushed towards the edge where it is least visible. Inward starts at the edge and ends with the tight curves at the center.\n"
"Default uses shortest-path ordering, which may run in either direction."
msgstr ""
msgid "Bottom surface fill order"
msgstr ""
msgid ""
"Direction in which bottom surfaces are filled when using a center-based pattern (Concentric, Archimedean Chords, Octagram Spiral).\n"
"Inward starts each surface with the wider outer curves, which improves first layer adhesion on build plates where the tight curves at the center may not stick. Outward starts at the center, pushing any excess material towards the edge.\n"
"Default uses shortest-path ordering, which may run in either direction."
msgstr ""
msgid "Internal solid infill pattern"
msgstr "内部实心填充图案"
@@ -14204,9 +14336,6 @@ msgstr ""
"如果您的固件已经在低于某阈值时禁用风扇(例如 Klipper 的 [fan] off_below: 0.10 会在指令占空比低于 10% 时关闭风扇),那么此选项与固件阈值最好设置为相同的值。使二者匹配(例如 Klipper 中 off_below: 0.10、此处为 10%)可确保切片软件绝不会发出会被固件悄然丢弃的非零值,且风扇绝不会收到低于其实际可启动转速的值。\n"
"设置为 0 以停用。"
msgid "%"
msgstr "%"
msgid "Time cost"
msgstr "耗时"
@@ -14905,6 +15034,9 @@ msgstr ""
"要禁用输入整形,请使用“禁用”类型。\n"
"RRFX 和 Y 的值相等。"
msgid "Hz"
msgstr "赫兹"
msgid "Y"
msgstr "Y"
@@ -15188,6 +15320,15 @@ msgstr "挤出类型更换 G-code工艺"
msgid "This G-code is inserted when the extrusion role is changed. It runs after the machine and filament extrusion role G-code."
msgstr "当挤出类型发生变化时插入此 G-code。它在机器和耗材的挤出类型更换 G-code 之后运行。"
msgid "Plugins Used"
msgstr ""
msgid "Plugin capabilities referenced by this preset, stored as name;uuid;capability."
msgstr ""
msgid "Python plugin(s) invoked at each slicing pipeline step to read and modify intermediate slicing data, including a final G-code post-processing step. Research/experimental."
msgstr ""
msgid "Printer type"
msgstr "打印机类型"
@@ -15256,6 +15397,15 @@ msgstr "擦拭前的回抽量"
msgid "This is the length of fast retraction before a wipe, relative to retraction length."
msgstr "擦拭之前的回抽长度,用总回抽长度的百分比表示。"
msgid "Retract amount after wipe"
msgstr ""
#, c-format
msgid ""
"The length of fast retraction after wipe, relative to retraction length.\n"
"The value will be clamped by 100% minus the retract amount before the wipe value."
msgstr ""
# TODO: Review, changed by lang refactor. PR 14254
msgid "Retract on layer change"
msgstr "换层时回抽"
@@ -16269,16 +16419,6 @@ msgstr "顶部壳体厚度"
msgid "The number of top solid layers is increased when slicing if the thickness calculated by top shell layers is thinner than this value. This can avoid having too thin a shell when layer height is small. 0 means that this setting is disabled and thickness of top shell is determined simply by the number of top shell layers."
msgstr "如果由顶部壳体层数算出的厚度小于这个数值那么切片时将自动增加顶部壳体层数。这能够避免当层高很小时顶部壳体过薄。0 表示关闭这个设置,同时顶部壳体的厚度完全由顶部壳体层数决定"
msgid "Anisotropic surfaces"
msgstr ""
msgid ""
"Anisotropic patterns on the top and bottom surfaces.\n"
"Co-directional printing mode will be applied. For certain patterns, omni-directional filling provides color dispersion when using multi-colored or silk plastics.\n"
"This option disable the gap fill.\n"
"This option can increase a printing time."
msgstr ""
msgid "Separated infills"
msgstr ""
@@ -18112,9 +18252,6 @@ msgstr "开始 / 结束"
msgid "Frequency settings"
msgstr "频率设置"
msgid "Hz"
msgstr "赫兹"
msgid "RepRap firmware uses the same frequency range for both axes."
msgstr "RepRap 固件将对两个轴使用相同的频率范围。"
@@ -20103,6 +20240,145 @@ msgstr "存档预览"
msgid "Open File"
msgstr "打开文件"
msgid "AMS Dryness Control"
msgstr ""
msgid "Filament Drying Settings"
msgstr ""
msgid "Stopping"
msgstr ""
msgid "Unable to dry temporarily due to ..."
msgstr ""
msgid "Drying Error"
msgstr ""
msgid "Please check the Assistant for troubleshooting"
msgstr ""
msgid "Please remove and store the filament (as shown)."
msgstr ""
msgid "The AMS can rotate the filament which is properly stored, providing better drying results."
msgstr ""
msgid "Rotate spool when drying"
msgstr ""
msgctxt "amsdrying"
msgid "Back"
msgstr ""
msgid "Drying-Heating"
msgstr ""
msgid "Drying-Dehumidifying"
msgstr ""
msgid " maximum drying temperature is "
msgstr ""
msgid " minimum drying temperature is "
msgstr ""
msgid "This filament may not be completely dried."
msgstr ""
msgid "This AMS is currently printing. To ensure print quality, the drying temperature cannot exceed the recommended drying temperature."
msgstr ""
msgid "The temperature shall not exceed the filament's heat distortion temperature"
msgstr ""
msgid "Minimum time value cannot be less than 1."
msgstr ""
msgid "Maximum time value cannot be greater than 24."
msgstr ""
msgid "Insufficient power"
msgstr ""
msgid " Too many AMS drying simultaneously. Please plug in the power or stop other drying processes before starting."
msgstr ""
msgid "AMS is busy"
msgstr ""
msgid " AMS is calibrating | reading RFID | loading/unloading material, please wait."
msgstr ""
msgid "Filament in AMS outlet"
msgstr ""
msgid " The high drying temperature may cause AMS blockage, please unload first."
msgstr ""
msgid "Initiating AMS drying"
msgstr ""
msgid "Not supported in 2D mode"
msgstr ""
msgid "Task in progress"
msgstr ""
msgid " The AMS might be in use during Task."
msgstr ""
msgid " Firmware update in progress, please wait..."
msgstr ""
msgid " Please plug in the power and then use the drying function."
msgstr ""
msgid " The high drying temperature may cause AMS blockage. Please unload the filament manually before proceeding."
msgstr ""
msgid "System is busy"
msgstr ""
msgid " Initiating other drying processes, please wait a few seconds..."
msgstr ""
msgid "For better drying results, remove the filament and allow it to rotate."
msgstr ""
msgid "The AMS will automatically rotate the stored filament slots to enhance the drying performance."
msgstr ""
msgid "Alternatively, you can dry the filament without removing it."
msgstr ""
msgid "Unknown filaments will be treated as PLA."
msgstr ""
msgid "Please store the filament marked with an exclamation mark."
msgstr ""
msgid "Filament left in the feeder during drying may soften because the drying temperature exceeds the softening point of materials like PLA and TPU."
msgstr ""
msgid "Starting: Checking adapter connection"
msgstr ""
msgid "Starting: Checking filament status"
msgstr ""
msgid "Starting: Checking drying presets"
msgstr ""
msgid "Starting: Checking filament location"
msgstr ""
msgid "Starting: Checking air intake"
msgstr ""
msgid "Starting: Checking air vent"
msgstr ""
msgid "The filament may not be compatible with the current machine settings. Generic filament presets will be used."
msgstr "此耗材可能于当前设备设置不兼容,将使用通用耗材预设。"
@@ -20427,6 +20703,12 @@ msgstr ""
"避免翘曲\n"
"您知道吗打印ABS这类易翘曲材料时适当提高热床温度可以降低翘曲的概率。"
#~ msgid "°C"
#~ msgstr "°C"
#~ msgid "%"
#~ msgstr "%"
#~ msgid "Renders cast shadows on the plate in realistic view."
#~ msgstr "在写实渲染中渲染投射到打印板上的阴影。"

View File

@@ -9,7 +9,7 @@ msgid ""
msgstr ""
"Project-Id-Version: Orca Slicer\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-07-13 16:24-0300\n"
"POT-Creation-Date: 2026-07-17 15:13-0300\n"
"PO-Revision-Date: 2025-11-28 13:48-0600\n"
"Last-Translator: tntchn <15895303+tntchn@users.noreply.github.com>\n"
"Language-Team: \n"
@@ -1982,6 +1982,17 @@ msgstr "已經是最新版本。"
msgid "Info"
msgstr "資訊"
msgid "Loading Plugins"
msgstr ""
#, c-format, boost-format
msgid "Plugin %s is no longer available."
msgstr ""
#, c-format, boost-format
msgid "Plugin %s access is unauthorized."
msgstr ""
msgid "Loading printer & filament profiles"
msgstr "載入列印設備與線材設定檔"
@@ -2101,6 +2112,18 @@ msgstr ""
msgid "Resolve cloud sync conflict"
msgstr "解決雲端同步衝突"
msgid "Syncing your account…"
msgstr ""
msgid "Migrating presets…"
msgstr ""
msgid "Fetching plugins…"
msgstr ""
msgid "Loading user presets…"
msgstr ""
msgid "Retrieving printer information, please try again later."
msgstr "正在取得列印設備資訊,請稍後再試。"
@@ -2231,6 +2254,21 @@ msgstr ""
msgid "*"
msgstr "*"
msgid "Plugins"
msgstr ""
#, c-format, boost-format
msgid ""
"Failed to open the Plugins dialog:\n"
"%s"
msgstr ""
msgid "Failed to open the Plugins dialog (unknown error)."
msgstr ""
msgid "Plugin Terminal"
msgstr ""
msgid "Changing application language"
msgstr "正在為應用程式切換語言"
@@ -5078,6 +5116,28 @@ msgstr "無效格式,應該是「%1%」這種格式"
msgid "N/A"
msgstr "不適用"
msgid "System agents"
msgstr ""
msgid "No plugin selected"
msgstr ""
msgid "Add plugin"
msgstr ""
msgid "Select plugin"
msgstr ""
msgid "Remove plugin"
msgstr ""
msgid "Configure"
msgstr ""
#, c-format, boost-format
msgid "Configure (%d)"
msgstr ""
msgid "Pick"
msgstr "選取"
@@ -5243,9 +5303,6 @@ msgstr "流量"
msgid "Fan speed"
msgstr "風扇速度"
msgid "°C"
msgstr "°C"
msgid "Time"
msgstr "時間"
@@ -7277,6 +7334,14 @@ msgctxt "Layers"
msgid "Bottom"
msgstr "底部"
msgid "Plugin Selection"
msgstr ""
msgid ""
"No plugins capabilities available for this type.\n"
"Enable or install some to use."
msgstr ""
msgid "Enable detection of build plate position"
msgstr "啟用列印板位置偵測"
@@ -8178,6 +8243,40 @@ msgstr "設備頁面"
msgid "Synchronize AMS Filament Information"
msgstr "同步 AMS 線材資訊"
msgid "OrcaCloud plugins required by the current preset are not installed:"
msgstr ""
msgid "Install Plugins"
msgstr ""
msgid "Local plugins required by the current preset are missing:"
msgstr ""
msgid "Find on OrcaCloud"
msgstr ""
msgid "Plugins required by the current preset are not activated:"
msgstr ""
msgid "Activate Now"
msgstr ""
msgid "The installed plugin does not provide the required capability — it may be outdated:"
msgstr ""
msgid "Preparing to install plugins..."
msgstr ""
msgid "Installing plugins"
msgstr ""
msgid "Cancelling — finishing the current plugin..."
msgstr ""
#, boost-format
msgid "Installing %1%..."
msgstr ""
msgid "Plate Settings"
msgstr "列印板參數設定"
@@ -9252,6 +9351,9 @@ msgstr "使用外部料盤進行多色列印"
msgid "Your filament grouping method in the sliced file is not optimal."
msgstr "切片檔案中的線材分組方式不是最佳選擇。"
msgid "To ensure print quality, the drying temperature will be lowered during printing."
msgstr ""
msgid "Auto Bed Leveling"
msgstr "自動熱床調平"
@@ -9982,6 +10084,12 @@ msgstr "變更擠出機任務的 G-code"
msgid "Post-processing Scripts"
msgstr "後處理腳本"
msgid "Slicing Pipeline Plugin"
msgstr ""
msgid "Plugin Configuration"
msgstr ""
msgid "Notes"
msgstr "備註"
@@ -11131,6 +11239,9 @@ msgstr "切換物件/零件的可列印屬性"
msgid "Switch between Prepare/Preview"
msgstr "在準備/預覽模式之中切換"
msgid "Open actions speed dial"
msgstr ""
msgid "Plater"
msgstr "準備"
@@ -11998,6 +12109,9 @@ msgstr "API 金鑰"
msgid "HTTP digest"
msgstr "HTTP 摘要"
msgid "Configuration for the plugin capabilities this preset uses, overriding the global Capabilities configuration. Stored as a raw JSON array and edited through the dialog behind the button, never typed in directly."
msgstr ""
msgid "Avoid crossing walls"
msgstr "避免跨越外牆"
@@ -13006,6 +13120,24 @@ msgstr ""
"底面層的密度。此功能旨在實現美觀或功能需求,而非修正過擠等問題。\n"
"警告:降低此數值可能會對熱床附著力產生負面影響"
msgid "Top surface fill order"
msgstr ""
msgid ""
"Direction in which top surfaces are filled when using a center-based pattern (Concentric, Archimedean Chords, Octagram Spiral).\n"
"Outward starts at the center of the surface, so any excess material is pushed towards the edge where it is least visible. Inward starts at the edge and ends with the tight curves at the center.\n"
"Default uses shortest-path ordering, which may run in either direction."
msgstr ""
msgid "Bottom surface fill order"
msgstr ""
msgid ""
"Direction in which bottom surfaces are filled when using a center-based pattern (Concentric, Archimedean Chords, Octagram Spiral).\n"
"Inward starts each surface with the wider outer curves, which improves first layer adhesion on build plates where the tight curves at the center may not stick. Outward starts at the center, pushing any excess material towards the edge.\n"
"Default uses shortest-path ordering, which may run in either direction."
msgstr ""
msgid "Internal solid infill pattern"
msgstr "內部實心填充圖案"
@@ -14255,9 +14387,6 @@ msgstr ""
"如果您的韌體已經在低於某個閾值時停用風扇(例如 Klipper 的 [fan] off_below: 0.10 會在指令工作週期低於 10% 時關閉風扇),則此選項與韌體閾值最好設定為相同的值。讓兩者相符(例如 Klipper 中的 off_below: 0.10 與此處的 10%)可確保切片軟體永遠不會發出韌體會默默捨棄的非零值,且風扇永遠不會收到低於您已知它實際能啟動轉動的值。\n"
"設定為 0 以停用。"
msgid "%"
msgstr "%"
msgid "Time cost"
msgstr "時間成本"
@@ -14960,6 +15089,9 @@ msgstr ""
"若要停用輸入整形,請使用 Disable 類型。\n"
"RRFX 與 Y 值相等。"
msgid "Hz"
msgstr "赫茲"
msgid "Y"
msgstr "Y"
@@ -15249,6 +15381,15 @@ msgstr "變更擠出模式 G-code列印參數"
msgid "This G-code is inserted when the extrusion role is changed. It runs after the machine and filament extrusion role G-code."
msgstr "此 G-code 會在擠出模式變更時插入。它會在機器和線材擠出模式 G-code 之後執行。"
msgid "Plugins Used"
msgstr ""
msgid "Plugin capabilities referenced by this preset, stored as name;uuid;capability."
msgstr ""
msgid "Python plugin(s) invoked at each slicing pipeline step to read and modify intermediate slicing data, including a final G-code post-processing step. Research/experimental."
msgstr ""
msgid "Printer type"
msgstr "列印設備類型"
@@ -15317,6 +15458,15 @@ msgstr "擦拭前的回抽量"
msgid "This is the length of fast retraction before a wipe, relative to retraction length."
msgstr "擦拭之前的回抽長度,用總回抽長度的百分比表示"
msgid "Retract amount after wipe"
msgstr ""
#, c-format
msgid ""
"The length of fast retraction after wipe, relative to retraction length.\n"
"The value will be clamped by 100% minus the retract amount before the wipe value."
msgstr ""
# TODO: Review, changed by lang refactor. PR 14254
msgid "Retract on layer change"
msgstr "換層時回抽"
@@ -16317,16 +16467,6 @@ msgstr "頂部外殼厚度"
msgid "The number of top solid layers is increased when slicing if the thickness calculated by top shell layers is thinner than this value. This can avoid having too thin a shell when layer height is small. 0 means that this setting is disabled and thickness of top shell is determined simply by the number of top shell layers."
msgstr "當切片時,如果通過頂部殼層計算的厚度小於設定值,將自動增加頂部實心層的數量,以避免層高較小時頂部殼層過薄。若設為 0則停用此功能頂部殼層厚度完全由設定的頂部殼層數決定"
msgid "Anisotropic surfaces"
msgstr ""
msgid ""
"Anisotropic patterns on the top and bottom surfaces.\n"
"Co-directional printing mode will be applied. For certain patterns, omni-directional filling provides color dispersion when using multi-colored or silk plastics.\n"
"This option disable the gap fill.\n"
"This option can increase a printing time."
msgstr ""
msgid "Separated infills"
msgstr ""
@@ -18156,9 +18296,6 @@ msgstr "開始 / 結束"
msgid "Frequency settings"
msgstr "頻率設定"
msgid "Hz"
msgstr "赫茲"
msgid "RepRap firmware uses the same frequency range for both axes."
msgstr "RepRap 韌體對兩個軸使用相同的頻率範圍。"
@@ -20153,6 +20290,145 @@ msgstr "封存預覽"
msgid "Open File"
msgstr "開啟檔案"
msgid "AMS Dryness Control"
msgstr ""
msgid "Filament Drying Settings"
msgstr ""
msgid "Stopping"
msgstr ""
msgid "Unable to dry temporarily due to ..."
msgstr ""
msgid "Drying Error"
msgstr ""
msgid "Please check the Assistant for troubleshooting"
msgstr ""
msgid "Please remove and store the filament (as shown)."
msgstr ""
msgid "The AMS can rotate the filament which is properly stored, providing better drying results."
msgstr ""
msgid "Rotate spool when drying"
msgstr ""
msgctxt "amsdrying"
msgid "Back"
msgstr ""
msgid "Drying-Heating"
msgstr ""
msgid "Drying-Dehumidifying"
msgstr ""
msgid " maximum drying temperature is "
msgstr ""
msgid " minimum drying temperature is "
msgstr ""
msgid "This filament may not be completely dried."
msgstr ""
msgid "This AMS is currently printing. To ensure print quality, the drying temperature cannot exceed the recommended drying temperature."
msgstr ""
msgid "The temperature shall not exceed the filament's heat distortion temperature"
msgstr ""
msgid "Minimum time value cannot be less than 1."
msgstr ""
msgid "Maximum time value cannot be greater than 24."
msgstr ""
msgid "Insufficient power"
msgstr ""
msgid " Too many AMS drying simultaneously. Please plug in the power or stop other drying processes before starting."
msgstr ""
msgid "AMS is busy"
msgstr ""
msgid " AMS is calibrating | reading RFID | loading/unloading material, please wait."
msgstr ""
msgid "Filament in AMS outlet"
msgstr ""
msgid " The high drying temperature may cause AMS blockage, please unload first."
msgstr ""
msgid "Initiating AMS drying"
msgstr ""
msgid "Not supported in 2D mode"
msgstr ""
msgid "Task in progress"
msgstr ""
msgid " The AMS might be in use during Task."
msgstr ""
msgid " Firmware update in progress, please wait..."
msgstr ""
msgid " Please plug in the power and then use the drying function."
msgstr ""
msgid " The high drying temperature may cause AMS blockage. Please unload the filament manually before proceeding."
msgstr ""
msgid "System is busy"
msgstr ""
msgid " Initiating other drying processes, please wait a few seconds..."
msgstr ""
msgid "For better drying results, remove the filament and allow it to rotate."
msgstr ""
msgid "The AMS will automatically rotate the stored filament slots to enhance the drying performance."
msgstr ""
msgid "Alternatively, you can dry the filament without removing it."
msgstr ""
msgid "Unknown filaments will be treated as PLA."
msgstr ""
msgid "Please store the filament marked with an exclamation mark."
msgstr ""
msgid "Filament left in the feeder during drying may soften because the drying temperature exceeds the softening point of materials like PLA and TPU."
msgstr ""
msgid "Starting: Checking adapter connection"
msgstr ""
msgid "Starting: Checking filament status"
msgstr ""
msgid "Starting: Checking drying presets"
msgstr ""
msgid "Starting: Checking filament location"
msgstr ""
msgid "Starting: Checking air intake"
msgstr ""
msgid "Starting: Checking air vent"
msgstr ""
msgid "The filament may not be compatible with the current machine settings. Generic filament presets will be used."
msgstr "線材可能與目前的列印設備設定不相容,將使用一般線材預設。"
@@ -20498,6 +20774,12 @@ msgstr ""
"您知道嗎?當列印容易翹曲的材料(如 ABS適當提高熱床溫度\n"
"可以降低翹曲的機率。"
#~ msgid "°C"
#~ msgstr "°C"
#~ msgid "%"
#~ msgstr "%"
#~ msgid "Renders cast shadows on the plate in realistic view."
#~ msgstr "在擬真檢視中於列印板上算繪投射陰影。"

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,323 @@
{
"result": 0,
"t": 1765968095,
"ver": 202511162200,
"data": [
{
"ecode": "03008041",
"image": "",
"actions": [
4,
6
],
"device": "26A"
},
{
"ecode": "03008060",
"image": "",
"actions": [
22
],
"device": "26A"
},
{
"ecode": "12008010",
"image": "c31daf51b36e446698f14c6df879ea21.png",
"actions": [
6,
4
],
"device": "26A"
},
{
"ecode": "12FF8010",
"image": "f87557495f2f2163a44bde8f4ddd9b8c.png",
"actions": [
4,
6
],
"device": "26A"
},
{
"ecode": "18008016",
"image": "",
"actions": [
4,
6
],
"device": "26A"
},
{
"ecode": "07008016",
"image": "",
"actions": [
4,
6
],
"device": "26A"
},
{
"ecode": "07018016",
"image": "",
"actions": [
4,
6
],
"device": "26A"
},
{
"ecode": "03002E0000030001",
"image": "",
"actions": [
52
],
"device": "26A"
},
{
"ecode": "03004016",
"image": "",
"actions": [
6
],
"device": "26A"
},
{
"ecode": "03008019",
"image": "",
"actions": [
4
],
"device": "default"
},
{
"ecode": "0502C026",
"image": "",
"actions": [
11
],
"device": "default"
},
{
"ecode": "05004003",
"image": "",
"actions": [
11
],
"device": "default"
},
{
"ecode": "05004040",
"image": "",
"actions": [
11
],
"device": "default"
},
{
"ecode": "05004042",
"image": "",
"actions": [
36,
37
],
"device": "default"
},
{
"ecode": "03008000",
"image": "",
"actions": [
2
],
"device": "default"
},
{
"ecode": "0C00402D",
"image": "",
"actions": [
11
],
"device": "default"
},
{
"ecode": "05004037",
"image": "",
"actions": [
11
],
"device": "default"
},
{
"ecode": "05004015",
"image": "",
"actions": [
14
],
"device": "default"
},
{
"ecode": "05004007",
"image": "",
"actions": [
11
],
"device": "default"
},
{
"ecode": "0502C014",
"image": "",
"actions": [
11
],
"device": "default"
},
{
"ecode": "0300800C",
"image": "",
"actions": [
2
],
"device": "default"
},
{
"ecode": "05004004",
"image": "",
"actions": [
11
],
"device": "default"
},
{
"ecode": "0500402E",
"image": "",
"actions": [
14
],
"device": "default"
},
{
"ecode": "05024001",
"image": "",
"actions": [
11
],
"device": "default"
},
{
"ecode": "0502C012",
"image": "",
"actions": [
11
],
"device": "default"
},
{
"ecode": "0502C010",
"image": "",
"actions": [
35
],
"device": "default"
},
{
"ecode": "05008092",
"image": "",
"actions": [
27,
5
],
"device": "default"
},
{
"ecode": "05004014",
"image": "",
"actions": [
11
],
"device": "default"
},
{
"ecode": "0300800D",
"image": "",
"actions": [
2,
6
],
"device": "default"
},
{
"ecode": "0500402F",
"image": "",
"actions": [
14
],
"device": "default"
},
{
"ecode": "05004041",
"image": "",
"actions": [
11
],
"device": "default"
},
{
"ecode": "0500400E",
"image": "",
"actions": [
11
],
"device": "default"
},
{
"ecode": "05004043",
"image": "",
"actions": [
11
],
"device": "default"
},
{
"ecode": "0C00402C",
"image": "",
"actions": [
11
],
"device": "default"
},
{
"ecode": "03008017",
"image": "",
"actions": [
4
],
"device": "default"
},
{
"ecode": "03008013",
"image": "",
"actions": [
2
],
"device": "default"
},
{
"ecode": "03008007",
"image": "",
"actions": [
2,
5
],
"device": "default"
},
{
"ecode": "03008016",
"image": "",
"actions": [
4,
5,
6
],
"device": "default"
}
]
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

22217
resources/hms/hms_de_20P.json Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

19557
resources/hms/hms_de_26A.json Normal file

File diff suppressed because it is too large Load Diff

23353
resources/hms/hms_de_31B.json Normal file

File diff suppressed because it is too large Load Diff

Some files were not shown because too many files have changed in this diff Show More