1+ #!/usr/bin/env python3
2+ """
3+ Minimal setup.py for RtBot Python wrapper.
4+
5+ This setup.py is designed to work with pre-built artifacts from Bazel.
6+ For development builds, use: bazel build //libs/wrappers/python:rtbot_wheel
7+ """
8+
19import os
2- import platform
3- import subprocess
410import sys
5- import tempfile
6- import shutil
7- from setuptools import setup , Extension
8- from setuptools .command .build_ext import build_ext
9- from setuptools .command .egg_info import egg_info
10-
11- RTBOT_REPO = "https://github.com/rtbot-dev/rtbot.git"
11+ from setuptools import setup , find_packages
1212
1313def get_version ():
14+ """Get version from git tags, with dev suffix if ahead of latest tag."""
15+ import subprocess
16+
1417 try :
15- output = subprocess .check_output (
16- ['bash' , '-c' , "grep '^VERSION ' dist/out/stable-status.txt | cut -d' ' -f2" ],
18+ # Get the latest git tag
19+ latest_tag = subprocess .check_output (
20+ ['git' , 'describe' , '--tags' , '--abbrev=0' ],
1721 stderr = subprocess .PIPE
1822 ).decode ().strip ()
19- return output if output else "0.1.0"
20- except :
21- return "0.1.0"
22-
23- class BazelExtension (Extension ):
24- def __init__ (self , name ):
25- super ().__init__ (name , sources = [])
2623
27- class CustomEggInfo (egg_info ):
28- def run (self ):
29- os .makedirs ('rtbot' , exist_ok = True )
30- super ().run ()
24+ # Remove 'v' prefix if present
25+ if latest_tag .startswith ('v' ):
26+ latest_tag = latest_tag [1 :]
3127
32- class BazelBuildExt (build_ext ):
33- def run (self ):
34- self ._install_bazelisk ()
35- repo_dir = self ._get_repo_dir ()
36- self ._build_rtbot (repo_dir )
37-
38- def _get_repo_dir (self ):
39- current_dir = os .path .abspath (os .getcwd ())
40- while current_dir != '/' :
41- if os .path .exists (os .path .join (current_dir , 'WORKSPACE' )):
42- return current_dir
43- current_dir = os .path .dirname (current_dir )
44-
45- tmp_dir = tempfile .mkdtemp ()
46- self ._clone_repo (tmp_dir )
47- return tmp_dir
28+ # Get current commit description
29+ git_describe = subprocess .check_output (
30+ ['git' , 'describe' , '--tags' , '--always' ],
31+ stderr = subprocess .PIPE
32+ ).decode ().strip ()
4833
49- def _install_bazelisk (self ):
50- try :
51- subprocess .check_call (['bazelisk' , '--version' ])
52- return
53- except (subprocess .CalledProcessError , FileNotFoundError ):
54- pass
34+ # If we're exactly on a tag, use that version
35+ if git_describe == f'v{ latest_tag } ' or git_describe == latest_tag :
36+ return latest_tag
5537
56- print ("Installing bazelisk..." )
57- system = platform .system ().lower ()
58- arch = platform .machine ().lower ()
59-
60- if system == 'windows' :
61- url = f"https://github.com/bazelbuild/bazelisk/releases/latest/download/bazelisk-windows-{ arch } .exe"
62- out = "bazelisk.exe"
63- else :
64- url = f"https://github.com/bazelbuild/bazelisk/releases/latest/download/bazelisk-{ system } -{ arch } "
65- out = "bazelisk"
66-
67- subprocess .check_call (['curl' , '-L' , url , '-o' , out ])
68- if system != 'windows' :
69- os .chmod (out , 0o755 )
70-
71- os .environ ['PATH' ] = os .getcwd () + os .pathsep + os .environ ['PATH' ]
38+ # If we're ahead of the tag, create a dev version
39+ # Format: v0.3.8-135-gc6ee14a -> 0.3.8.dev135+gc6ee14a
40+ parts = git_describe .split ('-' )
41+ if len (parts ) >= 3 :
42+ tag_part = parts [0 ]
43+ if tag_part .startswith ('v' ):
44+ tag_part = tag_part [1 :]
45+ commits_ahead = parts [1 ]
46+ short_sha = parts [2 ]
47+ return f"{ tag_part } .dev{ commits_ahead } +{ short_sha } "
7248
73- def _clone_repo (self , tmp_dir ):
74- print ("Cloning RTBot repository..." )
75- subprocess .check_call (['git' , 'clone' , '--depth' , '1' , RTBOT_REPO , tmp_dir ])
49+ # Fallback: just use the tag
50+ return latest_tag
7651
77- def _get_bazel_bin ( self , repo_dir ):
78- bazel_cmd = 'bazelisk' if platform . system (). lower () != 'windows' else 'bazelisk.exe'
52+ except ( subprocess . CalledProcessError , FileNotFoundError , IndexError ):
53+ # Fallback to reading from Bazel build if git fails
7954 try :
80- bazel_bin = subprocess .check_output (
81- [bazel_cmd , 'info' , 'bazel-bin' ],
82- cwd = repo_dir ,
83- text = True
84- ).strip ()
85- return bazel_bin
86- except subprocess .CalledProcessError :
87- return os .path .join (repo_dir , 'dist' ) # Fallback to --symlink_prefix value
88-
89- def _build_rtbot (self , repo_dir ):
90- print ("Building RTBot..." )
91- bazel_cmd = 'bazelisk' if platform .system ().lower () != 'windows' else 'bazelisk.exe'
92-
93- subprocess .check_call (
94- [bazel_cmd , 'build' , '//libs/wrappers/python:rtbotapi.so' , '//libs/wrappers/python:copy' ],
95- cwd = repo_dir
96- )
97-
98- bazel_bin = self ._get_bazel_bin (repo_dir )
99- package_dir = os .path .join (self .build_lib , 'rtbot' )
100- os .makedirs (package_dir , exist_ok = True )
55+ version_file = "dist/bin/libs/wrappers/python/version.txt"
56+ if os .path .exists (version_file ):
57+ with open (version_file , 'r' ) as f :
58+ return f .read ().strip ()
59+ except :
60+ pass
61+ return "0.1.0"
10162
102- # Copy files from bazel-bin
103- copy_dir = os .path .join (bazel_bin , 'libs/wrappers/python/rtbot' )
104- for item in ['MANIFEST.in' , 'README.md' , 'operators.py' , 'setup.py' , '__init__.py' ]:
105- src = os .path .join (copy_dir , item )
106- if os .path .exists (src ):
107- shutil .copy2 (src , package_dir )
63+ # Check if we're in development mode (rtbotapi.so exists locally)
64+ has_extension = os .path .exists ("rtbotapi.so" ) or os .path .exists ("rtbotapi.pyd" )
10865
109- # Copy the extension
110- ext_path = os .path .join (bazel_bin , 'libs/wrappers/python/rtbotapi.so' )
111- if platform .system ().lower () == 'windows' :
112- ext_path = ext_path .replace ('.so' , '.pyd' )
113-
114- if os .path .exists (ext_path ):
115- shutil .copy2 (ext_path , package_dir )
116- else :
117- raise RuntimeError (f"Built extension not found at { ext_path } " )
66+ if not has_extension :
67+ print ("Error: rtbot extension not found." )
68+ print ("This package requires pre-built artifacts from Bazel." )
69+ print ("Run: bazel build //libs/wrappers/python:copy" )
70+ print ("Then copy the artifacts to this directory before running setup.py" )
71+ sys .exit (1 )
11872
11973setup (
12074 name = 'rtbot' ,
12175 version = get_version (),
122- description = 'Python bindings for RTBot framework' ,
123- author = 'RTBot Developers' ,
76+ description = 'Python bindings for RtBot framework' ,
77+ long_description = 'RtBot is a real-time data processing framework with Python bindings.' ,
78+ long_description_content_type = 'text/plain' ,
79+ author = 'RtBot Developers' ,
12480 url = 'https://github.com/rtbot-dev/rtbot' ,
125- ext_modules = [BazelExtension ('rtbot' )],
126- cmdclass = {
127- 'build_ext' : BazelBuildExt ,
128- 'egg_info' : CustomEggInfo ,
81+ packages = find_packages (),
82+ package_data = {
83+ 'rtbot' : ['*.so' , '*.pyd' , '*.py' ],
12984 },
130- packages = ['rtbot' ],
13185 install_requires = [
13286 "pandas>=1.0.0"
13387 ],
13488 python_requires = '>=3.10' ,
89+ classifiers = [
90+ 'Development Status :: 3 - Alpha' ,
91+ 'Intended Audience :: Developers' ,
92+ 'License :: OSI Approved :: Apache Software License' ,
93+ 'Programming Language :: Python :: 3' ,
94+ 'Programming Language :: Python :: 3.10' ,
95+ 'Programming Language :: Python :: 3.11' ,
96+ 'Programming Language :: Python :: 3.12' ,
97+ 'Programming Language :: Python :: 3.13' ,
98+ ],
13599)
0 commit comments