diff --git a/.github/workflows/python-wheel-workflow.yml b/.github/workflows/python-wheel-workflow.yml index 4504bd40f..c80403251 100644 --- a/.github/workflows/python-wheel-workflow.yml +++ b/.github/workflows/python-wheel-workflow.yml @@ -114,6 +114,8 @@ jobs: CIBW_PLATFORM: ${{ matrix.os }} CIBW_BUILD: "cp39-* cp310-* cp311-* cp312-* cp313-*" CIBW_SKIP: "*-musllinux_*" + # Use uv on macOS to avoid transient GitHub rate limits when cibuildwheel + CIBW_BUILD_FRONTEND: ${{ matrix.os == 'macos' && 'build[uv]' || 'build' }} # Pin arch to the matrix platform CIBW_ARCHS: ${{ matrix.platform }} CIBW_MANYLINUX_X86_64_IMAGE: ${{ matrix.os == 'linux' && format('manylinux{0}', matrix.manylinux) || '' }} @@ -232,7 +234,11 @@ jobs: run: | set -euxo pipefail python -m pip install --upgrade pip - python -m pip install packaging cibuildwheel + if [ "${{ matrix.os }}" = "macos" ]; then + python -m pip install packaging "cibuildwheel[uv]>=2.22" + else + python -m pip install packaging "cibuildwheel>=2.22" + fi mkdir -p python/dist python -m cibuildwheel --output-dir python/dist "$PKGDIR" diff --git a/cpp/CMakeLists.txt b/cpp/CMakeLists.txt index f1fa70e98..cf87165e5 100644 --- a/cpp/CMakeLists.txt +++ b/cpp/CMakeLists.txt @@ -419,4 +419,4 @@ add_custom_target(graphar-clformat add_custom_target(graphar-cpplint COMMAND ${PROJECT_SOURCE_DIR}/misc/cpplint.py --root=${PROJECT_SOURCE_DIR}/include ${FILES_NEED_LINT} COMMENT "Running cpplint check." - VERBATIM) + VERBATIM) \ No newline at end of file diff --git a/cpp/src/graphar/graph_info.cc b/cpp/src/graphar/graph_info.cc index 84f39518f..26669b78f 100644 --- a/cpp/src/graphar/graph_info.cc +++ b/cpp/src/graphar/graph_info.cc @@ -28,6 +28,7 @@ #include "graphar/graph_info.h" #include "graphar/result.h" #include "graphar/types.h" +#include "graphar/util.h" #include "graphar/version_parser.h" #include "graphar/yaml.h" @@ -1102,24 +1103,6 @@ Status EdgeInfo::Save(const std::string& path) const { namespace { -static std::string PathToDirectory(const std::string& path) { - if (path.rfind("s3://", 0) == 0) { - size_t t = path.find_last_of('?'); - std::string prefix = path.substr(0, t); - std::string suffix = path.substr(t); - const size_t last_slash_idx = prefix.rfind('/'); - if (std::string::npos != last_slash_idx) { - return prefix.substr(0, last_slash_idx + 1) + suffix; - } - } else { - const size_t last_slash_idx = path.rfind('/'); - if (std::string::npos != last_slash_idx) { - return path.substr(0, last_slash_idx + 1); // +1 to include the slash - } - } - return path; -} - static Result> ConstructGraphInfo( std::shared_ptr graph_meta, const std::string& default_name, const std::string& default_prefix, const std::shared_ptr fs, @@ -1411,8 +1394,8 @@ Result> GraphInfo::Load(const std::string& path) { fs->ReadFileToValue(no_url_path)); GAR_ASSIGN_OR_RAISE(auto graph_meta, Yaml::Load(yaml_content)); std::string default_name = "graph"; - std::string default_prefix = PathToDirectory(path); - no_url_path = PathToDirectory(no_url_path); + std::string default_prefix = util::PathToDirectory(path); + no_url_path = util::PathToDirectory(no_url_path); return ConstructGraphInfo(graph_meta, default_name, default_prefix, fs, no_url_path); } @@ -1486,5 +1469,4 @@ Status GraphInfo::Save(const std::string& path) const { GAR_ASSIGN_OR_RAISE(auto yaml_content, this->Dump()); return fs->WriteValueToFile(yaml_content, no_url_path); } - } // namespace graphar diff --git a/cpp/src/graphar/util.cc b/cpp/src/graphar/util.cc index 0712e0700..ebdfe359a 100644 --- a/cpp/src/graphar/util.cc +++ b/cpp/src/graphar/util.cc @@ -106,4 +106,23 @@ std::string ValueGetter::Value(const void* data, int64_t offset) { reinterpret_cast(data)->GetView(offset)); } +std::string PathToDirectory(const std::string& path) { + if (path.rfind("s3://", 0) == 0) { + size_t t = path.find_last_of('?'); + + std::string prefix = (t == std::string::npos) ? path : path.substr(0, t); + std::string suffix = (t == std::string::npos) ? "" : path.substr(t); + + const size_t last_slash_idx = prefix.rfind('/'); + if (std::string::npos != last_slash_idx) { + return prefix.substr(0, last_slash_idx + 1) + suffix; + } + } else { + const size_t last_slash_idx = path.rfind('/'); + if (std::string::npos != last_slash_idx) { + return path.substr(0, last_slash_idx + 1); + } + } + return path; +} } // namespace graphar::util diff --git a/cpp/src/graphar/util.h b/cpp/src/graphar/util.h index 1ef13a3ea..61bc59bc3 100644 --- a/cpp/src/graphar/util.h +++ b/cpp/src/graphar/util.h @@ -273,4 +273,6 @@ static arrow::Status OpenParquetArrowReader( return arrow::Status::OK(); } +std::string PathToDirectory(const std::string& path); + } // namespace graphar::util diff --git a/cpp/test/CMakeLists.txt b/cpp/test/CMakeLists.txt index 35f25ce04..29fb3ed00 100644 --- a/cpp/test/CMakeLists.txt +++ b/cpp/test/CMakeLists.txt @@ -81,3 +81,4 @@ add_graphar_test(test_arrow_chunk_reader SRCS test_arrow_chunk_reader.cc) add_graphar_test(test_graph SRCS test_graph.cc) add_graphar_test(test_multi_label SRCS test_multi_label.cc) add_graphar_test(test_multi_property SRCS test_multi_property.cc) +add_graphar_test(test_util SRCS test_util.cc) diff --git a/cpp/test/test_util.cc b/cpp/test/test_util.cc new file mode 100644 index 000000000..ba3d40072 --- /dev/null +++ b/cpp/test/test_util.cc @@ -0,0 +1,51 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include +#include + +#include +#include "./util.h" +#include "graphar/util.h" + +namespace graphar { + +TEST_CASE("PathUtilTest", "[util]") { + SECTION("PathToDirectory_S3_Handling") { + std::string s3_with_query = "s3://bucket/path/graph.yml?version=123"; + REQUIRE(util::PathToDirectory(s3_with_query) == + "s3://bucket/path/?version=123"); + + std::string s3_no_query = "s3://bucket/path/graph.yml"; + REQUIRE(util::PathToDirectory(s3_no_query) == "s3://bucket/path/"); + + std::string s3_root = "s3://bucket/graph.yml"; + REQUIRE(util::PathToDirectory(s3_root) == "s3://bucket/"); + } + + SECTION("PathToDirectory_Local_Handling") { + std::string local_path = "/tmp/data/graph.yml"; + REQUIRE(util::PathToDirectory(local_path) == "/tmp/data/"); + + std::string relative_path = "graph.yml"; + REQUIRE(util::PathToDirectory(relative_path) == "graph.yml"); + } +} + +} // namespace graphar diff --git a/python/README.md b/python/README.md index c6a5e8ff5..70325da9f 100644 --- a/python/README.md +++ b/python/README.md @@ -1,12 +1,12 @@ # GraphAr Python SDK -GraphAr Python SDK provides Python bindings for the GraphAr C++ library, allowing user to work with GraphAr formatted graph data in Python environments. It includes both a high-level API for data manipulation and a command-line interface for common operations. +GraphAr Python SDK provides Python bindings for the GraphAr C++ library, allowing users to work with GraphAr formatted graph data in Python environments. It includes both a high-level API for data manipulation and a command-line interface for common operations. ## Installation ### Prerequisites -- Python >= 3.7 +- Python >= 3.9 - pip (latest version recommended) - CMake >= 3.15 (for building from source) - Apache Arrow >= 12.0 (for building from source)