Skip to content

Commit

Permalink
Python: generate type stubs for all user functions
Browse files Browse the repository at this point in the history
  • Loading branch information
badboy committed Apr 3, 2023
1 parent be03b7e commit 6e62049
Show file tree
Hide file tree
Showing 8 changed files with 40 additions and 29 deletions.
7 changes: 4 additions & 3 deletions uniffi_bindgen/src/bindings/python/gen_python/compounds.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,8 @@ impl SequenceCodeType {
}

impl CodeType for SequenceCodeType {
fn type_label(&self, _oracle: &dyn CodeOracle) -> String {
"list".to_string()
fn type_label(&self, oracle: &dyn CodeOracle) -> String {
format!("list[{}]", self.inner.type_label(oracle))
}

fn canonical_name(&self, oracle: &dyn CodeOracle) -> String {
Expand All @@ -73,8 +73,9 @@ impl CodeType for SequenceCodeType {

fn coerce(&self, oracle: &dyn CodeOracle, nm: &str) -> String {
format!(
"list({} for x in {})",
"list({} for x in cast(list[{}], {}))",
oracle.find(&self.inner).coerce(oracle, "x"),
oracle.find(&self.inner).type_label(oracle),
nm
)
}
Expand Down
34 changes: 19 additions & 15 deletions uniffi_bindgen/src/bindings/python/gen_python/primitives.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,36 +34,40 @@ fn render_literal(_oracle: &dyn CodeOracle, literal: &Literal) -> String {
}

macro_rules! impl_code_type_for_primitive {
($T:ty, $class_name:literal, $coerce_code:expr) => {
($T:ty, $python_name:literal, $canonical_name:literal, $coerce_code:expr) => {
paste! {
pub struct $T;

impl CodeType for $T {
fn type_label(&self, _oracle: &dyn CodeOracle) -> String {
$class_name.into()
$python_name.into()
}

fn canonical_name(&self, _oracle: &dyn CodeOracle) -> String {
$canonical_name.into()
}

fn literal(&self, oracle: &dyn CodeOracle, literal: &Literal) -> String {
render_literal(oracle, &literal)
}

fn coerce(&self, _oracle: &dyn CodeOracle, nm: &str) -> String {
format!($coerce_code, nm)
format!($coerce_code, format!("cast({}, {})", $python_name, nm))
}
}
}
};
}

impl_code_type_for_primitive!(BooleanCodeType, "Bool", "bool({})");
impl_code_type_for_primitive!(StringCodeType, "String", "{}");
impl_code_type_for_primitive!(Int8CodeType, "Int8", "int({})");
impl_code_type_for_primitive!(Int16CodeType, "Int16", "int({})");
impl_code_type_for_primitive!(Int32CodeType, "Int32", "int({})");
impl_code_type_for_primitive!(Int64CodeType, "Int64", "int({})");
impl_code_type_for_primitive!(UInt8CodeType, "UInt8", "int({})");
impl_code_type_for_primitive!(UInt16CodeType, "UInt16", "int({})");
impl_code_type_for_primitive!(UInt32CodeType, "UInt32", "int({})");
impl_code_type_for_primitive!(UInt64CodeType, "UInt64", "int({})");
impl_code_type_for_primitive!(Float32CodeType, "Float", "float({})");
impl_code_type_for_primitive!(Float64CodeType, "Double", "float({})");
impl_code_type_for_primitive!(BooleanCodeType, "bool", "Bool", "bool({})");
impl_code_type_for_primitive!(StringCodeType, "str", "String", "{}");
impl_code_type_for_primitive!(Int8CodeType, "int", "Int8", "int({})");
impl_code_type_for_primitive!(Int16CodeType, "int", "Int16", "int({})");
impl_code_type_for_primitive!(Int32CodeType, "int", "Int32", "int({})");
impl_code_type_for_primitive!(Int64CodeType, "int", "Int64", "int({})");
impl_code_type_for_primitive!(UInt8CodeType, "int", "UInt8", "int({})");
impl_code_type_for_primitive!(UInt16CodeType, "int", "UInt16", "int({})");
impl_code_type_for_primitive!(UInt32CodeType, "int", "UInt32", "int({})");
impl_code_type_for_primitive!(UInt64CodeType, "int", "UInt64", "int({})");
impl_code_type_for_primitive!(Float32CodeType, "float", "Float", "float({})");
impl_code_type_for_primitive!(Float64CodeType, "float", "Double", "float({})");
3 changes: 3 additions & 0 deletions uniffi_bindgen/src/bindings/python/templates/CustomType.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
{%- match python_config.custom_types.get(name.as_str()) %}
{% when None %}
{#- No custom type config, just forward all methods to our builtin type #}
# Type alias
{{ name }} = {{ builtin|type_name }}

class FfiConverterType{{ name }}:
@staticmethod
def write(value, buf):
Expand Down
8 changes: 6 additions & 2 deletions uniffi_bindgen/src/bindings/python/templates/EnumTemplate.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,16 @@ class {{ type_name }}(enum.Enum):
{% else %}

class {{ type_name }}:
{% for variant in e.variants() -%}
{{ variant.name()|enum_variant_py }}: type
{% endfor %}

def __init__(self):
raise RuntimeError("{{ type_name }} cannot be instantiated directly")

# Each enum variant is a nested class of the enum itself.
{% for variant in e.variants() -%}
class {{ variant.name()|enum_variant_py }}(object):
class _{{ variant.name()|enum_variant_py }}(object):
def __init__(self,{% for field in variant.fields() %}{{ field.name()|var_name }}{% if loop.last %}{% else %}, {% endif %}{% endfor %}):
{% if variant.has_fields() %}
{%- for field in variant.fields() %}
Expand Down Expand Up @@ -53,7 +57,7 @@ def is_{{ variant.name()|var_name }}(self):
# enum class, so that method calls and instance checks etc will work intuitively.
# We might be able to do this a little more neatly with a metaclass, but this'll do.
{% for variant in e.variants() -%}
{{ type_name }}.{{ variant.name()|enum_variant_py }} = type("{{ type_name }}.{{ variant.name()|enum_variant_py }}", ({{ type_name }}.{{variant.name()|enum_variant_py}}, {{ type_name }},), {})
{{ type_name }}.{{ variant.name()|enum_variant_py }} = type("{{ type_name }}.{{ variant.name()|enum_variant_py }}", ({{ type_name }}._{{variant.name()|enum_variant_py}}, {{ type_name }},), {})
{% endfor %}

{% endif %}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ def __str__(self):
{%- endif %}
{%- endif %}

{{ type_name }}.{{ variant_type_name }} = {{ variant_type_name }}
{{ type_name }}.{{ variant_type_name }} = {{ variant_type_name }} # type: ignore
{%- endfor %}
{{ type_name }} = UniFFIExceptionTmpNamespace.{{ type_name }}
del UniFFIExceptionTmpNamespace
Expand Down
3 changes: 2 additions & 1 deletion uniffi_bindgen/src/bindings/python/templates/macros.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,9 @@
{%- for arg in func.arguments() -%}
{{ arg.name()|var_name }}
{%- match arg.default_value() %}
{%- when Some with(literal) %} = DEFAULT
{%- when Some with(literal) %}: Union[object, {{ arg|type_name -}}] = DEFAULT
{%- else %}
: {{ arg|type_name -}}
{%- endmatch %}
{%- if !loop.last %},{% endif -%}
{%- endfor %}
Expand Down
6 changes: 1 addition & 5 deletions uniffi_bindgen/src/bindings/python/templates/wrapper.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,6 @@
# This file was autogenerated by some hot garbage in the `uniffi` crate.
# Trust me, you don't want to mess with it!

# Tell mypy (a type checker) to ignore all errors from this file.
# See https://mypy.readthedocs.io/en/stable/config_file.html?highlight=ignore-errors#confval-ignore_errors
# mypy: ignore-errors

# Common helper code.
#
# Ideally this would live in a separate .py file where it can be unittested etc
Expand All @@ -24,11 +20,11 @@
import struct
import contextlib
import datetime
from typing import Union, cast
{%- if ci.has_async_fns() %}
import asyncio
{%- endif %}
import contextvars
import enum
{%- for req in self.imports() %}
{{ req.render() }}
{%- endfor %}
Expand Down
6 changes: 4 additions & 2 deletions uniffi_bindgen/src/interface/types/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,6 @@ pub enum Type {
String,
Timestamp,
Duration,
// Types defined in the component API, each of which has a string name.
Object(String),
Record(String),
Enum(String),
Error(String),
Expand All @@ -75,6 +73,10 @@ pub enum Type {
name: String,
builtin: Box<Type>,
},
// Types defined in the component API, each of which has a string name.
// Defined last, as its functions might reference any other type from above,
// so should be defined last.
Object(String),
}

#[derive(Debug, Clone, Copy, Eq, PartialEq, Checksum, Ord, PartialOrd)]
Expand Down

0 comments on commit 6e62049

Please sign in to comment.