unaiverse 0.1.8__cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of unaiverse might be problematic. Click here for more details.

Files changed (50) hide show
  1. unaiverse/__init__.py +19 -0
  2. unaiverse/agent.py +2008 -0
  3. unaiverse/agent_basics.py +2041 -0
  4. unaiverse/clock.py +191 -0
  5. unaiverse/dataprops.py +1209 -0
  6. unaiverse/hsm.py +1889 -0
  7. unaiverse/modules/__init__.py +18 -0
  8. unaiverse/modules/cnu/__init__.py +17 -0
  9. unaiverse/modules/cnu/cnus.py +536 -0
  10. unaiverse/modules/cnu/layers.py +261 -0
  11. unaiverse/modules/cnu/psi.py +60 -0
  12. unaiverse/modules/hl/__init__.py +15 -0
  13. unaiverse/modules/hl/hl_utils.py +411 -0
  14. unaiverse/modules/networks.py +1509 -0
  15. unaiverse/modules/utils.py +710 -0
  16. unaiverse/networking/__init__.py +16 -0
  17. unaiverse/networking/node/__init__.py +18 -0
  18. unaiverse/networking/node/connpool.py +1261 -0
  19. unaiverse/networking/node/node.py +2299 -0
  20. unaiverse/networking/node/profile.py +447 -0
  21. unaiverse/networking/node/tokens.py +79 -0
  22. unaiverse/networking/p2p/__init__.py +188 -0
  23. unaiverse/networking/p2p/go.mod +127 -0
  24. unaiverse/networking/p2p/go.sum +548 -0
  25. unaiverse/networking/p2p/golibp2p.py +18 -0
  26. unaiverse/networking/p2p/golibp2p.pyi +135 -0
  27. unaiverse/networking/p2p/lib.go +2527 -0
  28. unaiverse/networking/p2p/lib.go.sha256 +1 -0
  29. unaiverse/networking/p2p/lib_types.py +312 -0
  30. unaiverse/networking/p2p/message_pb2.py +63 -0
  31. unaiverse/networking/p2p/messages.py +268 -0
  32. unaiverse/networking/p2p/mylogger.py +77 -0
  33. unaiverse/networking/p2p/p2p.py +929 -0
  34. unaiverse/networking/p2p/proto-go/message.pb.go +616 -0
  35. unaiverse/networking/p2p/unailib.cpython-312-aarch64-linux-gnu.so +0 -0
  36. unaiverse/streamlib/__init__.py +15 -0
  37. unaiverse/streamlib/streamlib.py +210 -0
  38. unaiverse/streams.py +770 -0
  39. unaiverse/utils/__init__.py +16 -0
  40. unaiverse/utils/ask_lone_wolf.json +27 -0
  41. unaiverse/utils/lone_wolf.json +19 -0
  42. unaiverse/utils/misc.py +492 -0
  43. unaiverse/utils/sandbox.py +293 -0
  44. unaiverse/utils/server.py +435 -0
  45. unaiverse/world.py +353 -0
  46. unaiverse-0.1.8.dist-info/METADATA +365 -0
  47. unaiverse-0.1.8.dist-info/RECORD +50 -0
  48. unaiverse-0.1.8.dist-info/WHEEL +7 -0
  49. unaiverse-0.1.8.dist-info/licenses/LICENSE +43 -0
  50. unaiverse-0.1.8.dist-info/top_level.txt +1 -0
