目录
Vishwa Shah

feat!: merge 5.0.0 (#136)

  • refactor!: replace Real and Integer with double and int (#131)

Replace the uses of ostk::core::type::Integer in the library, tests and Python bindings. The URL port was the only Real/Integer user in io. Its undefined state (Integer::Undefined(), meaning “no port in the URL”) has no faithful int value, so it becomes std::optional.

  • URL port is now std::optional: constructor argument (default std::nullopt), accessPort(), getPort(), setPort() and the member
  • URL::Parse parses the port with boost::lexical_cast and throws the same RuntimeError (“Cannot cast string [..] to Integer.”) as Integer::Parse did; no port gives std::nullopt
  • toString() and operator<< print the port as before (“Undefined” when absent)
  • operator== keeps its behaviour (two missing ports are equal); operator!= now returns true when only one URL has a port (Integer’s != returned false when either side was undefined, so it was not the negation of ==)
  • Remove the ostk::io::Integer alias and the Core/Type/Integer.hpp include from URL.hpp
  • Add C++ and Python tests for a missing port

Python-visible changes:

  • URL.get_port() returns int, or None when the URL has no port (was ostk.core.type.Integer, undefined when there was no port)
  • URL(…) and URL.set_port() take int or None for the port (None removes it); plain Python ints keep working

BREAKING CHANGE: URL(const String&, const String&, const String&, const Integer& = Integer::Undefined(), …) becomes URL(…, const std::optional& aPort = std::nullopt, …); const Integer& URL::accessPort() const becomes const std::optional& URL::accessPort() const; Integer URL::getPort() const becomes std::optional URL::getPort() const; void URL::setPort(const Integer&) becomes void URL::setPort(const std::optional&). The ostk::io::Integer alias is removed and URL.hpp no longer includes Core/Type/Integer.hpp. Python URL.get_port() returns int or None, and URL(…)/URL.set_port() take int or None.

Co-authored-by: Claude Opus 5.5 noreply@anthropic.com

  • refactor!: replace Undefined pattern with std::optional (#132)

  • refactor!: remove unimplemented Undefined declarations from ip::Address

ip::Address is declared but not implemented (Address.cpp is empty and the class has no Python binding). Like core’s System::User, System::Group and Logger::Source, drop its unimplemented null-object declarations so the Undefined pattern does not survive in the public header.

  • Remove the Address::Undefined() and Address::isDefined() declarations
  • Remove Address::Type::Undefined; Address::Type is now { IPv4, IPv6 }

BREAKING CHANGE: removed the declarations Address::Undefined, Address::isDefined and the enumerator Address::Type::Undefined. None of them had a definition, so no linked code can depend on them. There is no Python change.

Co-Authored-By: Claude Opus 5.5 noreply@anthropic.com

  • refactor!: replace Undefined pattern with std::optional in http::Request

A Request is now always defined. Request::Method::Undefined was not an “unspecified” default (no signature defaulted to it); it only existed to build the Request::Undefined() null object, so it is removed with it. Callers that need “no request” should use std::optional.

  • Remove Request::Undefined(), Request::isDefined() and Request::Method::Undefined
  • Remove the Undefined(“Request”) guards from getMethod(), getUrl() and getBody(), and the Undefined entry from StringFromMethod()
  • Client::Send no longer checks aRequest.isDefined(). A request whose URL is undefined still throws Undefined(“URL”) when Send serializes the URL (until URL itself is migrated)
  • Python: remove Request.undefined(), Request.is_defined() and Request.Method.Undefined

Request::Method values shift down by one (Get is now 0). Nothing in this repository depends on the integer values: StringFromMethod uses a map and Client::Send uses StringFromMethod.

BREAKING CHANGE: removed Request::Undefined, Request::isDefined and Request::Method::Undefined. Use std::optional where a request may be absent, and pass a real method. Python: Request.undefined(), Request.is_defined() and Request.Method.Undefined are removed; use None for “no request”.

Co-Authored-By: Claude Opus 5.5 noreply@anthropic.com

  • refactor!: replace Undefined pattern with std::optional in http::Response

A Response is now always defined. Response::StatusCode::Undefined (0) was not an “unspecified” default (no signature defaulted to it); it only marked the Response::Undefined() null object, so it is removed with it. Callers that need “no response” should use std::optional.

  • Remove Response::Undefined(), Response::isDefined() and Response::StatusCode::Undefined
  • Remove the Undefined(“Response”) guards from isOk(), getStatusCode() and getBody(), and the Undefined entry from StringFromStatusCode()
  • Client::Send used to return an undefined response when cURL reported no status code (0, e.g. for file:// transfers); every accessor of that response then threw Undefined(“Response”). Send now throws that same exception directly
  • Python: remove Response.undefined(), Response.is_defined() and Response.StatusCode.Undefined

The other StatusCode enumerators have explicit values, so their integer values do not change.

BREAKING CHANGE: removed Response::Undefined, Response::isDefined and Response::StatusCode::Undefined. Use std::optional where a response may be absent. Client::Send now throws ostk::core::error::runtime::Undefined(“Response”) when no status code is received, instead of returning an undefined response. Python: Response.undefined(), Response.is_defined() and Response.StatusCode.Undefined are removed; Client.send raises RuntimeError in the no-status-code case.

Co-Authored-By: Claude Opus 5.5 noreply@anthropic.com

  • refactor!: replace Undefined pattern with std::optional in URL

A URL is now always defined. The undefined state (an empty scheme or host) is rejected when the URL is built or modified, instead of being carried around and rejected later by toString(), the comparison operators and http::Client. Callers that need “no URL” should use std::optional.

  • Remove URL::Undefined() and URL::isDefined()
  • The URL constructor, setScheme() and setHost() throw ostk::core::error::runtime::Undefined(“Scheme”) / (“Host”) for an empty scheme or host. URL::Parse is unchanged: it still throws Wrong for a string without scheme or host, before constructing the URL
  • Remove the Undefined(“URL”) guard from toString(), the early returns for undefined operands in operator== and operator!=, and the “Undefined” fallbacks for scheme and host in operator<<
  • Request’s operator<< prints the URL without an isDefined() check, and Client::Fetch and Client::List no longer check aUrl.isDefined(). Their core-owned Directory/File isDefined() checks are unchanged
  • Python: remove URL.undefined() and URL.is_defined(); URL(…), set_scheme and set_host raise RuntimeError for an empty scheme or host
  • Remove the URL.undefined() and url.is_defined() cells from the URL reference notebook

url::Query::Undefined() and Query::isDefined() are unchanged: an “undefined” query is the empty query, a valid value with ordinary equality and no guards.

BREAKING CHANGE: removed URL::Undefined and URL::isDefined. Use std::optional where a URL may be absent (for example a variable that is assigned later), and drop isDefined() checks on URLs. Constructing a URL with an empty scheme or host, or setting one, now throws ostk::core::error::runtime::Undefined instead of producing an undefined URL. Python: URL.undefined() and URL.is_defined() are removed; use None for “no URL”.

Co-Authored-By: Claude Opus 5.5 noreply@anthropic.com


Co-authored-by: Claude Opus 5.5 noreply@anthropic.com

  • refactor!: normalize getters to return const references for stored members (#133)

Only getters are kept. Stored non-trivial members return const T& so the caller decides whether to copy. Computed and trivial values return by value.

  • URL: the const accessScheme/accessHost/accessPath/accessPort/accessUser/ accessPassword/accessQuery/accessFragment duplicates are removed; getScheme/getHost/getPath/getUser/getPassword/getFragment return const String&, getPort returns const std::optional<int>& and getQuery returns const Query&
  • url::Query::Parameter: the const accessName/accessValue duplicates are removed; getName/getValue return const String&
  • http::Request: getUrl returns const URL& and getBody returns const String&
  • http::Response: getBody returns const String& (with a && overload returning a copy, so Client::Get(url).getBody() does not dangle)
  • Client::Send now passes a pointer into the request’s stored body to CURLOPT_POSTFIELDS instead of into a destroyed temporary copy
  • Python: get_body on Response is bound through a lambda because of the ref-qualified overloads; Python names and return values are unchanged

BREAKING CHANGE: URL::accessScheme/accessHost/accessPath/accessPort/ accessUser/accessPassword/accessQuery/accessFragment and url::Query::Parameter::accessName/accessValue are removed (use the get* getters). URL::getScheme/getHost/getPath/getUser/getPassword/getFragment, Query::Parameter::getName/getValue and Request::getBody now return const String&, URL::getPort returns const std::optional<int>&, URL::getQuery returns const Query&, Request::getUrl returns const URL&, and Response::getBody is ref-qualified (const String& getBody() const&, String getBody() &&), so member pointers to it are ambiguous.

Co-authored-by: Claude Opus 5.5 noreply@anthropic.com

  • build!: migrate python bindings from pybind11 to nanobind (#134)

  • build!: adapt to open-space-toolkit-core v6

Move to open-space-toolkit-core 6 and adapt every call site to its API. No public API of this repository changes.

  • CMake: FIND_PACKAGE (OpenSpaceToolkitCore 6). The development image now installs the latest core 6 packages (OSTK_CORE_MAJOR=”6”).
  • Python: open-space-toolkit-core~=6.0 in pyproject.toml.in.
  • Core’s Directory/File::Undefined() and isDefined() were removed (core 2b2ed644), so a Directory or File is always defined:
    • Client::Fetch no longer checks aDirectory.isDefined(), and the File::Undefined() placeholder is gone: the destination File is now declared where it is built from the directory and the URL path.
    • Client::List no longer checks aFile.isDefined().
    • The Fetch test cases that passed Directory::Undefined() (and a commented-out List case that passed File::Undefined()) are removed.

Steps 1-3 of this release listed these as the core boundaries. The other core APIs io uses (Path, String::Format, Array range-for, File/Directory getPath, error::RuntimeError and error::runtime::Undefined) are unchanged in core 6, and io uses no Real, Integer or const access* from core.

BREAKING CHANGE: requires open-space-toolkit-core 6 (C++ and Python). Client::Fetch and Client::List no longer throw ostk::core::error::runtime::Undefined for an undefined Directory/File, because core 6 cannot construct one.

Co-Authored-By: Claude Opus 5.5 noreply@anthropic.com

  • build!: migrate python bindings from pybind11 to nanobind

Follow open-space-toolkit-core v6.0.0 (ed59a510, nanobind v3.1.0) and move the Python bindings from pybind11 to nanobind. The build files mirror core’s: nanobind is fetched with FetchContent (pinned to v3.1.0, as core, so that both extension modules share one nanobind ABI and core’s types resolve here), its runtime is built once per Python version from nb_combined.cpp (NB_ADD_LIBRARY, with -fno-strict-aliasing, hidden visibility and NB_COMPACT_ASSERTIONS outside Debug), PY_STRIP replaces pybind11_strip, and stubs come from nanobind’s stubgen, written into the package directory so that the wheel ships them (with py.typed). No development image change is needed. The README dependency table lists nanobind instead of pybind11.

Python 3.9 is dropped (nanobind 3 and core 6 both require Python >= 3.10): PYTHON_SEARCH_VERSIONS is 3.10-3.14, requires-python is “>=3.10” and uv.lock is regenerated.

The bindings translate almost mechanically. The parts that do not:

  • pybind11/operators.h: URL, Query and Query.Parameter ==/!= and URL + String are explicit lambdas bound to their dunder names with is_operator(). URL += String takes URL& and returns it under rv_policy::none, so a += b keeps returning a itself.
  • nanobind has no umbrella STL header. Utilities/ArrayCasting.hpp now includes the nanobind STL casters (as core’s does; std::string and the std::optional<int> URL port need them) next to the Array<T> list caster, and is included once at the top of the module, before any binding that uses those casters.
  • "doSanitize"_a = false needs using namespace nanobind::literals.
  • pybind11 set __hash__ = None on classes that define __eq__ (as Python does for class bodies); nanobind keeps the identity hash. The module now restores the pybind11 rule for its own classes at import (Utilities/Hash.hpp, the same helper as mathematics), so URL, Query and Query.Parameter stay unhashable.

No init(factory), make_iterator, arg_v, handle.cast, trampoline, holder type, custom exception, implicitly_convertible, Eigen or NumPy is used in this module. The const& getters (normalised in the previous commits) copy under nanobind’s default policy, as under pybind11, and Response.get_body stays a by-value lambda over the ref-qualified overloads.

Verification: the 12 existing Python tests pass unchanged. New tests pin URL += returning the same object and the unhashable classes, and test/test_cross_module.py passes core v6 objects into and out of this module (String arguments, the str -> String implicit conversion registered by core, String return values, a Directory argument and a File return value through Client.fetch on a file:// URL, and a File argument to Client.list). All 19 pass on both the pybind11 build and this one. dir() of every class is unchanged apart from the pybind11-only _pybind11_conduit_v1_ attribute and the enums (below). Importing and exercising the module reports no nanobind leaks at shutdown. On Python 3.11 the stripped extension module is 15% smaller (328 kB -> 280 kB), and a micro-benchmark of ten call shapes (method calls, ==, parse, construction, operators, enum and list arguments) is 3.3x faster by geometric mean (1.2x to 6.5x).

User-visible behaviour changes:

  • Request.Method and Response.StatusCode are Python enum.Enum subclasses, as in core v6: int(member) raises TypeError (use .value), repr(member) is Method.Get instead of <Method.Get: 0>, and __members__ is a mappingproxy instead of a dict. .name, .value, member order, equality, hashing and Method(0) are unchanged. An enum parameter now also accepts the plain int value (Request(0, url, "")), which pybind11 rejected with TypeError.
  • Error messages for failed argument conversions follow nanobind’s wording (“incompatible function arguments”, unqualified type names such as URL instead of ostk.io.URL); the exception types are unchanged (TypeError). No io binding takes a C++ char, so core’s ValueError -> TypeError change has no counterpart here.

Not addressed:

  • Utilities/IterableConverter.hpp (Boost.Python, never included) is left as it was.
  • URL.set_array (a no-op free function bound as a method, so it is only callable as URL.set_array([...])) is kept as is; its stub now reads set_array(self).
  • The BUILD_WHEELS_IN_CMAKE=OFF branch still generates no stubs (as in core).
  • nanobind’s own runtime sources trigger -Wshadow warnings under this project’s flags; the binding sources build warning-free.

BREAKING CHANGE: Python 3.9 is no longer supported; enums are enum.Enum (no int()).

Co-Authored-By: Claude Opus 5.5 noreply@anthropic.com


Co-authored-by: Claude Opus 5.5 noreply@anthropic.com


Co-authored-by: Claude Opus 5.5 noreply@anthropic.com

2天前209次提交

Open Space Toolkit ▸ I/O

Build and Test Release Code Coverage Documentation GitHub version PyPI version License

Addressing, networking, database connectors.

Getting Started

Want to get started? This is the simplest and quickest way:

Binder

Nothing to download or install! This will automatically start a JupyterLab environment in your browser with Open Space Toolkit libraries and example notebooks ready to use.

Alternatives

Docker Images

Docker must be installed on your system.

iPython

The following command will start an iPython shell within a container where the OSTk components are already installed:

docker run -it openspacecollective/open-space-toolkit-io-development python3.11 -m IPython

Once the shell is up and running, playing with it is easy:

from ostk.io import URL # URL class
from ostk.io.ip.tcp.http import Client # HTTP client class

url = URL.parse("https://www.google.com") # Construct a URL

response = Client.get(url) # Send an HTTP GET request (over HTTPS)

response.get_status_code() # Display the status code of the HTTP response

Tip: Use tab for auto-completion!

JupyterLab

The following command will start a JupyterLab server within a container where the OSTk components are already installed:

docker run --publish=8888:8888 openspacecollective/open-space-toolkit-io-jupyter

Once the container is running, access http://localhost:8888/lab and create a Python 3 Notebook.

Installation

C++

The binary packages are hosted using GitHub Releases:

  • Runtime libraries: open-space-toolkit-io-X.Y.Z-1.x86_64-runtime
  • C++ headers: open-space-toolkit-io-X.Y.Z-1.x86_64-devel
  • Python bindings: open-space-toolkit-io-X.Y.Z-1.x86_64-python

Debian / Ubuntu

After downloading the relevant .deb binary packages, install:

apt install open-space-toolkit-io-*.deb

Python

Install from PyPI:

pip install open-space-toolkit-io

Documentation

Documentation is available here:

Structure

The library exhibits the following structure:

├── IP
│   ├── Address
│   └── TCP
│       ├── Client
│       ├── Server
│       └── HTTP
│           ├── Client
│           └── Server
└── URL
    └── Query

Tutorials

Tutorials are available here:

Setup

Development Environment

Using Docker for development is recommended, to simplify the installation of the necessary build tools and dependencies. Instructions on how to install Docker are available here.

To start the development environment:

make start-development

This will:

  1. Build the openspacecollective/open-space-toolkit-io-development Docker image.
  2. Create a development environment container with local source files and helper scripts mounted.
  3. Start a bash shell from the ./build working directory.

If installing Docker is not an option, you can manually install the development tools (GCC, CMake) and all required dependencies, by following a procedure similar to the one described in the Development Dockerfile.

Build

From the ./build directory:

cmake ..
make

Tip: ostk-build simplifies building from within the development environment.

Test

To start a container to build and run the tests:

make test

Or to run them manually:

./bin/open-space-toolkit-io.test

Tip: ostk-test simplifies running tests from within the development environment.

Dependencies

Name Version License Link
nanobind 3.1.0 BSD-3-Clause github.com/wjakob/nanobind
{fmt} 5.2.0 BSD-2-Clause github.com/fmtlib/fmt
Core main Apache License 2.0 github.com/open-space-collective/open-space-toolkit-core

Contribution

Contributions are more than welcome!

Please read our contributing guide to learn about our development process, how to propose fixes and improvements, and how to build and test the code.

Special Thanks

Loft Orbital

License

Apache License 2.0

关于

Open Space Toolkit IO 组件(YAML/JSON 等数据序列化)。镜像收录自 https://github.com/open-space-collective/open-space-toolkit-io,License:Apache-2.0

8.2 MB
邀请码
    Gitlink(确实开源)
  • 加入我们
  • 官网邮箱:gitlink@ccf.org.cn
  • QQ群
  • QQ群
  • 公众号
  • 公众号

版权所有:中国计算机学会技术支持:开源发展技术委员会
京ICP备13000930号-9 京公网安备 11010802047560号