python_ffi_dart 0.4.4 copy "python_ffi_dart: ^0.4.4" to clipboard
python_ffi_dart: ^0.4.4 copied to clipboard

A Python-FFI for Dart, intended for Dart-only applications outside of a Flutter project.

example/lib/python_ffi_dart_example.dart

import "dart:typed_data";

import "package:collection/collection.dart";
import "package:python_ffi_dart/python_ffi_dart.dart";
import "package:python_ffi_dart_example/python_modules/eq_test.g.dart";
import "package:python_ffi_dart_example/python_modules/type_mappings.g.dart";

typedef SendTyPythonCallback<T> = void Function({required T value});
typedef ReceiveFromPythonCallback<T> = T Function();

class TypeMappingEntry<T extends Object?> {
  const TypeMappingEntry({
    required this.pythonType,
    required this.value,
    this.dartType,
    this.sendToPython,
    this.receiveFromPython,
    this.equals,
  });

  final String? dartType;
  final String pythonType;
  final T value;
  final SendTyPythonCallback<T>? sendToPython;
  final ReceiveFromPythonCallback<T>? receiveFromPython;
  final bool Function(T, T)? equals;

  String get _dartType => dartType ?? T.toString();

  bool Function(T, T) get _equals => equals ?? (T a, T b) => a == b;

  void run() {
    try {
      print("\ntesting $_dartType ←→ $pythonType");
      final SendTyPythonCallback<T>? sendToPython = this.sendToPython;
      if (sendToPython == null) {
        print("├── dart –> python skipped ⚠️");
      } else {
        sendToPython(value: value);
        print("├── dart –> python successful ✅");
      }

      final ReceiveFromPythonCallback<T>? receiveFromPython =
          this.receiveFromPython;
      if (receiveFromPython == null) {
        print("└── python –> dart skipped ⚠️");
      } else {
        final T receivedValue = receiveFromPython();
        assert(
          _equals(receivedValue, value),
          "Python returned $receivedValue, but expected $value",
        );
        print("└── python –> dart successful ✅");
      }
    } on Exception catch (e) {
      print("└── ❌ error: $e");
    }
  }
}

Future<void> typeMappings() async {
  final type_mappings module = type_mappings.import();

  // ignore: prefer_void_to_null
  TypeMappingEntry<Null>(
    dartType: "null",
    pythonType: "None",
    value: null,
    sendToPython: module.receive_none,
    receiveFromPython: module.request_none,
  ).run();

  TypeMappingEntry<bool>(
    dartType: "true",
    pythonType: "True",
    value: true,
    sendToPython: module.receive_bool_true,
    receiveFromPython: module.request_bool_true,
  ).run();

  TypeMappingEntry<bool>(
    dartType: "false",
    pythonType: "False",
    value: false,
    sendToPython: module.receive_bool_false,
    receiveFromPython: module.request_bool_false,
  ).run();

  TypeMappingEntry<int>(
    pythonType: "int",
    value: 42,
    sendToPython: module.receive_int,
    receiveFromPython: module.request_int,
  ).run();

  TypeMappingEntry<double>(
    pythonType: "float",
    value: 3.14,
    sendToPython: module.receive_float,
    receiveFromPython: module.request_float,
  ).run();

  TypeMappingEntry<String>(
    pythonType: "str",
    value: "Hello World",
    sendToPython: module.receive_str,
    receiveFromPython: module.request_str,
  ).run();

  TypeMappingEntry<Uint8List>(
    pythonType: "bytes",
    value: Uint8List.fromList("Hello World".codeUnits),
    sendToPython: module.receive_bytes,
    receiveFromPython: module.request_bytes,
  ).run();

  TypeMappingEntry<Map<String, int>>(
    pythonType: "dict[str, int]",
    value: const <String, int>{"one": 1, "two": 2, "three": 3},
    sendToPython: module.receive_dict,
    receiveFromPython: module.request_dict,
    equals: const MapEquality<String, int>().equals,
  ).run();

  TypeMappingEntry<List<int>>(
    pythonType: "list[int]",
    value: const <int>[1, 2, 3],
    sendToPython: module.receive_list,
    receiveFromPython: module.request_list,
    equals: (List<int> a, List<int> b) =>
        const ListEquality<int>().equals(a, b),
  ).run();

  TypeMappingEntry<List<int>>(
    pythonType: "tuple[int]",
    value: const <int>[1, 2, 3],
    receiveFromPython: module.request_tuple,
    equals: (List<int> a, List<int> b) =>
        const ListEquality<int>().equals(a, b),
  ).run();

  TypeMappingEntry<PythonTuple<int>>(
    pythonType: "tuple[int]",
    value: PythonTuple<int>.from(
      <int>[1, 2, 3],
    ),
    sendToPython: module.receive_tuple,
    equals: (PythonTuple<int> a, PythonTuple<int> b) =>
        const ListEquality<int>().equals(a, b),
  ).run();

  TypeMappingEntry<Set<int>>(
    pythonType: "set[int]",
    value: const <int>{1, 2, 3},
    sendToPython: module.receive_set,
    receiveFromPython: module.request_set,
    equals: const SetEquality<int>().equals,
  ).run();

  Iterable<int> iterable() sync* {
    yield 1;
    yield 2;
    yield 3;
  }

  TypeMappingEntry<Iterable<int>>(
    pythonType: "iterable[int]",
    value: iterable(),
    sendToPython: module.receive_iterable,
    receiveFromPython: module.request_iterable,
    equals: const IterableEquality<int>().equals,
  ).run();

  TypeMappingEntry<Iterator<int>>(
    pythonType: "iterator[int]",
    value: iterable().iterator,
    sendToPython: module.receive_iterator,
    receiveFromPython: module.request_iterator,
    equals: (Iterator<int> a, Iterator<int> b) {
      while (a.moveNext()) {
        if (!b.moveNext()) {
          return false;
        }
        if (a.current != b.current) {
          return false;
        }
      }
      return !b.moveNext();
    },
  ).run();

  TypeMappingEntry<Iterator<int>>(
    pythonType: "generator[int]",
    value: iterable().iterator,
    receiveFromPython: module.request_generator,
    equals: (Iterator<int> a, Iterator<int> b) {
      while (a.moveNext()) {
        if (!b.moveNext()) {
          return false;
        }
        if (a.current != b.current) {
          return false;
        }
      }
      return !b.moveNext();
    },
  ).run();

  TypeMappingEntry<int Function(int)>(
    pythonType: "Callable[[int], int]",
    value: (int x) {
      assert(x == 1, "Expected 1, but got $x");
      return 2;
    },
    sendToPython: module.receive_callable,
    receiveFromPython: module.request_callable,
    equals: (int Function(int) a, int Function(int) b) => a(1) == b(1),
  ).run();
}

