diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8acfbc292..7209d7d5a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -7,23 +7,17 @@ on: branches: [main] jobs: - test-ubuntu-py38: - runs-on: ${{matrix.os}} + test-ubuntu-py39-coverage: + runs-on: ubuntu-latest timeout-minutes: 20 - strategy: - fail-fast: false - matrix: - os: [ubuntu-latest] - python-version: - - "3.8" steps: - uses: actions/checkout@v3 - - name: Set up Python ${{ matrix.python-version }} + - name: Set up Python 3.9 uses: actions/setup-python@v4 with: - python-version: ${{ matrix.python-version }} + python-version: "3.9" - name: Upgrade pip version run: | @@ -33,6 +27,7 @@ jobs: run: | python -m pip install -r requirements.txt python -m pip install -r docs/requirements.txt + python -m pip install spin - name: Install lcov run: | @@ -40,12 +35,15 @@ jobs: sudo apt-get install -y lcov - name: Build package + env: + CXXFLAGS: "-std=c++17 --coverage" + CFLAGS: "--coverage" run: | - CXXFLAGS="-std=c++17 --coverage" CFLAGS="--coverage" python scripts/build/install.py - # coverage tests + spin build -v + - name: Run tests run: | - python -m pytest --doctest-modules --cov=./ --cov-report=xml -s + spin test -v - name: Capture Coverage Data with lcov run: | @@ -72,7 +70,7 @@ jobs: run: | sphinx-build -b html docs/source/ docs/build/html - test-ubuntu-py39-py310: + test-ubuntu-py39-py310-py311: runs-on: ${{matrix.os}} timeout-minutes: 20 strategy: @@ -82,6 +80,7 @@ jobs: python-version: - "3.9" - "3.10" + - "3.11" steps: - uses: actions/checkout@v3 @@ -99,14 +98,17 @@ jobs: run: | python -m pip install -r requirements.txt python -m pip install -r docs/requirements.txt + python -m pip install spin - name: Build package + env: + CXXFLAGS: "-std=c++17" run: | - CXXFLAGS="-std=c++17" python scripts/build/install.py + spin build -v - name: Run tests run: | - python -c "import pydatastructs; pydatastructs.test(only_benchmarks=True)" + spin test -v - name: Build Documentation run: | @@ -120,9 +122,9 @@ jobs: matrix: os: [macos-latest] python-version: - - "3.8" - "3.9" - "3.10" + - "3.11" steps: - uses: actions/checkout@v3 @@ -140,66 +142,57 @@ jobs: run: | python -m pip install -r requirements.txt python -m pip install -r docs/requirements.txt + python -m pip install spin - name: Build package env: MACOSX_DEPLOYMENT_TARGET: 11.0 + CXXFLAGS: "-std=c++17" run: | - CXXFLAGS="-std=c++17" python scripts/build/install.py + spin build -v + - name: Run tests run: | - python -c "import pydatastructs; pydatastructs.test()" + spin test -v - name: Build Documentation run: | sphinx-build -b html docs/source/ docs/build/html - # test-windows: - # runs-on: ${{matrix.os}} - # timeout-minutes: 20 - # strategy: - # fail-fast: false - # matrix: - # os: [windows-latest] - # python-version: - # - "3.8" - - # steps: - # - uses: actions/checkout@v3 - - # - name: Set up Python ${{ matrix.python-version }} - # uses: actions/setup-python@v4 - # with: - # python-version: ${{ matrix.python-version }} - - # - name: Setup conda - # uses: s-weigand/setup-conda@v1 - # with: - # update-conda: true - # python-version: ${{ matrix.python-version }} - # conda-channels: anaconda, conda-forge - # # - run: conda --version # This fails due to unknown reasons - # - run: which python - - # - name: Upgrade pip version - # run: | - # python -m pip install --upgrade pip - - # - name: Install requirements - # run: | - # python -m pip install -r requirements.txt - # python -m pip install -r docs/requirements.txt - - # - name: Build package - # env: - # CL: "/std:c++17" - # run: | - # python scripts/build/install.py - - # - name: Run tests - # run: | - # python -c "import pydatastructs; pydatastructs.test()" - - # - name: Build Documentation - # run: | - # sphinx-build -b html docs/source/ docs/build/html + test-windows: + runs-on: windows-latest + strategy: + fail-fast: false + matrix: + python-version: ["3.9", "3.10", "3.11"] + + steps: + - uses: actions/checkout@v3 + + - uses: actions/setup-python@v4 + with: + python-version: ${{ matrix.python-version }} + + - uses: ilammy/msvc-dev-cmd@v1 + + - name: Upgrade pip + run: python -m pip install --upgrade pip + + - name: Install requirements + run: | + python -m pip install -r requirements.txt + python -m pip install -r docs/requirements.txt + python -m pip install spin + + - name: Build package + env: + CFLAGS: "/MD" + CXXFLAGS: "/std:c++17 /MD /Zc:strictStrings-" + CL: "/std:c++17 /MD /Zc:strictStrings-" + run: spin build -v + + - name: Run tests + run: spin test -v + + - name: Build Documentation + run: sphinx-build -b html docs/source/ docs/build/html diff --git a/environment.yml b/environment.yml index 2d2ce160d..f08245fbc 100644 --- a/environment.yml +++ b/environment.yml @@ -9,6 +9,8 @@ dependencies: - pip: - codecov - pytest-cov + - spin + - meson - sphinx==5.0 - sphinx-readable-theme==1.3.0 - myst_nb==0.17.2 diff --git a/meson.build b/meson.build new file mode 100644 index 000000000..86aa0c2cb --- /dev/null +++ b/meson.build @@ -0,0 +1,8 @@ +project('pydatastructs', 'cpp', + version : '1.0.1-dev', + default_options : ['cpp_std=c++17']) + + +python = import('python').find_installation(pure: false) + +subdir('pydatastructs') diff --git a/pydatastructs/graphs/__init__.py b/pydatastructs/graphs/__init__.py index c1a70574a..21e0a5f35 100644 --- a/pydatastructs/graphs/__init__.py +++ b/pydatastructs/graphs/__init__.py @@ -9,7 +9,6 @@ from . import algorithms from . import adjacency_list from . import adjacency_matrix -from . import _extensions from .algorithms import ( breadth_first_search, diff --git a/pydatastructs/graphs/_backend/cpp/graph.cpp b/pydatastructs/graphs/_backend/cpp/graph.cpp index d41ca60f4..67b1b4572 100644 --- a/pydatastructs/graphs/_backend/cpp/graph.cpp +++ b/pydatastructs/graphs/_backend/cpp/graph.cpp @@ -4,45 +4,64 @@ #include "AdjacencyMatrix.hpp" #include "AdjacencyListGraphNode.hpp" #include "AdjacencyMatrixGraphNode.hpp" +#include "GraphEdge.hpp" +#include "GraphNode.hpp" #include "graph_bindings.hpp" +#include "Algorithms.hpp" -#ifdef __cplusplus -extern "C" { -#endif - -PyMODINIT_FUNC PyInit__graph(void); - -#ifdef __cplusplus -} -#endif +static PyMethodDef GraphMethods[] = { + {"bfs_adjacency_list", (PyCFunction)breadth_first_search_adjacency_list, METH_VARARGS | METH_KEYWORDS, "Run BFS on adjacency list with callback"}, + {"bfs_adjacency_matrix", (PyCFunction)breadth_first_search_adjacency_matrix, METH_VARARGS | METH_KEYWORDS, "Run BFS on adjacency matrix with callback"}, + {"minimum_spanning_tree_prim_adjacency_list", (PyCFunction)minimum_spanning_tree_prim_adjacency_list, METH_VARARGS | METH_KEYWORDS, "Run Prim's algorithm on adjacency list"}, + {"shortest_paths_dijkstra_adjacency_list", (PyCFunction)shortest_paths_dijkstra_adjacency_list, METH_VARARGS | METH_KEYWORDS, "Dijkstra's algorithm for adjacency list graphs"}, + {NULL, NULL, 0, NULL} +}; static struct PyModuleDef graph_module = { PyModuleDef_HEAD_INIT, "_graph", "C++ module for graphs", -1, - NULL, + GraphMethods, }; PyMODINIT_FUNC PyInit__graph(void) { PyObject* m; - if (PyType_Ready(&AdjacencyListGraphType) < 0) + if (PyType_Ready(&GraphNodeType) < 0) return NULL; if (PyType_Ready(&AdjacencyListGraphNodeType) < 0) return NULL; - if (PyType_Ready(&AdjacencyMatrixGraphType) < 0) + if (PyType_Ready(&AdjacencyMatrixGraphNodeType) < 0) return NULL; - if (PyType_Ready(&AdjacencyMatrixGraphNodeType) < 0) + if (PyType_Ready(&GraphEdgeType) < 0) + return NULL; + + if (PyType_Ready(&AdjacencyListGraphType) < 0) + return NULL; + + if (PyType_Ready(&AdjacencyMatrixGraphType) < 0) return NULL; m = PyModule_Create(&graph_module); if (m == NULL) return NULL; + Py_INCREF(&GraphNodeType); + PyModule_AddObject(m, "GraphNode", (PyObject*)&GraphNodeType); + + Py_INCREF(&AdjacencyListGraphNodeType); + PyModule_AddObject(m, "AdjacencyListGraphNode", (PyObject*)&AdjacencyListGraphNodeType); + + Py_INCREF(&AdjacencyMatrixGraphNodeType); + PyModule_AddObject(m, "AdjacencyMatrixGraphNode", (PyObject*)&AdjacencyMatrixGraphNodeType); + + Py_INCREF(&GraphEdgeType); + PyModule_AddObject(m, "GraphEdge", (PyObject*)&GraphEdgeType); + Py_INCREF(&AdjacencyListGraphType); if (PyModule_AddObject(m, "AdjacencyListGraph", (PyObject*)&AdjacencyListGraphType) < 0) { Py_DECREF(&AdjacencyListGraphType); @@ -50,13 +69,6 @@ PyMODINIT_FUNC PyInit__graph(void) { return NULL; } - Py_INCREF(&AdjacencyListGraphNodeType); - if (PyModule_AddObject(m, "AdjacencyListGraphNode", (PyObject*)&AdjacencyListGraphNodeType) < 0) { - Py_DECREF(&AdjacencyListGraphNodeType); - Py_DECREF(m); - return NULL; - } - Py_INCREF(&AdjacencyMatrixGraphType); if (PyModule_AddObject(m, "AdjacencyMatrixGraph", (PyObject*)&AdjacencyMatrixGraphType) < 0) { Py_DECREF(&AdjacencyMatrixGraphType); diff --git a/pydatastructs/graphs/algorithms.py b/pydatastructs/graphs/algorithms.py index 9324b7278..6c2182fed 100644 --- a/pydatastructs/graphs/algorithms.py +++ b/pydatastructs/graphs/algorithms.py @@ -92,7 +92,7 @@ def breadth_first_search( return getattr(algorithms, func)( graph, source_node, operation, *args, **kwargs) else: - from pydatastructs.graphs._backend.cpp._algorithms import bfs_adjacency_list, bfs_adjacency_matrix + from pydatastructs.graphs._backend.cpp._graph import bfs_adjacency_list, bfs_adjacency_matrix if (graph._impl == "adjacency_list"): extra_args = args if args else () return bfs_adjacency_list(graph, source_node, operation, extra_args) @@ -349,7 +349,7 @@ def minimum_spanning_tree(graph, algorithm, **kwargs): %(algorithm, graph._impl)) return getattr(algorithms, func)(graph) else: - from pydatastructs.graphs._backend.cpp._algorithms import minimum_spanning_tree_prim_adjacency_list + from pydatastructs.graphs._backend.cpp._graph import minimum_spanning_tree_prim_adjacency_list if graph._impl == "adjacency_list" and algorithm == 'prim': return minimum_spanning_tree_prim_adjacency_list(graph) @@ -814,7 +814,7 @@ def shortest_paths(graph: Graph, algorithm: str, "finding shortest paths in graphs."%(algorithm)) return getattr(algorithms, func)(graph, source, target) else: - from pydatastructs.graphs._backend.cpp._algorithms import shortest_paths_dijkstra_adjacency_list + from pydatastructs.graphs._backend.cpp._graph import shortest_paths_dijkstra_adjacency_list if graph._impl == "adjacency_list" and algorithm == 'dijkstra': return shortest_paths_dijkstra_adjacency_list(graph, source, target) diff --git a/pydatastructs/graphs/meson.build b/pydatastructs/graphs/meson.build new file mode 100644 index 000000000..2cda248cc --- /dev/null +++ b/pydatastructs/graphs/meson.build @@ -0,0 +1,34 @@ +python = import('python').find_installation(pure: false) + +python.install_sources( + [ + '__init__.py', + 'adjacency_list.py', + 'adjacency_matrix.py', + 'algorithms.py', + 'graph.py' + ], + subdir: 'pydatastructs/graphs' +) + +python.install_sources( + ['_backend/__init__.py', '_backend/cpp/__init__.py'], + subdir: 'pydatastructs/graphs/_backend' +) + +py_include = include_directories('../utils/_backend/cpp') + +python.extension_module( + '_graph', + [ + '_backend/cpp/graph.cpp', + '_backend/cpp/algorithms.cpp', + '../utils/_backend/cpp/graph_utils.cpp', + ], + include_directories: py_include, + install: true, + subdir: 'pydatastructs/graphs/_backend/cpp' +) + + +subdir('tests') \ No newline at end of file diff --git a/pydatastructs/graphs/tests/meson.build b/pydatastructs/graphs/tests/meson.build new file mode 100644 index 000000000..e887b63a9 --- /dev/null +++ b/pydatastructs/graphs/tests/meson.build @@ -0,0 +1,12 @@ +python = import('python').find_installation(pure: false) + +python.install_sources( + [ + '__init__.py', + 'test_adjacency_list.py', + 'test_adjacency_matrix.py', + 'test_algorithms.py' + ], + subdir: 'pydatastructs/graphs/tests', + install_tag: 'tests' +) diff --git a/pydatastructs/graphs/tests/test_adjacency_list.py b/pydatastructs/graphs/tests/test_adjacency_list.py index 3a9cdb14f..2544082b6 100644 --- a/pydatastructs/graphs/tests/test_adjacency_list.py +++ b/pydatastructs/graphs/tests/test_adjacency_list.py @@ -62,7 +62,7 @@ def test_adjacency_list(): assert g2.num_edges() == 3 assert g2.num_vertices() == 3 neighbors = g2.neighbors('v_4') - assert neighbors == [v_6, v_5] + assert set(neighbors) == {v_6, v_5} v = AdjacencyListGraphNode('v', 4, backend = Backend.CPP) g2.add_vertex(v) g2.add_edge('v_4', 'v', 0) diff --git a/pydatastructs/graphs/tests/test_algorithms.py b/pydatastructs/graphs/tests/test_algorithms.py index 04ebcccda..7dd2e1b78 100644 --- a/pydatastructs/graphs/tests/test_algorithms.py +++ b/pydatastructs/graphs/tests/test_algorithms.py @@ -6,7 +6,6 @@ from pydatastructs.utils.raises_util import raises from pydatastructs.utils.misc_util import AdjacencyListGraphNode, AdjacencyMatrixGraphNode from pydatastructs.graphs._backend.cpp import _graph -from pydatastructs.graphs._backend.cpp import _algorithms from pydatastructs.utils.misc_util import Backend def test_breadth_first_search(): diff --git a/pydatastructs/linear_data_structures/__init__.py b/pydatastructs/linear_data_structures/__init__.py index de247b88e..c6b3341d2 100644 --- a/pydatastructs/linear_data_structures/__init__.py +++ b/pydatastructs/linear_data_structures/__init__.py @@ -4,7 +4,6 @@ arrays, linked_lists, algorithms, - _extensions ) from .arrays import ( diff --git a/pydatastructs/linear_data_structures/_backend/cpp/algorithms/llvm_algorithms.py b/pydatastructs/linear_data_structures/_backend/cpp/algorithms/llvm_algorithms.py index 20c4c4ce6..24b14609d 100644 --- a/pydatastructs/linear_data_structures/_backend/cpp/algorithms/llvm_algorithms.py +++ b/pydatastructs/linear_data_structures/_backend/cpp/algorithms/llvm_algorithms.py @@ -13,7 +13,6 @@ _fn_ptr_cache = {} def _cleanup(): - """Clean up LLVM resources on exit.""" global _engines, _target_machine, _fn_ptr_cache _engines.clear() _target_machine = None @@ -27,20 +26,15 @@ def _ensure_target_machine(): return try: - binding.initialize() - binding.initialize_native_target() - binding.initialize_native_asmprinter() + binding.initialize_all_targets() + binding.initialize_all_asmprinters() target = binding.Target.from_default_triple() - _target_machine = target.create_target_machine( - opt=3, - features="+sse,+sse2,+sse3,+ssse3,+sse4.1,+sse4.2,+avx,+avx2" - ) + _target_machine = target.create_target_machine(opt=3) except Exception as e: raise RuntimeError(f"Failed to initialize LLVM target machine: {e}") def get_bubble_sort_ptr(dtype: str) -> int: - """Get function pointer for bubble sort with specified dtype.""" dtype = dtype.lower().strip() if dtype not in _SUPPORTED: raise ValueError(f"Unsupported dtype '{dtype}'. Supported: {list(_SUPPORTED)}") @@ -148,31 +142,15 @@ def _materialize(dtype: str) -> int: mod = binding.parse_assembly(llvm_ir) mod.verify() - pmb = binding.PassManagerBuilder() - pmb.opt_level = 3 - pmb.loop_vectorize = True - pmb.slp_vectorize = True - - fpm = binding.create_function_pass_manager(mod) - pm = binding.create_module_pass_manager() - - pm.add_basic_alias_analysis_pass() - pm.add_type_based_alias_analysis_pass() - pm.add_instruction_combining_pass() - pm.add_gvn_pass() - pm.add_cfg_simplification_pass() - pm.add_loop_unroll_pass() - pm.add_loop_unswitch_pass() - - pmb.populate(fpm) - pmb.populate(pm) - - fpm.initialize() - for func in mod.functions: - fpm.run(func) - fpm.finalize() - - pm.run(mod) + try: + pm = binding.ModulePassManager() + pm.add_instruction_combining_pass() + pm.add_reassociate_pass() + pm.add_gvn_pass() + pm.add_cfg_simplification_pass() + pm.run(mod) + except AttributeError: + pass engine = binding.create_mcjit_compiler(mod, _target_machine) engine.finalize_object() diff --git a/pydatastructs/linear_data_structures/_backend/cpp/algorithms/quadratic_time_sort.hpp b/pydatastructs/linear_data_structures/_backend/cpp/algorithms/quadratic_time_sort.hpp index 0e6b32d07..210382455 100644 --- a/pydatastructs/linear_data_structures/_backend/cpp/algorithms/quadratic_time_sort.hpp +++ b/pydatastructs/linear_data_structures/_backend/cpp/algorithms/quadratic_time_sort.hpp @@ -244,9 +244,15 @@ static PyObject* bubble_sort_llvm(PyObject* self, PyObject* args, PyObject* kwds PyErr_Clear(); } Py_DECREF(sys_path); + if (!mod) { + return NULL; + } PyObject* fn = PyObject_GetAttrString(mod, "get_bubble_sort_ptr"); Py_DECREF(mod); + if (!fn) { + return NULL; + } PyObject* arg = PyUnicode_FromString(dtype_str); if (!arg) { @@ -257,6 +263,9 @@ static PyObject* bubble_sort_llvm(PyObject* self, PyObject* args, PyObject* kwds PyObject* addr_obj = PyObject_CallFunctionObjArgs(fn, arg, NULL); Py_DECREF(fn); Py_DECREF(arg); + if (!addr_obj) { + return NULL; + } return addr_obj; }; diff --git a/pydatastructs/linear_data_structures/meson.build b/pydatastructs/linear_data_structures/meson.build new file mode 100644 index 000000000..439dd7455 --- /dev/null +++ b/pydatastructs/linear_data_structures/meson.build @@ -0,0 +1,39 @@ +python = import('python').find_installation(pure: false) + +python.install_sources( + [ + '__init__.py', + 'algorithms.py', + 'arrays.py', + 'linked_lists.py' + ], + subdir: 'pydatastructs/linear_data_structures' +) + +python.install_sources( + ['_backend/__init__.py', '_backend/cpp/__init__.py'], + subdir: 'pydatastructs/linear_data_structures/_backend' +) + +python.install_sources( + ['_backend/cpp/algorithms/llvm_algorithms.py'], + subdir: 'pydatastructs/linear_data_structures/_backend/cpp/algorithms' +) + +python.extension_module( + '_arrays', + '_backend/cpp/arrays/arrays.cpp', + install: true, + subdir: 'pydatastructs/linear_data_structures/_backend/cpp' +) + +python.extension_module( + '_algorithms', + '_backend/cpp/algorithms/algorithms.cpp', + install: true, + subdir: 'pydatastructs/linear_data_structures/_backend/cpp', + cpp_args: ['-std=c++17'], + override_options: ['cpp_std=c++17'], +) + +subdir('tests') diff --git a/pydatastructs/linear_data_structures/tests/meson.build b/pydatastructs/linear_data_structures/tests/meson.build new file mode 100644 index 000000000..343f068f4 --- /dev/null +++ b/pydatastructs/linear_data_structures/tests/meson.build @@ -0,0 +1,15 @@ +python = import('python').find_installation(pure: false) + +python.install_sources( + [ + '__init__.py', + 'benchmarks/__init__.py', + 'benchmarks/test_algorithms.py', + 'benchmarks/test_arrays.py', + 'test_algorithms.py', + 'test_arrays.py', + 'test_linked_lists.py' + ], + subdir: 'pydatastructs/linear_data_structures/tests', + install_tag: 'tests' +) diff --git a/pydatastructs/meson.build b/pydatastructs/meson.build new file mode 100644 index 000000000..f7e116460 --- /dev/null +++ b/pydatastructs/meson.build @@ -0,0 +1,10 @@ +python = import('python').find_installation(pure: false) + +python.install_sources(['__init__.py'], subdir: 'pydatastructs') + +subdir('utils') +subdir('linear_data_structures') +subdir('miscellaneous_data_structures') +subdir('trees') +subdir('graphs') +subdir('strings') diff --git a/pydatastructs/miscellaneous_data_structures/__init__.py b/pydatastructs/miscellaneous_data_structures/__init__.py index 60754c413..6ed099769 100644 --- a/pydatastructs/miscellaneous_data_structures/__init__.py +++ b/pydatastructs/miscellaneous_data_structures/__init__.py @@ -6,7 +6,6 @@ queue, disjoint_set, sparse_table, - _extensions, ) from .binomial_trees import ( diff --git a/pydatastructs/miscellaneous_data_structures/meson.build b/pydatastructs/miscellaneous_data_structures/meson.build new file mode 100644 index 000000000..644ec7e3b --- /dev/null +++ b/pydatastructs/miscellaneous_data_structures/meson.build @@ -0,0 +1,30 @@ +python = import('python').find_installation(pure: false) + +python.install_sources( + [ + '__init__.py', + 'algorithms.py', + 'multiset.py', + 'sparse_table.py', + 'disjoint_set.py', + 'queue.py', + 'binomial_trees.py', + 'segment_tree.py', + 'stack.py' + ], + subdir: 'pydatastructs/miscellaneous_data_structures' +) + +python.install_sources( + ['_backend/__init__.py', '_backend/cpp/__init__.py'], + subdir: 'pydatastructs/miscellaneous_data_structures/_backend' +) + +python.extension_module( + '_stack', + '_backend/cpp/stack/stack.cpp', + install: true, + subdir: 'pydatastructs/miscellaneous_data_structures/_backend/cpp' +) + +subdir('tests') diff --git a/pydatastructs/miscellaneous_data_structures/tests/meson.build b/pydatastructs/miscellaneous_data_structures/tests/meson.build new file mode 100644 index 000000000..9841338be --- /dev/null +++ b/pydatastructs/miscellaneous_data_structures/tests/meson.build @@ -0,0 +1,16 @@ +python = import('python').find_installation(pure: false) + +python.install_sources( + [ + '__init__.py', + 'test_binomial_trees.py', + 'test_disjoint_set.py', + 'test_multiset.py', + 'test_queue.py', + 'test_range_query_dynamic.py', + 'test_range_query_static.py', + 'test_stack.py' + ], + subdir: 'pydatastructs/miscellaneous_data_structures/tests', + install_tag: 'tests' +) diff --git a/pydatastructs/strings/meson.build b/pydatastructs/strings/meson.build new file mode 100644 index 000000000..5a588232d --- /dev/null +++ b/pydatastructs/strings/meson.build @@ -0,0 +1,12 @@ +python = import('python').find_installation(pure: false) + +python.install_sources( + [ + '__init__.py', + 'algorithms.py', + 'trie.py' + ], + subdir: 'pydatastructs/strings' +) + +subdir('tests') diff --git a/pydatastructs/strings/tests/meson.build b/pydatastructs/strings/tests/meson.build new file mode 100644 index 000000000..30f1da937 --- /dev/null +++ b/pydatastructs/strings/tests/meson.build @@ -0,0 +1,11 @@ +python = import('python').find_installation(pure: false) + +python.install_sources( + [ + '__init__.py', + 'test_algorithms.py', + 'test_trie.py' + ], + subdir: 'pydatastructs/strings/tests', + install_tag: 'tests' +) diff --git a/pydatastructs/trees/__init__.py b/pydatastructs/trees/__init__.py index 1c99cca25..892730122 100644 --- a/pydatastructs/trees/__init__.py +++ b/pydatastructs/trees/__init__.py @@ -5,7 +5,6 @@ m_ary_trees, space_partitioning_trees, heaps, - _extensions ) from .binary_trees import ( diff --git a/pydatastructs/trees/_backend/__init__.py b/pydatastructs/trees/_backend/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/pydatastructs/trees/_backend/cpp/__init__.py b/pydatastructs/trees/_backend/cpp/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/pydatastructs/trees/meson.build b/pydatastructs/trees/meson.build new file mode 100644 index 000000000..bcaae16ae --- /dev/null +++ b/pydatastructs/trees/meson.build @@ -0,0 +1,26 @@ +python = import('python').find_installation(pure: false) + +python.install_sources( + [ + '__init__.py', + 'binary_trees.py', + 'heaps.py', + 'm_ary_trees.py', + 'space_partitioning_trees.py' + ], + subdir: 'pydatastructs/trees' +) + +python.install_sources( + ['_backend/__init__.py', '_backend/cpp/__init__.py'], + subdir: 'pydatastructs/trees/_backend' +) + +python.extension_module( + '_trees', + '_backend/cpp/trees.cpp', + install: true, + subdir: 'pydatastructs/trees/_backend/cpp' +) + +subdir('tests') diff --git a/pydatastructs/trees/tests/meson.build b/pydatastructs/trees/tests/meson.build new file mode 100644 index 000000000..fcafdff37 --- /dev/null +++ b/pydatastructs/trees/tests/meson.build @@ -0,0 +1,14 @@ +python = import('python').find_installation(pure: false) + +python.install_sources( + [ + '__init__.py', + 'benchmarks/test_binary_trees.py', + 'test_binary_trees.py', + 'test_heaps.py', + 'test_m_ary_trees.py', + 'test_space_partitioning_tree.py' + ], + subdir: 'pydatastructs/trees/tests', + install_tag: 'tests' +) diff --git a/pydatastructs/utils/__init__.py b/pydatastructs/utils/__init__.py index 20a8c750c..c4971be32 100644 --- a/pydatastructs/utils/__init__.py +++ b/pydatastructs/utils/__init__.py @@ -3,7 +3,6 @@ from . import ( misc_util, testing_util, - _extensions ) from .misc_util import ( diff --git a/pydatastructs/utils/_backend/__init__.py b/pydatastructs/utils/_backend/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/pydatastructs/utils/_backend/cpp/AdjacencyListGraphNode.hpp b/pydatastructs/utils/_backend/cpp/AdjacencyListGraphNode.hpp index 4a41b0c3b..8eba3752d 100644 --- a/pydatastructs/utils/_backend/cpp/AdjacencyListGraphNode.hpp +++ b/pydatastructs/utils/_backend/cpp/AdjacencyListGraphNode.hpp @@ -79,11 +79,6 @@ static PyObject* AdjacencyListGraphNode_new(PyTypeObject* type, PyObject* args, for (Py_ssize_t i = 0; i < size; i++) { PyObject* node = PyList_GetItem(adjacency_list, i); - if (PyType_Ready(&AdjacencyListGraphNodeType) < 0) { - PyErr_SetString(PyExc_RuntimeError, "Failed to initialize AdjacencyListGraphNodeType"); - return NULL; - } - if (!PyObject_IsInstance(node, (PyObject*)&AdjacencyListGraphNodeType)) { PyErr_SetString(PyExc_TypeError, "Adjacency list must contain only AdjacencyListGraphNode instances"); return NULL; @@ -254,45 +249,5 @@ static PyMethodDef AdjacencyListGraphNode_methods[] = { {NULL} }; -inline PyTypeObject AdjacencyListGraphNodeType = { - /* tp_name */ PyVarObject_HEAD_INIT(NULL, 0) "AdjacencyListGraphNode", - /* tp_basicsize */ sizeof(AdjacencyListGraphNode), - /* tp_itemsize */ 0, - /* tp_dealloc */ (destructor)AdjacencyListGraphNode_dealloc, - /* tp_print */ 0, - /* tp_getattr */ 0, - /* tp_setattr */ 0, - /* tp_reserved */ 0, - /* tp_repr */ 0, - /* tp_as_number */ 0, - /* tp_as_sequence */ 0, - /* tp_as_mapping */ 0, - /* tp_hash */ 0, - /* tp_call */ 0, - /* tp_str */ (reprfunc)GraphNode_str, - /* tp_getattro */ 0, - /* tp_setattro */ 0, - /* tp_as_buffer */ 0, - /* tp_flags */ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, - /* tp_doc */ "Node Data Structure for an Adjacency List Graph", - /* tp_traverse */ 0, - /* tp_clear */ 0, - /* tp_richcompare */ 0, - /* tp_weaklistoffset */ 0, - /* tp_iter */ 0, - /* tp_iternext */ 0, - /* tp_methods */ AdjacencyListGraphNode_methods, - /* tp_members */ AdjacencyListGraphNode_PyMemberDef, - /* tp_getset */ AdjacencyListGraphNode_getsetters, - /* tp_base */ &GraphNodeType, - /* tp_dict */ 0, - /* tp_descr_get */ 0, - /* tp_descr_set */ 0, - /* tp_dictoffset */ 0, - /* tp_init */ 0, - /* tp_alloc */ 0, - /* tp_new */ AdjacencyListGraphNode_new, -}; - #endif diff --git a/pydatastructs/utils/_backend/cpp/AdjacencyMatrixGraphNode.hpp b/pydatastructs/utils/_backend/cpp/AdjacencyMatrixGraphNode.hpp index f5aaf5c9f..f8c0d2148 100644 --- a/pydatastructs/utils/_backend/cpp/AdjacencyMatrixGraphNode.hpp +++ b/pydatastructs/utils/_backend/cpp/AdjacencyMatrixGraphNode.hpp @@ -28,44 +28,4 @@ static PyObject* AdjacencyMatrixGraphNode_new(PyTypeObject* type, PyObject* args return reinterpret_cast(self); } -inline PyTypeObject AdjacencyMatrixGraphNodeType = { - /* tp_name */ PyVarObject_HEAD_INIT(NULL, 0) "AdjacencyMatrixGraphNode", - /* tp_basicsize */ sizeof(AdjacencyMatrixGraphNode), - /* tp_itemsize */ 0, - /* tp_dealloc */ (destructor)AdjacencyMatrixGraphNode_dealloc, - /* tp_print */ 0, - /* tp_getattr */ 0, - /* tp_setattr */ 0, - /* tp_reserved */ 0, - /* tp_repr */ 0, - /* tp_as_number */ 0, - /* tp_as_sequence */ 0, - /* tp_as_mapping */ 0, - /* tp_hash */ 0, - /* tp_call */ 0, - /* tp_str */ 0, - /* tp_getattro */ 0, - /* tp_setattro */ 0, - /* tp_as_buffer */ 0, - /* tp_flags */ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, - /* tp_doc */ "Node Data Structure for an Adjacency Matrix Graph", - /* tp_traverse */ 0, - /* tp_clear */ 0, - /* tp_richcompare */ 0, - /* tp_weaklistoffset */ 0, - /* tp_iter */ 0, - /* tp_iternext */ 0, - /* tp_methods */ 0, - /* tp_members */ 0, - /* tp_getset */ 0, - /* tp_base */ &GraphNodeType, - /* tp_dict */ 0, - /* tp_descr_get */ 0, - /* tp_descr_set */ 0, - /* tp_dictoffset */ 0, - /* tp_init */ 0, - /* tp_alloc */ 0, - /* tp_new */ AdjacencyMatrixGraphNode_new, -}; - #endif diff --git a/pydatastructs/utils/_backend/cpp/GraphEdge.hpp b/pydatastructs/utils/_backend/cpp/GraphEdge.hpp index 4008db17c..a1b5fa864 100644 --- a/pydatastructs/utils/_backend/cpp/GraphEdge.hpp +++ b/pydatastructs/utils/_backend/cpp/GraphEdge.hpp @@ -131,44 +131,4 @@ static PyGetSetDef GraphEdge_getsetters[] = { {NULL} }; -inline PyTypeObject GraphEdgeType = { - /* tp_name */ PyVarObject_HEAD_INIT(NULL, 0) "GraphEdge", - /* tp_basicsize */ sizeof(GraphEdge), - /* tp_itemsize */ 0, - /* tp_dealloc */ (destructor)GraphEdge_dealloc, - /* tp_print */ 0, - /* tp_getattr */ 0, - /* tp_setattr */ 0, - /* tp_reserved */ 0, - /* tp_repr */ 0, - /* tp_as_number */ 0, - /* tp_as_sequence */ 0, - /* tp_as_mapping */ 0, - /* tp_hash */ 0, - /* tp_call */ 0, - /* tp_str */ (reprfunc)GraphEdge_str, - /* tp_getattro */ 0, - /* tp_setattro */ 0, - /* tp_as_buffer */ 0, - /* tp_flags */ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, - /* tp_doc */ "Data Structure for a Graph Edge", - /* tp_traverse */ 0, - /* tp_clear */ 0, - /* tp_richcompare */ 0, - /* tp_weaklistoffset */ 0, - /* tp_iter */ 0, - /* tp_iternext */ 0, - /* tp_methods */ 0, - /* tp_members */ 0, - /* tp_getset */ GraphEdge_getsetters, - /* tp_base */ 0, - /* tp_dict */ 0, - /* tp_descr_get */ 0, - /* tp_descr_set */ 0, - /* tp_dictoffset */ 0, - /* tp_init */ 0, - /* tp_alloc */ 0, - /* tp_new */ GraphEdge_new, -}; - #endif diff --git a/pydatastructs/utils/_backend/cpp/GraphNode.hpp b/pydatastructs/utils/_backend/cpp/GraphNode.hpp index 5ef706d52..17a0748fd 100644 --- a/pydatastructs/utils/_backend/cpp/GraphNode.hpp +++ b/pydatastructs/utils/_backend/cpp/GraphNode.hpp @@ -7,6 +7,8 @@ #include #include "Node.hpp" +extern PyTypeObject GraphNodeType; + enum class DataType { None, Int, @@ -204,44 +206,5 @@ static struct PyMemberDef GraphNode_PyMemberDef[] = { }; -static PyTypeObject GraphNodeType = { - /* tp_name */ PyVarObject_HEAD_INIT(NULL, 0) "GraphNode", - /* tp_basicsize */ sizeof(GraphNode), - /* tp_itemsize */ 0, - /* tp_dealloc */ (destructor) GraphNode_dealloc, - /* tp_print */ 0, - /* tp_getattr */ 0, - /* tp_setattr */ 0, - /* tp_reserved */ 0, - /* tp_repr */ 0, - /* tp_as_number */ 0, - /* tp_as_sequence */ 0, - /* tp_as_mapping */ 0, - /* tp_hash */ 0, - /* tp_call */ 0, - /* tp_str */ (reprfunc) GraphNode_str, - /* tp_getattro */ 0, - /* tp_setattro */ 0, - /* tp_as_buffer */ 0, - /* tp_flags */ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, - /* tp_doc */ 0, - /* tp_traverse */ 0, - /* tp_clear */ 0, - /* tp_richcompare */ 0, - /* tp_weaklistoffset */ 0, - /* tp_iter */ 0, - /* tp_iternext */ 0, - /* tp_methods */ 0, - /* tp_members */ GraphNode_PyMemberDef, - /* tp_getset */ GraphNode_getsetters, - /* tp_base */ &PyBaseObject_Type, - /* tp_dict */ 0, - /* tp_descr_get */ 0, - /* tp_descr_set */ 0, - /* tp_dictoffset */ 0, - /* tp_init */ 0, - /* tp_alloc */ 0, - /* tp_new */ GraphNode_new, -}; #endif diff --git a/pydatastructs/utils/_backend/cpp/__init__.py b/pydatastructs/utils/_backend/cpp/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/pydatastructs/utils/_backend/cpp/graph_utils.cpp b/pydatastructs/utils/_backend/cpp/graph_utils.cpp index d47390fc1..cf7ec1585 100644 --- a/pydatastructs/utils/_backend/cpp/graph_utils.cpp +++ b/pydatastructs/utils/_backend/cpp/graph_utils.cpp @@ -5,6 +5,167 @@ #include "GraphEdge.hpp" #include "graph_bindings.hpp" +PyTypeObject GraphNodeType = { + /* tp_name */ PyVarObject_HEAD_INIT(NULL, 0) "GraphNode", + /* tp_basicsize */ sizeof(GraphNode), + /* tp_itemsize */ 0, + /* tp_dealloc */ (destructor) GraphNode_dealloc, + /* tp_print */ 0, + /* tp_getattr */ 0, + /* tp_setattr */ 0, + /* tp_reserved */ 0, + /* tp_repr */ 0, + /* tp_as_number */ 0, + /* tp_as_sequence */ 0, + /* tp_as_mapping */ 0, + /* tp_hash */ 0, + /* tp_call */ 0, + /* tp_str */ (reprfunc) GraphNode_str, + /* tp_getattro */ 0, + /* tp_setattro */ 0, + /* tp_as_buffer */ 0, + /* tp_flags */ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + /* tp_doc */ 0, + /* tp_traverse */ 0, + /* tp_clear */ 0, + /* tp_richcompare */ 0, + /* tp_weaklistoffset */ 0, + /* tp_iter */ 0, + /* tp_iternext */ 0, + /* tp_methods */ 0, + /* tp_members */ GraphNode_PyMemberDef, + /* tp_getset */ GraphNode_getsetters, + /* tp_base */ &PyBaseObject_Type, + /* tp_dict */ 0, + /* tp_descr_get */ 0, + /* tp_descr_set */ 0, + /* tp_dictoffset */ 0, + /* tp_init */ 0, + /* tp_alloc */ 0, + /* tp_new */ GraphNode_new, +}; + +PyTypeObject AdjacencyListGraphNodeType = { + /* tp_name */ PyVarObject_HEAD_INIT(NULL, 0) "AdjacencyListGraphNode", + /* tp_basicsize */ sizeof(AdjacencyListGraphNode), + /* tp_itemsize */ 0, + /* tp_dealloc */ (destructor)AdjacencyListGraphNode_dealloc, + /* tp_print */ 0, + /* tp_getattr */ 0, + /* tp_setattr */ 0, + /* tp_reserved */ 0, + /* tp_repr */ 0, + /* tp_as_number */ 0, + /* tp_as_sequence */ 0, + /* tp_as_mapping */ 0, + /* tp_hash */ 0, + /* tp_call */ 0, + /* tp_str */ (reprfunc)GraphNode_str, + /* tp_getattro */ 0, + /* tp_setattro */ 0, + /* tp_as_buffer */ 0, + /* tp_flags */ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + /* tp_doc */ "Node Data Structure for an Adjacency List Graph", + /* tp_traverse */ 0, + /* tp_clear */ 0, + /* tp_richcompare */ 0, + /* tp_weaklistoffset */ 0, + /* tp_iter */ 0, + /* tp_iternext */ 0, + /* tp_methods */ AdjacencyListGraphNode_methods, + /* tp_members */ AdjacencyListGraphNode_PyMemberDef, + /* tp_getset */ AdjacencyListGraphNode_getsetters, + /* tp_base */ &GraphNodeType, + /* tp_dict */ 0, + /* tp_descr_get */ 0, + /* tp_descr_set */ 0, + /* tp_dictoffset */ 0, + /* tp_init */ 0, + /* tp_alloc */ 0, + /* tp_new */ AdjacencyListGraphNode_new, +}; + +PyTypeObject AdjacencyMatrixGraphNodeType = { + /* tp_name */ PyVarObject_HEAD_INIT(NULL, 0) "AdjacencyMatrixGraphNode", + /* tp_basicsize */ sizeof(AdjacencyMatrixGraphNode), + /* tp_itemsize */ 0, + /* tp_dealloc */ (destructor)AdjacencyMatrixGraphNode_dealloc, + /* tp_print */ 0, + /* tp_getattr */ 0, + /* tp_setattr */ 0, + /* tp_reserved */ 0, + /* tp_repr */ 0, + /* tp_as_number */ 0, + /* tp_as_sequence */ 0, + /* tp_as_mapping */ 0, + /* tp_hash */ 0, + /* tp_call */ 0, + /* tp_str */ 0, + /* tp_getattro */ 0, + /* tp_setattro */ 0, + /* tp_as_buffer */ 0, + /* tp_flags */ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + /* tp_doc */ "Node Data Structure for an Adjacency Matrix Graph", + /* tp_traverse */ 0, + /* tp_clear */ 0, + /* tp_richcompare */ 0, + /* tp_weaklistoffset */ 0, + /* tp_iter */ 0, + /* tp_iternext */ 0, + /* tp_methods */ 0, + /* tp_members */ 0, + /* tp_getset */ 0, + /* tp_base */ &GraphNodeType, + /* tp_dict */ 0, + /* tp_descr_get */ 0, + /* tp_descr_set */ 0, + /* tp_dictoffset */ 0, + /* tp_init */ 0, + /* tp_alloc */ 0, + /* tp_new */ AdjacencyMatrixGraphNode_new, +}; + +PyTypeObject GraphEdgeType = { + /* tp_name */ PyVarObject_HEAD_INIT(NULL, 0) "GraphEdge", + /* tp_basicsize */ sizeof(GraphEdge), + /* tp_itemsize */ 0, + /* tp_dealloc */ (destructor)GraphEdge_dealloc, + /* tp_print */ 0, + /* tp_getattr */ 0, + /* tp_setattr */ 0, + /* tp_reserved */ 0, + /* tp_repr */ 0, + /* tp_as_number */ 0, + /* tp_as_sequence */ 0, + /* tp_as_mapping */ 0, + /* tp_hash */ 0, + /* tp_call */ 0, + /* tp_str */ (reprfunc)GraphEdge_str, + /* tp_getattro */ 0, + /* tp_setattro */ 0, + /* tp_as_buffer */ 0, + /* tp_flags */ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + /* tp_doc */ "Data Structure for a Graph Edge", + /* tp_traverse */ 0, + /* tp_clear */ 0, + /* tp_richcompare */ 0, + /* tp_weaklistoffset */ 0, + /* tp_iter */ 0, + /* tp_iternext */ 0, + /* tp_methods */ 0, + /* tp_members */ 0, + /* tp_getset */ GraphEdge_getsetters, + /* tp_base */ 0, + /* tp_dict */ 0, + /* tp_descr_get */ 0, + /* tp_descr_set */ 0, + /* tp_dictoffset */ 0, + /* tp_init */ 0, + /* tp_alloc */ 0, + /* tp_new */ GraphEdge_new, +}; + + static struct PyModuleDef graph_utils_struct = { PyModuleDef_HEAD_INIT, "_graph_utils", diff --git a/pydatastructs/utils/_backend/cpp/nodes.cpp b/pydatastructs/utils/_backend/cpp/nodes.cpp index 4e50d6966..94951285c 100644 --- a/pydatastructs/utils/_backend/cpp/nodes.cpp +++ b/pydatastructs/utils/_backend/cpp/nodes.cpp @@ -11,7 +11,6 @@ static struct PyModuleDef nodes_struct = { }; PyMODINIT_FUNC PyInit__nodes(void) { - Py_Initialize(); PyObject *nodes = PyModule_Create(&nodes_struct); if (PyType_Ready(&NodeType) < 0) { diff --git a/pydatastructs/utils/_backend/cpp/utils.hpp b/pydatastructs/utils/_backend/cpp/utils.hpp index 36d323b9a..511c224c6 100644 --- a/pydatastructs/utils/_backend/cpp/utils.hpp +++ b/pydatastructs/utils/_backend/cpp/utils.hpp @@ -6,10 +6,41 @@ #include #include -static PyObject *PyZero = PyLong_FromLong(0); -static PyObject *PyOne = PyLong_FromLong(1); -static PyObject *PyTwo = PyLong_FromLong(2); -static PyObject *PyThree = PyLong_FromLong(3); +static PyObject* get_PyZero() { + static PyObject* PyZero = nullptr; + if (PyZero == nullptr) { + PyZero = PyLong_FromLong(0); + } + return PyZero; +} + +static PyObject* get_PyOne() { + static PyObject* PyOne = nullptr; + if (PyOne == nullptr) { + PyOne = PyLong_FromLong(1); + } + return PyOne; +} + +static PyObject* get_PyTwo() { + static PyObject* PyTwo = nullptr; + if (PyTwo == nullptr) { + PyTwo = PyLong_FromLong(2); + } + return PyTwo; +} + +static PyObject* get_PyThree() { + static PyObject* PyThree = nullptr; + if (PyThree == nullptr) { + PyThree = PyLong_FromLong(3); + } + return PyThree; +} +#define PyZero get_PyZero() +#define PyOne get_PyOne() +#define PyTwo get_PyTwo() +#define PyThree get_PyThree() static const char* _encoding = "utf-8"; static const char* _invalid_char = ""; diff --git a/pydatastructs/utils/meson.build b/pydatastructs/utils/meson.build new file mode 100644 index 000000000..816afa4ec --- /dev/null +++ b/pydatastructs/utils/meson.build @@ -0,0 +1,33 @@ +python = import('python').find_installation(pure: false) + +python.install_sources( + [ + '__init__.py', + 'misc_util.py', + 'raises_util.py', + 'testing_util.py' + ], + subdir: 'pydatastructs/utils' +) + +python.install_sources( + ['_backend/__init__.py', '_backend/cpp/__init__.py'], + subdir: 'pydatastructs/utils/_backend' +) + +cpp_args = [] +if host_machine.system() == 'windows' + cpp_args += ['/MD'] +endif + +python.extension_module( + '_nodes', + [ + '_backend/cpp/nodes.cpp', + ], + cpp_args: cpp_args, + install: true, + subdir: 'pydatastructs/utils/_backend/cpp' +) + +subdir('tests') \ No newline at end of file diff --git a/pydatastructs/utils/misc_util.py b/pydatastructs/utils/misc_util.py index 3672c58b9..529fc58fa 100644 --- a/pydatastructs/utils/misc_util.py +++ b/pydatastructs/utils/misc_util.py @@ -1,6 +1,7 @@ import math, pydatastructs from enum import Enum -from pydatastructs.utils._backend.cpp import _nodes, _graph_utils +from pydatastructs.utils._backend.cpp import _nodes + __all__ = [ 'TreeNode', @@ -411,7 +412,8 @@ def __new__(cls, name, data=None, adjacency_list=[], else [] return obj else: - return _graph_utils.AdjacencyListGraphNode(name, data, adjacency_list) + from pydatastructs.graphs._backend.cpp import _graph + return _graph.AdjacencyListGraphNode(name, data, adjacency_list) def add_adjacent_node(self, name, data=None): """ @@ -468,7 +470,8 @@ def __new__(cls, name, data=None, obj._impl = 'adjacency_matrix' return obj else: - return _graph_utils.AdjacencyMatrixGraphNode(str(name), data) + from pydatastructs.graphs._backend.cpp import _graph + return _graph.AdjacencyMatrixGraphNode(str(name), data) class GraphEdge(object): """ @@ -499,7 +502,8 @@ def __new__(cls, node1, node2, value=None, obj.value = value return obj else: - return _graph_utils.GraphEdge(node1, node2, value) + from pydatastructs.graphs._backend.cpp import _graph + return _graph.GraphEdge(node1, node2, value) def __str__(self): return str((self.source.name, self.target.name)) diff --git a/pydatastructs/utils/tests/meson.build b/pydatastructs/utils/tests/meson.build new file mode 100644 index 000000000..880f40987 --- /dev/null +++ b/pydatastructs/utils/tests/meson.build @@ -0,0 +1,11 @@ +python = import('python').find_installation(pure: false) + +python.install_sources( + [ + '__init__.py', + 'test_misc_util.py', + 'test_code_quality.py' + ], + subdir: 'pydatastructs/utils/tests', + install_tag: 'tests' +) diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 000000000..e8adc6578 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,17 @@ +[build-system] +requires = ["meson-python"] +build-backend = "mesonpy" + +[project] +name = "pydatastructs" +version = "1.0.1.dev0" +description = "Data structures and algorithms implemented using Python and C++" +readme = "README.md" +requires-python = ">=3.9" + +[tool.spin] +package = "pydatastructs" + +[tool.spin.commands] +Build = ["spin.cmds.meson.build"] +Test = ["spin.cmds.meson.test"] diff --git a/requirements.txt b/requirements.txt index ebb62275e..0b5f457a3 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,6 @@ codecov pytest pytest-cov -llvmlite \ No newline at end of file +llvmlite +spin +meson diff --git a/setup.py b/setup.py index bbe3faef0..615e8d89d 100644 --- a/setup.py +++ b/setup.py @@ -34,6 +34,6 @@ "Topic :: Scientific/Engineering :: Information Analysis", "Topic :: Software Development :: Libraries" ], - python_requires='>=3.5', + python_requires='>=3.9', ext_modules=extensions )