@@ -0,0 +1,293 @@
1
+ """
2
+ █████ █████ ██████ █████ █████ █████ █████ ██████████ ███████████ █████████ ██████████
3
+ ░░███ ░░███ ░░██████ ░░███ ░░███ ░░███ ░░███ ░░███░░░░░█░░███░░░░░███ ███░░░░░███░░███░░░░░█
4
+ ░███ ░███ ░███░███ ░███ ██████ ░███ ░███ ░███ ░███ █ ░ ░███ ░███ ░███ ░░░ ░███ █ ░
5
+ ░███ ░███ ░███░░███░███ ░░░░░███ ░███ ░███ ░███ ░██████ ░██████████ ░░█████████ ░██████
6
+ ░███ ░███ ░███ ░░██████ ███████ ░███ ░░███ ███ ░███░░█ ░███░░░░░███ ░░░░░░░░███ ░███░░█
7
+ ░███ ░███ ░███ ░░█████ ███░░███ ░███ ░░░█████░ ░███ ░ █ ░███ ░███ ███ ░███ ░███ ░ █
8
+ ░░████████ █████ ░░█████░░████████ █████ ░░███ ██████████ █████ █████░░█████████ ██████████
9
+ ░░░░░░░░ ░░░░░ ░░░░░ ░░░░░░░░ ░░░░░ ░░░ ░░░░░░░░░░ ░░░░░ ░░░░░ ░░░░░░░░░ ░░░░░░░░░░
10
+ A Collectionless AI Project (https://collectionless.ai)
11
+ Registration/Login: https://unaiverse.io
12
+ Code Repositories: https://github.com/collectionlessai/
13
+ Main Developers: Stefano Melacci (Project Leader), Christian Di Maio, Tommaso Guidi
14
+ """
15
+ import os
16
+ import sys
17
+ import uuid
18
+ import argparse
19
+ import subprocess
20
+ from pathlib import Path
21
+ from unaiverse.networking.p2p import P2P
22
+
23
+ # Configuration
24
+ DOCKER_IMAGE_NAME = "unaiverse-sandbox"
25
+ CONTAINER_NAME_BASE = "unaiverse-sandbox-container"
26
+ CONTAINER_NAME = f"{CONTAINER_NAME_BASE}-{uuid.uuid4().hex[:8]}" # Append a short unique ID
27
+ DOCKERFILE_CONTENT = """
28
+
29
+ # Debian image, automatically guessed architecture
30
+ FROM python:3.12-slim-bookworm
31
+
32
+ # Installing Go compiler
33
+ RUN apt-get update && apt-get install -y --no-install-recommends build-essential curl git
34
+ RUN rm -rf /var/lib/apt/lists/*
35
+ RUN ARCH=$(dpkg --print-architecture) && curl -LO https://go.dev/dl/go1.24.5.linux-${ARCH}.tar.gz
36
+ RUN ARCH=$(dpkg --print-architecture) && tar -C /usr/local -xzf go1.24.5.linux-${ARCH}.tar.gz
37
+ RUN ARCH=$(dpkg --print-architecture) && rm go1.24.5.linux-${ARCH}.tar.gz
38
+
39
+ # Set Go environment variables
40
+ ENV PATH="/usr/local/go/bin:${PATH}"
41
+ ENV GOPATH="/go"
42
+ RUN mkdir -p /go/bin /go/src /go/pkg
43
+
44
+ # Setting the working directory inside the container
45
+ WORKDIR /unaiverse
46
+
47
+ # Dependencies
48
+ RUN <create_requirements.txt>
49
+ RUN pip install --no-cache-dir -r requirements.txt --break-system-packages
50
+ """
51
+
52
+
53
+ def sandbox(file_to_run: str,
54
+ read_only_paths: tuple[str] | list[str] | None = None,
55
+ writable_paths: tuple[str] | list[str] | None = None) -> None:
56
+
57
+ # Path of this file
58
+ absolute_path_of_this_file = os.path.abspath(__file__)
59
+
60
+ # Folders composing the path (and file name at the end)
61
+ path_components = list(Path(absolute_path_of_this_file).parts)
62
+
63
+ # Ensuring the folder/file structure was not manipulated
64
+ assert path_components[-1] == 'sandbox.py', "Major security issue, stopping."
65
+ assert path_components[-2] == 'utils', "Major security issue, stopping."
66
+ assert path_components[-3] == 'unaiverse', "Major security issue, stopping."
67
+
68
+ # Main folder of UNaIVERSE
69
+ abspath_of_unaiverse_code = str(Path(*path_components[0:-3]))
70
+
71
+ # Clean up any remnants from previous runs first (safety)
72
+ cleanup_docker_artifacts(where=abspath_of_unaiverse_code)
73
+
74
+ # Requirements
75
+ echoed_contents_of_requirements = 'printf "'
76
+ with open(os.path.join(abspath_of_unaiverse_code, "requirements.txt"), 'r') as req_file:
77
+ req_lines = req_file.readlines()
78
+ for i, req_line in enumerate(req_lines):
79
+ if i != (len(req_lines) - 1) and len(req_line.strip()) > 0:
80
+ echoed_contents_of_requirements += req_line.strip() + "\\n"
81
+ else:
82
+ echoed_contents_of_requirements += req_line.strip() + "\\n\" > requirements.txt"
83
+
84
+ # Create Dockerfile
85
+ print("Creating Dockerfile...")
86
+ with open(os.path.join(abspath_of_unaiverse_code, "Dockerfile"), "w") as f:
87
+ f.write(DOCKERFILE_CONTENT.replace('<create_requirements.txt>', echoed_contents_of_requirements))
88
+
89
+ # Building Docker image
90
+ if not build_docker_image(where=abspath_of_unaiverse_code):
91
+ print("Exiting due to Docker image build failure")
92
+ cleanup_docker_artifacts(where=abspath_of_unaiverse_code) # Try to clean up what was created (if any)
93
+ sys.exit(1)
94
+
95
+ # Read only folders from the host machine
96
+ read_only_mount_paths = ([abspath_of_unaiverse_code] +
97
+ (list(read_only_paths) if read_only_paths is not None else []))
98
+
99
+ # Writable folders in host machine
100
+ writable_mount_paths = ([os.path.join(abspath_of_unaiverse_code, 'runners'),
101
+ os.path.join(abspath_of_unaiverse_code, 'unaiverse', 'library'),
102
+ os.path.join(abspath_of_unaiverse_code, 'unaiverse', 'networking', 'p2p')] +
103
+ (list(writable_paths) if writable_paths is not None else []))
104
+
105
+ # Running
106
+ if not run_in_docker(file_to_run=os.path.abspath(file_to_run),
107
+ read_only_host_paths=read_only_mount_paths,
108
+ writable_host_paths=writable_mount_paths):
109
+ print("Exiting due to Docker container run failure")
110
+ sys.exit(1)
111
+
112
+ # Final cleanup
113
+ cleanup_docker_artifacts(where=abspath_of_unaiverse_code)
114
+
115
+
116
+ def build_docker_image(where: str):
117
+ """Builds the Docker image."""
118
+ print(f"Building Docker image '{DOCKER_IMAGE_NAME}'...")
119
+
120
+ try:
121
+
122
+ # The '.' at the end means build from the current directory
123
+ subprocess.run(["docker", "build", "-t", DOCKER_IMAGE_NAME, where], check=True)
124
+ print(f"Docker image '{DOCKER_IMAGE_NAME}' built successfully.")
125
+ return True
126
+ except subprocess.CalledProcessError as e:
127
+ print(f"Error building Docker image: {e}")
128
+ return False
129
+
130
+
131
+ def cleanup_docker_artifacts(where: str):
132
+ """Cleans up the generated files and Docker image."""
133
+ print("Cleaning...")
134
+
135
+ # Stop and remove container if it's still running (e.g., if previous run failed)
136
+ try:
137
+ print(f"Attempting to stop and remove container '{CONTAINER_NAME}' (if running)...")
138
+ subprocess.run(["docker", "stop", CONTAINER_NAME],
139
+ check=False, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
140
+ subprocess.run(["docker", "rm", CONTAINER_NAME],
141
+ check=False, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
142
+ except Exception as e:
143
+ print(f"Error during preliminary container cleanup: {e}")
144
+
145
+ # Remove the Docker image
146
+ try:
147
+ print(f"Removing Docker image '{DOCKER_IMAGE_NAME}'...")
148
+ subprocess.run(["docker", "rmi", DOCKER_IMAGE_NAME], check=True)
149
+ print("Docker image removed.")
150
+ except subprocess.CalledProcessError as e:
151
+ print(f"Error removing Docker image '{DOCKER_IMAGE_NAME}': {e}")
152
+
153
+ # Remove the generated Dockerfile
154
+ if os.path.exists(os.path.join(where, "Dockerfile")):
155
+ os.remove(os.path.join(where, "Dockerfile"))
156
+ print("Removed Dockerfile.")
157
+
158
+
159
+ def run_in_docker(file_to_run: str, read_only_host_paths: list[str] = None, writable_host_paths: list[str] = None):
160
+ """Runs the code in a Docker container with optional mounts."""
161
+ print(f"\nRunning code in Docker container '{CONTAINER_NAME}'...")
162
+
163
+ # Building command (it will continue below...)
164
+ command = ["docker", "run",
165
+ "--rm", # Automatically remove the container when it exits
166
+ "-e", "PYTHONUNBUFFERED=1", # Ensure Python output is unbuffered
167
+ "-e", "NODE_STARTING_PORT",
168
+ "--name", CONTAINER_NAME]
169
+
170
+ if sys.platform.startswith('linux'):
171
+
172
+ # Linux
173
+ command.extend(["--net", "host"]), # Expose the host network (in macOS and Windows it is still a virtual host)
174
+ else:
175
+
176
+ # Not-linux: check ports (adding -p port:port)
177
+ port_int = int(os.getenv("NODE_STARTING_PORT", "0"))
178
+ if port_int > 0:
179
+ command.extend(["-p", str(port_int + 0) + ":" + str(port_int + 0)])
180
+ command.extend(["-p", str(port_int + 1) + ":" + str(port_int + 1) + "/udp"])
181
+ command.extend(["-p", str(port_int + 2) + ":" + str(port_int + 2)])
182
+ command.extend(["-p", str(port_int + 3) + ":" + str(port_int + 3) + "/udp"])
183
+
184
+ # Add read-only mount if path is provided
185
+ if read_only_host_paths is not None and len(read_only_host_paths) > 0:
186
+ for path in read_only_host_paths:
187
+
188
+ # Ensure the host path exists and is a directory
189
+ if not os.path.isdir(path):
190
+ print(
191
+ f"Error: Read-only host path '{path}' does not exist or is not a directory. Cannot mount.")
192
+ return False
193
+ else:
194
+
195
+ # Augmenting command
196
+ path = os.path.abspath(path)
197
+ command.extend(["-v", f"{path}:{path}:ro"])
198
+ print(f"Mounted host '{path}' as read-only to container")
199
+
200
+ # Add writable mount if path is provided
201
+ if writable_host_paths is not None and len(writable_host_paths) > 0:
202
+ for path in writable_host_paths:
203
+
204
+ # Ensure the host path exists and is a directory
205
+ if not os.path.isdir(path):
206
+ print(
207
+ f"Error: Writable host path '{path}' does not exist or is not a directory. Cannot mount.")
208
+ return False
209
+ else:
210
+
211
+ # Augmenting command
212
+ path = os.path.abspath(path)
213
+ command.extend(["-v", f"{path}:{path}"])
214
+ print(f"Mounted host '{path}' as writable to container")
215
+
216
+ # Completing command
217
+ command.append(DOCKER_IMAGE_NAME)
218
+
219
+ try:
220
+
221
+ # Running the prepared command... (using Popen to stream output in real-time)
222
+ try:
223
+ command.extend(["python3", file_to_run])
224
+ process = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, text=True)
225
+ for line in iter(process.stdout.readline, ''):
226
+ sys.stdout.write(line)
227
+ process.wait() # Wait for the process to finish
228
+ if process.returncode != 0:
229
+ print(f"Container exited with non-zero status code: {process.returncode}")
230
+ except KeyboardInterrupt:
231
+ pass
232
+
233
+ print(f"\nContainer '{CONTAINER_NAME}' finished execution.")
234
+ return True
235
+ except FileNotFoundError:
236
+ print("Error: Docker command not found. Is Docker installed and in your PATH?")
237
+ print("Please ensure Docker is installed and running.")
238
+ return False
239
+ except subprocess.CalledProcessError as e:
240
+ print(f"Error running Docker container: {e}")
241
+ return False
242
+
243
+
244
+ # Entry point
245
+ if __name__ == "__main__":
246
+ parser = argparse.ArgumentParser(
247
+ description="Run a Python script adding customizable read-only and writable paths.",
248
+ formatter_class=argparse.RawTextHelpFormatter,
249
+ epilog="""
250
+ Examples:
251
+ python utils/sandbox.py my_script.py -r /home/user/data:/opt/app/data -p 1234
252
+ python utils/sandbox.py another_script.py -w /tmp/output:/mnt/results
253
+ python utils/sandbox.py script_with_both.py -r /input:/app/in -w /output:/app/out -p 8082
254
+ """)
255
+ parser.add_argument(help="Path to the Python script to execute.", dest="script_to_run",
256
+ type=str)
257
+ parser.add_argument("-p", "--port", dest="port",
258
+ help="The starting port of the node(s) (each node uses 4 ports, consecutive port numbers)",
259
+ type=str, required=True)
260
+ parser.add_argument("-r", "--read-only", dest="read_only_folders",
261
+ help="One or multiple paths to mount as read-only. "
262
+ "Use a colon to separate multiple paths (e.g., /path/a:/path/b).",
263
+ type=str, default=None)
264
+ parser.add_argument("-w", "--writable", dest="writable_folders",
265
+ help="One or multiple paths to mount as writable. "
266
+ "Use a colon to separate multiple paths (e.g., /path/c:/path/d).",
267
+ type=str, default=None)
268
+ args = parser.parse_args()
269
+
270
+ if not args.script_to_run.endswith(".py"):
271
+ parser.error(f"The script '{args.script_to_run}' must be a Python file (e.g., ending with .py)")
272
+ script_to_run = args.script_to_run
273
+ if not int(args.port) > 0:
274
+ parser.error(f"Invalid port")
275
+
276
+ read_only_folders = None
277
+ if args.read_only_folders:
278
+ read_only_folders = args.read_only_folders.split(':')
279
+ writable_folders = None
280
+ if args.writable_folders:
281
+ writable_folders = args.writable_folders.split(':')
282
+
283
+ print("\n Running in sandbox...")
284
+ print(f"- Script to run: {script_to_run}")
285
+ print(f"- Starting port (+0, +1, +2, +3): {args.port}")
286
+ print(f"- Read only paths to mount (the UNaIVERSE code folder will be automatically mounted): {read_only_folders}")
287
+ print(f"- Writable paths to mount: {writable_folders}\n")
288
+
289
+ # Marking
290
+ os.environ["NODE_STARTING_PORT"] = args.port
291
+
292
+ # Running the sandbox and the script
293
+ sandbox(script_to_run, read_only_paths=read_only_folders, writable_paths=writable_folders)