void _expectEqTest(Object? a, Object? b, {required bool expected}) {
  try {
    print("\ntesting $a == $b, expecting $expected");
    final bool result = a == b;
    if (result == expected) {
      print("└── successful ✅");
    } else {
      print("└── ❌ failed");
    }
  } on Exception catch (e) {
    print("└── ❌ error: $e");
  }
}

Future<void> eqTest() async {
  final HasEq hasEq1 = HasEq(a: 0);
  final HasEq hasEq2 = HasEq(a: 0);
  final HasEq hasEq3 = HasEq(a: 1);
  final NoEq noEq1 = NoEq(a: 0);
  final NoEq noEq2 = NoEq(a: 0);
  final NoEq noEq3 = NoEq(a: 1);

  _expectEqTest(hasEq1, hasEq1, expected: true);
  _expectEqTest(hasEq2, hasEq2, expected: true);
  _expectEqTest(hasEq3, hasEq3, expected: true);

  _expectEqTest(hasEq1, hasEq2, expected: true);
  _expectEqTest(hasEq2, hasEq1, expected: true);

  _expectEqTest(hasEq1, hasEq3, expected: false);
  _expectEqTest(hasEq3, hasEq1, expected: false);
  _expectEqTest(hasEq2, hasEq3, expected: false);
  _expectEqTest(hasEq3, hasEq2, expected: false);

  _expectEqTest(noEq1, noEq1, expected: true);
  _expectEqTest(noEq2, noEq2, expected: true);
  _expectEqTest(noEq3, noEq3, expected: true);

  _expectEqTest(noEq1, noEq2, expected: false);
  _expectEqTest(noEq2, noEq1, expected: false);

  _expectEqTest(noEq1, noEq3, expected: false);
  _expectEqTest(noEq3, noEq1, expected: false);
  _expectEqTest(noEq2, noEq3, expected: false);
  _expectEqTest(noEq3, noEq2, expected: false);

  _expectEqTest(hasEq1, noEq1, expected: false);
  _expectEqTest(noEq1, hasEq1, expected: false);
  _expectEqTest(hasEq2, noEq2, expected: false);
  _expectEqTest(noEq2, hasEq2, expected: false);
  _expectEqTest(hasEq3, noEq3, expected: false);
  _expectEqTest(noEq3, hasEq3, expected: false);
}
4
likes
150
points
160
downloads

Publisher

verified publisherivlivs.dev

Weekly Downloads

A Python-FFI for Dart, intended for Dart-only applications outside of a Flutter project.

Repository (GitHub)

Documentation

API reference

License

BSD-3-Clause (license)

Dependencies

python_ffi_cpython_dart, python_ffi_interface

More

Packages that depend on python_ffi_dart