From 41a2892b4fd0b41fe66f283cc1ce2d2258dd4dba Mon Sep 17 00:00:00 2001 From: AndyTitu Date: Tue, 12 Mar 2024 15:46:08 +0100 Subject: [PATCH] Update project structure --- .github/workflows/validate.yml | 2 +- MANIFEST.in | 3 - onepassword/core.py | 14 - .../setup.py | 5 +- .../src}/__init__.py | 0 .../src}/libop_uniffi_core.so | Bin .../src}/op_uniffi_core.py | 0 .../op_uniffi_lib_mac_arm64/__init__.py | 0 .../libop_uniffi_core.dylib | Bin .../op_uniffi_lib_mac_arm64/op_uniffi_core.py | 966 ++++++++++++++++++ op_uniffi_core_mac_arm64/setup.py | 11 + pyproject.toml | 5 - sdk/onepassword/__init__.py | 0 {onepassword => sdk/onepassword}/client.py | 0 sdk/onepassword/core.py | 29 + .../onepassword}/secrets_api.py | 0 .../onepassword}/test_client.py | 0 sdk/setup.py | 14 + 18 files changed, 1022 insertions(+), 27 deletions(-) delete mode 100644 MANIFEST.in delete mode 100644 onepassword/core.py rename setup.py => op_uniffi_core_linux_amd64/setup.py (63%) rename {onepassword => op_uniffi_core_linux_amd64/src}/__init__.py (100%) rename {onepassword => op_uniffi_core_linux_amd64/src}/libop_uniffi_core.so (100%) rename {onepassword => op_uniffi_core_linux_amd64/src}/op_uniffi_core.py (100%) create mode 100644 op_uniffi_core_mac_arm64/op_uniffi_lib_mac_arm64/__init__.py rename {onepassword => op_uniffi_core_mac_arm64/op_uniffi_lib_mac_arm64}/libop_uniffi_core.dylib (100%) create mode 100644 op_uniffi_core_mac_arm64/op_uniffi_lib_mac_arm64/op_uniffi_core.py create mode 100644 op_uniffi_core_mac_arm64/setup.py delete mode 100644 pyproject.toml create mode 100644 sdk/onepassword/__init__.py rename {onepassword => sdk/onepassword}/client.py (100%) create mode 100644 sdk/onepassword/core.py rename {onepassword => sdk/onepassword}/secrets_api.py (100%) rename {onepassword => sdk/onepassword}/test_client.py (100%) create mode 100644 sdk/setup.py diff --git a/.github/workflows/validate.yml b/.github/workflows/validate.yml index 222dedc..0955e44 100644 --- a/.github/workflows/validate.yml +++ b/.github/workflows/validate.yml @@ -27,7 +27,7 @@ jobs: run: | pip install pytest && pip install pytest-asyncio && - python -m pytest onepassword/*.py + python -m pytest sdk/onepassword/*.py - name: Lint with Ruff run: | diff --git a/MANIFEST.in b/MANIFEST.in deleted file mode 100644 index 714e8c5..0000000 --- a/MANIFEST.in +++ /dev/null @@ -1,3 +0,0 @@ -include onepassword/* -recursive-include onepassword *.so -recursive-include onepassword *.dylib diff --git a/onepassword/core.py b/onepassword/core.py deleted file mode 100644 index 847d699..0000000 --- a/onepassword/core.py +++ /dev/null @@ -1,14 +0,0 @@ -import json -import onepassword.op_uniffi_core as core - -# InitClient creates a client instance in the current core module and returns its unique ID. -async def _init_client(client_config): - return await core.init_client(json.dumps(client_config)) - -# Invoke calls specified business logic from core. -async def _invoke(invoke_config): - return await core.invoke(json.dumps(invoke_config)) - -# ReleaseClient releases memory in the core associated with the given client ID. -def _release_client(client_id): - return core.release_client(json.dumps(client_id)) diff --git a/setup.py b/op_uniffi_core_linux_amd64/setup.py similarity index 63% rename from setup.py rename to op_uniffi_core_linux_amd64/setup.py index 67422da..25a4559 100644 --- a/setup.py +++ b/op_uniffi_core_linux_amd64/setup.py @@ -1,12 +1,9 @@ from setuptools import setup, find_packages setup( - name='onepassword', + name='op_uniffi_lib_mac_arm64', version='0.1.0', packages=find_packages(), author='1Password', url='https://github.com/1Password/onepassword-sdk-python', - install_requires=[ - "libop_uniffi_core;platform_system=='Darwin'", - ], ) \ No newline at end of file diff --git a/onepassword/__init__.py b/op_uniffi_core_linux_amd64/src/__init__.py similarity index 100% rename from onepassword/__init__.py rename to op_uniffi_core_linux_amd64/src/__init__.py diff --git a/onepassword/libop_uniffi_core.so b/op_uniffi_core_linux_amd64/src/libop_uniffi_core.so similarity index 100% rename from onepassword/libop_uniffi_core.so rename to op_uniffi_core_linux_amd64/src/libop_uniffi_core.so diff --git a/onepassword/op_uniffi_core.py b/op_uniffi_core_linux_amd64/src/op_uniffi_core.py similarity index 100% rename from onepassword/op_uniffi_core.py rename to op_uniffi_core_linux_amd64/src/op_uniffi_core.py diff --git a/op_uniffi_core_mac_arm64/op_uniffi_lib_mac_arm64/__init__.py b/op_uniffi_core_mac_arm64/op_uniffi_lib_mac_arm64/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/onepassword/libop_uniffi_core.dylib b/op_uniffi_core_mac_arm64/op_uniffi_lib_mac_arm64/libop_uniffi_core.dylib similarity index 100% rename from onepassword/libop_uniffi_core.dylib rename to op_uniffi_core_mac_arm64/op_uniffi_lib_mac_arm64/libop_uniffi_core.dylib diff --git a/op_uniffi_core_mac_arm64/op_uniffi_lib_mac_arm64/op_uniffi_core.py b/op_uniffi_core_mac_arm64/op_uniffi_lib_mac_arm64/op_uniffi_core.py new file mode 100644 index 0000000..65b0d49 --- /dev/null +++ b/op_uniffi_core_mac_arm64/op_uniffi_lib_mac_arm64/op_uniffi_core.py @@ -0,0 +1,966 @@ + + +# This file was autogenerated by some hot garbage in the `uniffi` crate. +# Trust me, you don't want to mess with it! + +# Common helper code. +# +# Ideally this would live in a separate .py file where it can be unittested etc +# in isolation, and perhaps even published as a re-useable package. +# +# However, it's important that the details of how this helper code works (e.g. the +# way that different builtin types are passed across the FFI) exactly match what's +# expected by the rust code on the other side of the interface. In practice right +# now that means coming from the exact some version of `uniffi` that was used to +# compile the rust component. The easiest way to ensure this is to bundle the Python +# helpers directly inline like we're doing here. + +import os +import sys +import ctypes +import enum +import struct +import contextlib +import datetime +import typing +import asyncio +import platform + +# Used for default argument values +_DEFAULT = object() + + +class _UniffiRustBuffer(ctypes.Structure): + _fields_ = [ + ("capacity", ctypes.c_int32), + ("len", ctypes.c_int32), + ("data", ctypes.POINTER(ctypes.c_char)), + ] + + @staticmethod + def alloc(size): + return _rust_call(_UniffiLib.ffi_op_uniffi_core_rustbuffer_alloc, size) + + @staticmethod + def reserve(rbuf, additional): + return _rust_call(_UniffiLib.ffi_op_uniffi_core_rustbuffer_reserve, rbuf, additional) + + def free(self): + return _rust_call(_UniffiLib.ffi_op_uniffi_core_rustbuffer_free, self) + + def __str__(self): + return "_UniffiRustBuffer(capacity={}, len={}, data={})".format( + self.capacity, + self.len, + self.data[0:self.len] + ) + + @contextlib.contextmanager + def alloc_with_builder(*args): + """Context-manger to allocate a buffer using a _UniffiRustBufferBuilder. + + The allocated buffer will be automatically freed if an error occurs, ensuring that + we don't accidentally leak it. + """ + builder = _UniffiRustBufferBuilder() + try: + yield builder + except: + builder.discard() + raise + + @contextlib.contextmanager + def consume_with_stream(self): + """Context-manager to consume a buffer using a _UniffiRustBufferStream. + + The _UniffiRustBuffer will be freed once the context-manager exits, ensuring that we don't + leak it even if an error occurs. + """ + try: + s = _UniffiRustBufferStream.from_rust_buffer(self) + yield s + if s.remaining() != 0: + raise RuntimeError("junk data left in buffer at end of consume_with_stream") + finally: + self.free() + + @contextlib.contextmanager + def read_with_stream(self): + """Context-manager to read a buffer using a _UniffiRustBufferStream. + + This is like consume_with_stream, but doesn't free the buffer afterwards. + It should only be used with borrowed `_UniffiRustBuffer` data. + """ + s = _UniffiRustBufferStream.from_rust_buffer(self) + yield s + if s.remaining() != 0: + raise RuntimeError("junk data left in buffer at end of read_with_stream") + +class _UniffiForeignBytes(ctypes.Structure): + _fields_ = [ + ("len", ctypes.c_int32), + ("data", ctypes.POINTER(ctypes.c_char)), + ] + + def __str__(self): + return "_UniffiForeignBytes(len={}, data={})".format(self.len, self.data[0:self.len]) + + +class _UniffiRustBufferStream: + """ + Helper for structured reading of bytes from a _UniffiRustBuffer + """ + + def __init__(self, data, len): + self.data = data + self.len = len + self.offset = 0 + + @classmethod + def from_rust_buffer(cls, buf): + return cls(buf.data, buf.len) + + def remaining(self): + return self.len - self.offset + + def _unpack_from(self, size, format): + if self.offset + size > self.len: + raise InternalError("read past end of rust buffer") + value = struct.unpack(format, self.data[self.offset:self.offset+size])[0] + self.offset += size + return value + + def read(self, size): + if self.offset + size > self.len: + raise InternalError("read past end of rust buffer") + data = self.data[self.offset:self.offset+size] + self.offset += size + return data + + def read_i8(self): + return self._unpack_from(1, ">b") + + def read_u8(self): + return self._unpack_from(1, ">B") + + def read_i16(self): + return self._unpack_from(2, ">h") + + def read_u16(self): + return self._unpack_from(2, ">H") + + def read_i32(self): + return self._unpack_from(4, ">i") + + def read_u32(self): + return self._unpack_from(4, ">I") + + def read_i64(self): + return self._unpack_from(8, ">q") + + def read_u64(self): + return self._unpack_from(8, ">Q") + + def read_float(self): + v = self._unpack_from(4, ">f") + return v + + def read_double(self): + return self._unpack_from(8, ">d") + + def read_c_size_t(self): + return self._unpack_from(ctypes.sizeof(ctypes.c_size_t) , "@N") + +class _UniffiRustBufferBuilder: + """ + Helper for structured writing of bytes into a _UniffiRustBuffer. + """ + + def __init__(self): + self.rbuf = _UniffiRustBuffer.alloc(16) + self.rbuf.len = 0 + + def finalize(self): + rbuf = self.rbuf + self.rbuf = None + return rbuf + + def discard(self): + if self.rbuf is not None: + rbuf = self.finalize() + rbuf.free() + + @contextlib.contextmanager + def _reserve(self, num_bytes): + if self.rbuf.len + num_bytes > self.rbuf.capacity: + self.rbuf = _UniffiRustBuffer.reserve(self.rbuf, num_bytes) + yield None + self.rbuf.len += num_bytes + + def _pack_into(self, size, format, value): + with self._reserve(size): + # XXX TODO: I feel like I should be able to use `struct.pack_into` here but can't figure it out. + for i, byte in enumerate(struct.pack(format, value)): + self.rbuf.data[self.rbuf.len + i] = byte + + def write(self, value): + with self._reserve(len(value)): + for i, byte in enumerate(value): + self.rbuf.data[self.rbuf.len + i] = byte + + def write_i8(self, v): + self._pack_into(1, ">b", v) + + def write_u8(self, v): + self._pack_into(1, ">B", v) + + def write_i16(self, v): + self._pack_into(2, ">h", v) + + def write_u16(self, v): + self._pack_into(2, ">H", v) + + def write_i32(self, v): + self._pack_into(4, ">i", v) + + def write_u32(self, v): + self._pack_into(4, ">I", v) + + def write_i64(self, v): + self._pack_into(8, ">q", v) + + def write_u64(self, v): + self._pack_into(8, ">Q", v) + + def write_float(self, v): + self._pack_into(4, ">f", v) + + def write_double(self, v): + self._pack_into(8, ">d", v) + + def write_c_size_t(self, v): + self._pack_into(ctypes.sizeof(ctypes.c_size_t) , "@N", v) +# A handful of classes and functions to support the generated data structures. +# This would be a good candidate for isolating in its own ffi-support lib. + +class InternalError(Exception): + pass + +class _UniffiRustCallStatus(ctypes.Structure): + """ + Error runtime. + """ + _fields_ = [ + ("code", ctypes.c_int8), + ("error_buf", _UniffiRustBuffer), + ] + + # These match the values from the uniffi::rustcalls module + CALL_SUCCESS = 0 + CALL_ERROR = 1 + CALL_PANIC = 2 + + def __str__(self): + if self.code == _UniffiRustCallStatus.CALL_SUCCESS: + return "_UniffiRustCallStatus(CALL_SUCCESS)" + elif self.code == _UniffiRustCallStatus.CALL_ERROR: + return "_UniffiRustCallStatus(CALL_ERROR)" + elif self.code == _UniffiRustCallStatus.CALL_PANIC: + return "_UniffiRustCallStatus(CALL_PANIC)" + else: + return "_UniffiRustCallStatus()" + +def _rust_call(fn, *args): + # Call a rust function + return _rust_call_with_error(None, fn, *args) + +def _rust_call_with_error(error_ffi_converter, fn, *args): + # Call a rust function and handle any errors + # + # This function is used for rust calls that return Result<> and therefore can set the CALL_ERROR status code. + # error_ffi_converter must be set to the _UniffiConverter for the error class that corresponds to the result. + call_status = _UniffiRustCallStatus(code=_UniffiRustCallStatus.CALL_SUCCESS, error_buf=_UniffiRustBuffer(0, 0, None)) + + args_with_error = args + (ctypes.byref(call_status),) + result = fn(*args_with_error) + _uniffi_check_call_status(error_ffi_converter, call_status) + return result + +def _uniffi_check_call_status(error_ffi_converter, call_status): + if call_status.code == _UniffiRustCallStatus.CALL_SUCCESS: + pass + elif call_status.code == _UniffiRustCallStatus.CALL_ERROR: + if error_ffi_converter is None: + call_status.error_buf.free() + raise InternalError("_rust_call_with_error: CALL_ERROR, but error_ffi_converter is None") + else: + raise error_ffi_converter.lift(call_status.error_buf) + elif call_status.code == _UniffiRustCallStatus.CALL_PANIC: + # When the rust code sees a panic, it tries to construct a _UniffiRustBuffer + # with the message. But if that code panics, then it just sends back + # an empty buffer. + if call_status.error_buf.len > 0: + msg = _UniffiConverterString.lift(call_status.error_buf) + else: + msg = "Unknown rust panic" + raise InternalError(msg) + else: + raise InternalError("Invalid _UniffiRustCallStatus code: {}".format( + call_status.code)) + +# A function pointer for a callback as defined by UniFFI. +# Rust definition `fn(handle: u64, method: u32, args: _UniffiRustBuffer, buf_ptr: *mut _UniffiRustBuffer) -> int` +_UNIFFI_FOREIGN_CALLBACK_T = ctypes.CFUNCTYPE(ctypes.c_int, ctypes.c_ulonglong, ctypes.c_ulong, ctypes.POINTER(ctypes.c_char), ctypes.c_int, ctypes.POINTER(_UniffiRustBuffer)) + +# UniFFI future continuation +_UNIFFI_FUTURE_CONTINUATION_T = ctypes.CFUNCTYPE(None, ctypes.c_size_t, ctypes.c_int8) + +class _UniffiPointerManagerCPython: + """ + Manage giving out pointers to Python objects on CPython + + This class is used to generate opaque pointers that reference Python objects to pass to Rust. + It assumes a CPython platform. See _UniffiPointerManagerGeneral for the alternative. + """ + + def new_pointer(self, obj): + """ + Get a pointer for an object as a ctypes.c_size_t instance + + Each call to new_pointer() must be balanced with exactly one call to release_pointer() + + This returns a ctypes.c_size_t. This is always the same size as a pointer and can be + interchanged with pointers for FFI function arguments and return values. + """ + # IncRef the object since we're going to pass a pointer to Rust + ctypes.pythonapi.Py_IncRef(ctypes.py_object(obj)) + # id() is the object address on CPython + # (https://docs.python.org/3/library/functions.html#id) + return id(obj) + + def release_pointer(self, address): + py_obj = ctypes.cast(address, ctypes.py_object) + obj = py_obj.value + ctypes.pythonapi.Py_DecRef(py_obj) + return obj + + def lookup(self, address): + return ctypes.cast(address, ctypes.py_object).value + +class _UniffiPointerManagerGeneral: + """ + Manage giving out pointers to Python objects on non-CPython platforms + + This has the same API as _UniffiPointerManagerCPython, but doesn't assume we're running on + CPython and is slightly slower. + + Instead of using real pointers, it maps integer values to objects and returns the keys as + c_size_t values. + """ + + def __init__(self): + self._map = {} + self._lock = threading.Lock() + self._current_handle = 0 + + def new_pointer(self, obj): + with self._lock: + handle = self._current_handle + self._current_handle += 1 + self._map[handle] = obj + return handle + + def release_pointer(self, handle): + with self._lock: + return self._map.pop(handle) + + def lookup(self, handle): + with self._lock: + return self._map[handle] + +# Pick an pointer manager implementation based on the platform +if platform.python_implementation() == 'CPython': + _UniffiPointerManager = _UniffiPointerManagerCPython # type: ignore +else: + _UniffiPointerManager = _UniffiPointerManagerGeneral # type: ignore +# Types conforming to `_UniffiConverterPrimitive` pass themselves directly over the FFI. +class _UniffiConverterPrimitive: + @classmethod + def lift(cls, value): + return value + + @classmethod + def lower(cls, value): + return value + +class _UniffiConverterPrimitiveInt(_UniffiConverterPrimitive): + @classmethod + def check_lower(cls, value): + try: + value = value.__index__() + except Exception: + raise TypeError("'{}' object cannot be interpreted as an integer".format(type(value).__name__)) + if not isinstance(value, int): + raise TypeError("__index__ returned non-int (type {})".format(type(value).__name__)) + if not cls.VALUE_MIN <= value < cls.VALUE_MAX: + raise ValueError("{} requires {} <= value < {}".format(cls.CLASS_NAME, cls.VALUE_MIN, cls.VALUE_MAX)) + +class _UniffiConverterPrimitiveFloat(_UniffiConverterPrimitive): + @classmethod + def check_lower(cls, value): + try: + value = value.__float__() + except Exception: + raise TypeError("must be real number, not {}".format(type(value).__name__)) + if not isinstance(value, float): + raise TypeError("__float__ returned non-float (type {})".format(type(value).__name__)) + +# Helper class for wrapper types that will always go through a _UniffiRustBuffer. +# Classes should inherit from this and implement the `read` and `write` static methods. +class _UniffiConverterRustBuffer: + @classmethod + def lift(cls, rbuf): + with rbuf.consume_with_stream() as stream: + return cls.read(stream) + + @classmethod + def lower(cls, value): + with _UniffiRustBuffer.alloc_with_builder() as builder: + cls.write(value, builder) + return builder.finalize() + +# Contains loading, initialization code, and the FFI Function declarations. +# Define some ctypes FFI types that we use in the library + +""" +Function pointer for a Rust task, which a callback function that takes a opaque pointer +""" +_UNIFFI_RUST_TASK = ctypes.CFUNCTYPE(None, ctypes.c_void_p, ctypes.c_int8) + +def _uniffi_future_callback_t(return_type): + """ + Factory function to create callback function types for async functions + """ + return ctypes.CFUNCTYPE(None, ctypes.c_size_t, return_type, _UniffiRustCallStatus) + +def _uniffi_load_indirect(): + """ + This is how we find and load the dynamic library provided by the component. + For now we just look it up by name. + """ + if sys.platform == "darwin": + libname = "lib{}.dylib" + elif sys.platform.startswith("win"): + # As of python3.8, ctypes does not seem to search $PATH when loading DLLs. + # We could use `os.add_dll_directory` to configure the search path, but + # it doesn't feel right to mess with application-wide settings. Let's + # assume that the `.dll` is next to the `.py` file and load by full path. + libname = os.path.join( + os.path.dirname(__file__), + "{}.dll", + ) + else: + # Anything else must be an ELF platform - Linux, *BSD, Solaris/illumos + libname = "lib{}.so" + + libname = libname.format("op_uniffi_core") + path = os.path.join(os.path.dirname(__file__), libname) + lib = ctypes.cdll.LoadLibrary(path) + return lib + +def _uniffi_check_contract_api_version(lib): + # Get the bindings contract version from our ComponentInterface + bindings_contract_version = 25 + # Get the scaffolding contract version by calling the into the dylib + scaffolding_contract_version = lib.ffi_op_uniffi_core_uniffi_contract_version() + if bindings_contract_version != scaffolding_contract_version: + raise InternalError("UniFFI contract version mismatch: try cleaning and rebuilding your project") + +def _uniffi_check_api_checksums(lib): + if lib.uniffi_op_uniffi_core_checksum_func_init_client() != 45066: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_op_uniffi_core_checksum_func_invoke() != 29143: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_op_uniffi_core_checksum_func_release_client() != 57155: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + +# A ctypes library to expose the extern-C FFI definitions. +# This is an implementation detail which will be called internally by the public API. + +_UniffiLib = _uniffi_load_indirect() +_UniffiLib.uniffi_op_uniffi_core_fn_func_init_client.argtypes = ( + _UniffiRustBuffer, +) +_UniffiLib.uniffi_op_uniffi_core_fn_func_init_client.restype = ctypes.c_void_p +_UniffiLib.uniffi_op_uniffi_core_fn_func_invoke.argtypes = ( + _UniffiRustBuffer, +) +_UniffiLib.uniffi_op_uniffi_core_fn_func_invoke.restype = ctypes.c_void_p +_UniffiLib.uniffi_op_uniffi_core_fn_func_release_client.argtypes = ( + _UniffiRustBuffer, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_op_uniffi_core_fn_func_release_client.restype = None +_UniffiLib.ffi_op_uniffi_core_rustbuffer_alloc.argtypes = ( + ctypes.c_int32, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.ffi_op_uniffi_core_rustbuffer_alloc.restype = _UniffiRustBuffer +_UniffiLib.ffi_op_uniffi_core_rustbuffer_from_bytes.argtypes = ( + _UniffiForeignBytes, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.ffi_op_uniffi_core_rustbuffer_from_bytes.restype = _UniffiRustBuffer +_UniffiLib.ffi_op_uniffi_core_rustbuffer_free.argtypes = ( + _UniffiRustBuffer, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.ffi_op_uniffi_core_rustbuffer_free.restype = None +_UniffiLib.ffi_op_uniffi_core_rustbuffer_reserve.argtypes = ( + _UniffiRustBuffer, + ctypes.c_int32, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.ffi_op_uniffi_core_rustbuffer_reserve.restype = _UniffiRustBuffer +_UniffiLib.ffi_op_uniffi_core_rust_future_poll_u8.argtypes = ( + ctypes.c_void_p, + _UNIFFI_FUTURE_CONTINUATION_T, + ctypes.c_size_t, +) +_UniffiLib.ffi_op_uniffi_core_rust_future_poll_u8.restype = None +_UniffiLib.ffi_op_uniffi_core_rust_future_cancel_u8.argtypes = ( + ctypes.c_void_p, +) +_UniffiLib.ffi_op_uniffi_core_rust_future_cancel_u8.restype = None +_UniffiLib.ffi_op_uniffi_core_rust_future_free_u8.argtypes = ( + ctypes.c_void_p, +) +_UniffiLib.ffi_op_uniffi_core_rust_future_free_u8.restype = None +_UniffiLib.ffi_op_uniffi_core_rust_future_complete_u8.argtypes = ( + ctypes.c_void_p, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.ffi_op_uniffi_core_rust_future_complete_u8.restype = ctypes.c_uint8 +_UniffiLib.ffi_op_uniffi_core_rust_future_poll_i8.argtypes = ( + ctypes.c_void_p, + _UNIFFI_FUTURE_CONTINUATION_T, + ctypes.c_size_t, +) +_UniffiLib.ffi_op_uniffi_core_rust_future_poll_i8.restype = None +_UniffiLib.ffi_op_uniffi_core_rust_future_cancel_i8.argtypes = ( + ctypes.c_void_p, +) +_UniffiLib.ffi_op_uniffi_core_rust_future_cancel_i8.restype = None +_UniffiLib.ffi_op_uniffi_core_rust_future_free_i8.argtypes = ( + ctypes.c_void_p, +) +_UniffiLib.ffi_op_uniffi_core_rust_future_free_i8.restype = None +_UniffiLib.ffi_op_uniffi_core_rust_future_complete_i8.argtypes = ( + ctypes.c_void_p, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.ffi_op_uniffi_core_rust_future_complete_i8.restype = ctypes.c_int8 +_UniffiLib.ffi_op_uniffi_core_rust_future_poll_u16.argtypes = ( + ctypes.c_void_p, + _UNIFFI_FUTURE_CONTINUATION_T, + ctypes.c_size_t, +) +_UniffiLib.ffi_op_uniffi_core_rust_future_poll_u16.restype = None +_UniffiLib.ffi_op_uniffi_core_rust_future_cancel_u16.argtypes = ( + ctypes.c_void_p, +) +_UniffiLib.ffi_op_uniffi_core_rust_future_cancel_u16.restype = None +_UniffiLib.ffi_op_uniffi_core_rust_future_free_u16.argtypes = ( + ctypes.c_void_p, +) +_UniffiLib.ffi_op_uniffi_core_rust_future_free_u16.restype = None +_UniffiLib.ffi_op_uniffi_core_rust_future_complete_u16.argtypes = ( + ctypes.c_void_p, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.ffi_op_uniffi_core_rust_future_complete_u16.restype = ctypes.c_uint16 +_UniffiLib.ffi_op_uniffi_core_rust_future_poll_i16.argtypes = ( + ctypes.c_void_p, + _UNIFFI_FUTURE_CONTINUATION_T, + ctypes.c_size_t, +) +_UniffiLib.ffi_op_uniffi_core_rust_future_poll_i16.restype = None +_UniffiLib.ffi_op_uniffi_core_rust_future_cancel_i16.argtypes = ( + ctypes.c_void_p, +) +_UniffiLib.ffi_op_uniffi_core_rust_future_cancel_i16.restype = None +_UniffiLib.ffi_op_uniffi_core_rust_future_free_i16.argtypes = ( + ctypes.c_void_p, +) +_UniffiLib.ffi_op_uniffi_core_rust_future_free_i16.restype = None +_UniffiLib.ffi_op_uniffi_core_rust_future_complete_i16.argtypes = ( + ctypes.c_void_p, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.ffi_op_uniffi_core_rust_future_complete_i16.restype = ctypes.c_int16 +_UniffiLib.ffi_op_uniffi_core_rust_future_poll_u32.argtypes = ( + ctypes.c_void_p, + _UNIFFI_FUTURE_CONTINUATION_T, + ctypes.c_size_t, +) +_UniffiLib.ffi_op_uniffi_core_rust_future_poll_u32.restype = None +_UniffiLib.ffi_op_uniffi_core_rust_future_cancel_u32.argtypes = ( + ctypes.c_void_p, +) +_UniffiLib.ffi_op_uniffi_core_rust_future_cancel_u32.restype = None +_UniffiLib.ffi_op_uniffi_core_rust_future_free_u32.argtypes = ( + ctypes.c_void_p, +) +_UniffiLib.ffi_op_uniffi_core_rust_future_free_u32.restype = None +_UniffiLib.ffi_op_uniffi_core_rust_future_complete_u32.argtypes = ( + ctypes.c_void_p, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.ffi_op_uniffi_core_rust_future_complete_u32.restype = ctypes.c_uint32 +_UniffiLib.ffi_op_uniffi_core_rust_future_poll_i32.argtypes = ( + ctypes.c_void_p, + _UNIFFI_FUTURE_CONTINUATION_T, + ctypes.c_size_t, +) +_UniffiLib.ffi_op_uniffi_core_rust_future_poll_i32.restype = None +_UniffiLib.ffi_op_uniffi_core_rust_future_cancel_i32.argtypes = ( + ctypes.c_void_p, +) +_UniffiLib.ffi_op_uniffi_core_rust_future_cancel_i32.restype = None +_UniffiLib.ffi_op_uniffi_core_rust_future_free_i32.argtypes = ( + ctypes.c_void_p, +) +_UniffiLib.ffi_op_uniffi_core_rust_future_free_i32.restype = None +_UniffiLib.ffi_op_uniffi_core_rust_future_complete_i32.argtypes = ( + ctypes.c_void_p, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.ffi_op_uniffi_core_rust_future_complete_i32.restype = ctypes.c_int32 +_UniffiLib.ffi_op_uniffi_core_rust_future_poll_u64.argtypes = ( + ctypes.c_void_p, + _UNIFFI_FUTURE_CONTINUATION_T, + ctypes.c_size_t, +) +_UniffiLib.ffi_op_uniffi_core_rust_future_poll_u64.restype = None +_UniffiLib.ffi_op_uniffi_core_rust_future_cancel_u64.argtypes = ( + ctypes.c_void_p, +) +_UniffiLib.ffi_op_uniffi_core_rust_future_cancel_u64.restype = None +_UniffiLib.ffi_op_uniffi_core_rust_future_free_u64.argtypes = ( + ctypes.c_void_p, +) +_UniffiLib.ffi_op_uniffi_core_rust_future_free_u64.restype = None +_UniffiLib.ffi_op_uniffi_core_rust_future_complete_u64.argtypes = ( + ctypes.c_void_p, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.ffi_op_uniffi_core_rust_future_complete_u64.restype = ctypes.c_uint64 +_UniffiLib.ffi_op_uniffi_core_rust_future_poll_i64.argtypes = ( + ctypes.c_void_p, + _UNIFFI_FUTURE_CONTINUATION_T, + ctypes.c_size_t, +) +_UniffiLib.ffi_op_uniffi_core_rust_future_poll_i64.restype = None +_UniffiLib.ffi_op_uniffi_core_rust_future_cancel_i64.argtypes = ( + ctypes.c_void_p, +) +_UniffiLib.ffi_op_uniffi_core_rust_future_cancel_i64.restype = None +_UniffiLib.ffi_op_uniffi_core_rust_future_free_i64.argtypes = ( + ctypes.c_void_p, +) +_UniffiLib.ffi_op_uniffi_core_rust_future_free_i64.restype = None +_UniffiLib.ffi_op_uniffi_core_rust_future_complete_i64.argtypes = ( + ctypes.c_void_p, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.ffi_op_uniffi_core_rust_future_complete_i64.restype = ctypes.c_int64 +_UniffiLib.ffi_op_uniffi_core_rust_future_poll_f32.argtypes = ( + ctypes.c_void_p, + _UNIFFI_FUTURE_CONTINUATION_T, + ctypes.c_size_t, +) +_UniffiLib.ffi_op_uniffi_core_rust_future_poll_f32.restype = None +_UniffiLib.ffi_op_uniffi_core_rust_future_cancel_f32.argtypes = ( + ctypes.c_void_p, +) +_UniffiLib.ffi_op_uniffi_core_rust_future_cancel_f32.restype = None +_UniffiLib.ffi_op_uniffi_core_rust_future_free_f32.argtypes = ( + ctypes.c_void_p, +) +_UniffiLib.ffi_op_uniffi_core_rust_future_free_f32.restype = None +_UniffiLib.ffi_op_uniffi_core_rust_future_complete_f32.argtypes = ( + ctypes.c_void_p, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.ffi_op_uniffi_core_rust_future_complete_f32.restype = ctypes.c_float +_UniffiLib.ffi_op_uniffi_core_rust_future_poll_f64.argtypes = ( + ctypes.c_void_p, + _UNIFFI_FUTURE_CONTINUATION_T, + ctypes.c_size_t, +) +_UniffiLib.ffi_op_uniffi_core_rust_future_poll_f64.restype = None +_UniffiLib.ffi_op_uniffi_core_rust_future_cancel_f64.argtypes = ( + ctypes.c_void_p, +) +_UniffiLib.ffi_op_uniffi_core_rust_future_cancel_f64.restype = None +_UniffiLib.ffi_op_uniffi_core_rust_future_free_f64.argtypes = ( + ctypes.c_void_p, +) +_UniffiLib.ffi_op_uniffi_core_rust_future_free_f64.restype = None +_UniffiLib.ffi_op_uniffi_core_rust_future_complete_f64.argtypes = ( + ctypes.c_void_p, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.ffi_op_uniffi_core_rust_future_complete_f64.restype = ctypes.c_double +_UniffiLib.ffi_op_uniffi_core_rust_future_poll_pointer.argtypes = ( + ctypes.c_void_p, + _UNIFFI_FUTURE_CONTINUATION_T, + ctypes.c_size_t, +) +_UniffiLib.ffi_op_uniffi_core_rust_future_poll_pointer.restype = None +_UniffiLib.ffi_op_uniffi_core_rust_future_cancel_pointer.argtypes = ( + ctypes.c_void_p, +) +_UniffiLib.ffi_op_uniffi_core_rust_future_cancel_pointer.restype = None +_UniffiLib.ffi_op_uniffi_core_rust_future_free_pointer.argtypes = ( + ctypes.c_void_p, +) +_UniffiLib.ffi_op_uniffi_core_rust_future_free_pointer.restype = None +_UniffiLib.ffi_op_uniffi_core_rust_future_complete_pointer.argtypes = ( + ctypes.c_void_p, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.ffi_op_uniffi_core_rust_future_complete_pointer.restype = ctypes.c_void_p +_UniffiLib.ffi_op_uniffi_core_rust_future_poll_rust_buffer.argtypes = ( + ctypes.c_void_p, + _UNIFFI_FUTURE_CONTINUATION_T, + ctypes.c_size_t, +) +_UniffiLib.ffi_op_uniffi_core_rust_future_poll_rust_buffer.restype = None +_UniffiLib.ffi_op_uniffi_core_rust_future_cancel_rust_buffer.argtypes = ( + ctypes.c_void_p, +) +_UniffiLib.ffi_op_uniffi_core_rust_future_cancel_rust_buffer.restype = None +_UniffiLib.ffi_op_uniffi_core_rust_future_free_rust_buffer.argtypes = ( + ctypes.c_void_p, +) +_UniffiLib.ffi_op_uniffi_core_rust_future_free_rust_buffer.restype = None +_UniffiLib.ffi_op_uniffi_core_rust_future_complete_rust_buffer.argtypes = ( + ctypes.c_void_p, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.ffi_op_uniffi_core_rust_future_complete_rust_buffer.restype = _UniffiRustBuffer +_UniffiLib.ffi_op_uniffi_core_rust_future_poll_void.argtypes = ( + ctypes.c_void_p, + _UNIFFI_FUTURE_CONTINUATION_T, + ctypes.c_size_t, +) +_UniffiLib.ffi_op_uniffi_core_rust_future_poll_void.restype = None +_UniffiLib.ffi_op_uniffi_core_rust_future_cancel_void.argtypes = ( + ctypes.c_void_p, +) +_UniffiLib.ffi_op_uniffi_core_rust_future_cancel_void.restype = None +_UniffiLib.ffi_op_uniffi_core_rust_future_free_void.argtypes = ( + ctypes.c_void_p, +) +_UniffiLib.ffi_op_uniffi_core_rust_future_free_void.restype = None +_UniffiLib.ffi_op_uniffi_core_rust_future_complete_void.argtypes = ( + ctypes.c_void_p, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.ffi_op_uniffi_core_rust_future_complete_void.restype = None +_UniffiLib.uniffi_op_uniffi_core_checksum_func_init_client.argtypes = ( +) +_UniffiLib.uniffi_op_uniffi_core_checksum_func_init_client.restype = ctypes.c_uint16 +_UniffiLib.uniffi_op_uniffi_core_checksum_func_invoke.argtypes = ( +) +_UniffiLib.uniffi_op_uniffi_core_checksum_func_invoke.restype = ctypes.c_uint16 +_UniffiLib.uniffi_op_uniffi_core_checksum_func_release_client.argtypes = ( +) +_UniffiLib.uniffi_op_uniffi_core_checksum_func_release_client.restype = ctypes.c_uint16 +_UniffiLib.ffi_op_uniffi_core_uniffi_contract_version.argtypes = ( +) +_UniffiLib.ffi_op_uniffi_core_uniffi_contract_version.restype = ctypes.c_uint32 +_uniffi_check_contract_api_version(_UniffiLib) +_uniffi_check_api_checksums(_UniffiLib) + +# Async support# RustFuturePoll values +_UNIFFI_RUST_FUTURE_POLL_READY = 0 +_UNIFFI_RUST_FUTURE_POLL_MAYBE_READY = 1 + +# Stores futures for _uniffi_continuation_callback +_UniffiContinuationPointerManager = _UniffiPointerManager() + +# Continuation callback for async functions +# lift the return value or error and resolve the future, causing the async function to resume. +@_UNIFFI_FUTURE_CONTINUATION_T +def _uniffi_continuation_callback(future_ptr, poll_code): + (eventloop, future) = _UniffiContinuationPointerManager.release_pointer(future_ptr) + eventloop.call_soon_threadsafe(_uniffi_set_future_result, future, poll_code) + +def _uniffi_set_future_result(future, poll_code): + if not future.cancelled(): + future.set_result(poll_code) + +async def _uniffi_rust_call_async(rust_future, ffi_poll, ffi_complete, ffi_free, lift_func, error_ffi_converter): + try: + eventloop = asyncio.get_running_loop() + + # Loop and poll until we see a _UNIFFI_RUST_FUTURE_POLL_READY value + while True: + future = eventloop.create_future() + ffi_poll( + rust_future, + _uniffi_continuation_callback, + _UniffiContinuationPointerManager.new_pointer((eventloop, future)), + ) + poll_code = await future + if poll_code == _UNIFFI_RUST_FUTURE_POLL_READY: + break + + return lift_func( + _rust_call_with_error(error_ffi_converter, ffi_complete, rust_future) + ) + finally: + ffi_free(rust_future) + +# Public interface members begin here. + + +class _UniffiConverterString: + @staticmethod + def check_lower(value): + if not isinstance(value, str): + raise TypeError("argument must be str, not {}".format(type(value).__name__)) + return value + + @staticmethod + def read(buf): + size = buf.read_i32() + if size < 0: + raise InternalError("Unexpected negative string length") + utf8_bytes = buf.read(size) + return utf8_bytes.decode("utf-8") + + @staticmethod + def write(value, buf): + utf8_bytes = value.encode("utf-8") + buf.write_i32(len(utf8_bytes)) + buf.write(utf8_bytes) + + @staticmethod + def lift(buf): + with buf.consume_with_stream() as stream: + return stream.read(stream.remaining()).decode("utf-8") + + @staticmethod + def lower(value): + with _UniffiRustBuffer.alloc_with_builder() as builder: + builder.write(value.encode("utf-8")) + return builder.finalize() + + +# Error +# We want to define each variant as a nested class that's also a subclass, +# which is tricky in Python. To accomplish this we're going to create each +# class separately, then manually add the child classes to the base class's +# __dict__. All of this happens in dummy class to avoid polluting the module +# namespace. +class Error(Exception): + """ + Error type sent over the FFI by UniFFI. + + `uniffi::Error` only supports errors that are enums, so we need to have a single-variant enum here. + """ + + pass + +_UniffiTempError = Error + +class Error: # type: ignore + class Error(_UniffiTempError): + """ + Any error ocurring in the SDK + """ + + + def __init__(self, msg): + super().__init__(", ".join([ + "msg={!r}".format(msg), + ])) + self.msg = msg + def __repr__(self): + return "Error.Error({})".format(str(self)) + _UniffiTempError.Error = Error # type: ignore + +Error = _UniffiTempError # type: ignore +del _UniffiTempError + + +class _UniffiConverterTypeError(_UniffiConverterRustBuffer): + @staticmethod + def read(buf): + variant = buf.read_i32() + if variant == 1: + return Error.Error( + msg=_UniffiConverterString.read(buf), + ) + raise InternalError("Raw enum value doesn't match any cases") + + @staticmethod + def check_lower(value): + if isinstance(value, Error.Error): + _UniffiConverterString.check_lower(value.msg) + return + + @staticmethod + def write(value, buf): + if isinstance(value, Error.Error): + buf.write_i32(1) + _UniffiConverterString.write(value.msg, buf) + +def init_client(client_config: "str"): + _UniffiConverterString.check_lower(client_config) + + return _uniffi_rust_call_async( + _UniffiLib.uniffi_op_uniffi_core_fn_func_init_client( + _UniffiConverterString.lower(client_config)), + _UniffiLib.ffi_op_uniffi_core_rust_future_poll_rust_buffer, + _UniffiLib.ffi_op_uniffi_core_rust_future_complete_rust_buffer, + _UniffiLib.ffi_op_uniffi_core_rust_future_free_rust_buffer, + # lift function + _UniffiConverterString.lift, + # Error FFI converter + _UniffiConverterTypeError, + ) + +def invoke(invocation: "str"): + _UniffiConverterString.check_lower(invocation) + + return _uniffi_rust_call_async( + _UniffiLib.uniffi_op_uniffi_core_fn_func_invoke( + _UniffiConverterString.lower(invocation)), + _UniffiLib.ffi_op_uniffi_core_rust_future_poll_rust_buffer, + _UniffiLib.ffi_op_uniffi_core_rust_future_complete_rust_buffer, + _UniffiLib.ffi_op_uniffi_core_rust_future_free_rust_buffer, + # lift function + _UniffiConverterString.lift, + # Error FFI converter + _UniffiConverterTypeError, + ) + +def release_client(client_id: "str"): + _UniffiConverterString.check_lower(client_id) + + _rust_call_with_error(_UniffiConverterTypeError,_UniffiLib.uniffi_op_uniffi_core_fn_func_release_client, + _UniffiConverterString.lower(client_id)) + + +__all__ = [ + "InternalError", + "Error", + "init_client", + "invoke", + "release_client", +] + diff --git a/op_uniffi_core_mac_arm64/setup.py b/op_uniffi_core_mac_arm64/setup.py new file mode 100644 index 0000000..917ae47 --- /dev/null +++ b/op_uniffi_core_mac_arm64/setup.py @@ -0,0 +1,11 @@ +from setuptools import setup, find_packages + + +setup( + name='op_uniffi_lib_mac_arm64', + version='0.1.0', + packages=find_packages(), + author='1Password', + description="The 1Password Python SDK offers programmatic read access to your secrets in 1Password in an interface native to Python.", + url='https://github.com/1Password/onepassword-sdk-python', +) \ No newline at end of file diff --git a/pyproject.toml b/pyproject.toml deleted file mode 100644 index 806d7da..0000000 --- a/pyproject.toml +++ /dev/null @@ -1,5 +0,0 @@ -[build-system] -requires = [ - "setuptools >= 40.6.0", - "wheel", -] \ No newline at end of file diff --git a/sdk/onepassword/__init__.py b/sdk/onepassword/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/onepassword/client.py b/sdk/onepassword/client.py similarity index 100% rename from onepassword/client.py rename to sdk/onepassword/client.py diff --git a/sdk/onepassword/core.py b/sdk/onepassword/core.py new file mode 100644 index 0000000..879ce5b --- /dev/null +++ b/sdk/onepassword/core.py @@ -0,0 +1,29 @@ +import json +import sys +import importlib.util +#import op_uniffi_lib_mac_arm64.op_uniffi_core as core + +if (spec := importlib.util.find_spec("op_uniffi_lib_mac_arm64.op_uniffi_core")) is not None: + module = importlib.util.module_from_spec(spec) + print(module) + sys.modules["core"] = module + spec.loader.exec_module(module) + print(f"op_uniffi_lib_mac_arm64 has been imported") +elif (spec := importlib.util.find_spec("op_uniffi_lib_linux_amd64")) is not None: + module = importlib.util.module_from_spec(spec) + sys.modules["core"] = module + spec.loader.exec_module(module) + +core = sys.modules["core"] + +# InitClient creates a client instance in the current core module and returns its unique ID. +async def _init_client(client_config): + return await core.init_client(json.dumps(client_config)) + +# Invoke calls specified business logic from core. +async def _invoke(invoke_config): + return await core.invoke(json.dumps(invoke_config)) + +# ReleaseClient releases memory in the core associated with the given client ID. +def _release_client(client_id): + return core.release_client(json.dumps(client_id)) diff --git a/onepassword/secrets_api.py b/sdk/onepassword/secrets_api.py similarity index 100% rename from onepassword/secrets_api.py rename to sdk/onepassword/secrets_api.py diff --git a/onepassword/test_client.py b/sdk/onepassword/test_client.py similarity index 100% rename from onepassword/test_client.py rename to sdk/onepassword/test_client.py diff --git a/sdk/setup.py b/sdk/setup.py new file mode 100644 index 0000000..a030ae2 --- /dev/null +++ b/sdk/setup.py @@ -0,0 +1,14 @@ +from setuptools import setup, find_packages + +setup( + name='onepassword', + version='0.1.0', + packages=find_packages(), + author='1Password', + description="The 1Password Python SDK offers programmatic read access to your secrets in 1Password in an interface native to Python.", + url='https://github.com/1Password/onepassword-sdk-python', + install_requires=[ + "op_uniffi_lib_mac_arm64; platform_system=='Darwin' and platform_machine=='arm64'", + "op_uniffi_lib_mac_x86_64; platform_system=='Linux' and platform_machine=='x86_64'", + ], +) \ No newline at end of file