primitive 0.2.9__py3-none-any.whl → 0.2.11__py3-none-any.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.
@@ -3,13 +3,11 @@ import typing
3
3
  import click
4
4
 
5
5
  from ..utils.printer import print_result
6
+ from .ui import render_hardware_table
6
7
 
7
8
  if typing.TYPE_CHECKING:
8
9
  from ..client import Primitive
9
10
 
10
- from rich.console import Console
11
- from rich.table import Table
12
-
13
11
 
14
12
  @click.group()
15
13
  @click.pass_context
@@ -71,71 +69,6 @@ def checkin_command(context):
71
69
  print_result(message=message, context=context, fg="green")
72
70
 
73
71
 
74
- def hardware_status_string(hardware):
75
- if activeReservation := hardware.get("activeReservation"):
76
- if activeReservation.get("status", None) == "in_progress":
77
- return "Reserved"
78
- if hardware.get("isQuarantined"):
79
- return "Quarantined"
80
- if not hardware.get("isOnline"):
81
- return "Offline"
82
- if not hardware.get("isHealthy"):
83
- return "Not healthy"
84
- if not hardware.get("isAvailable"):
85
- return "Not available"
86
- else:
87
- return "Available"
88
-
89
-
90
- def render_hardware_table(hardware_list):
91
- console = Console()
92
-
93
- table = Table(show_header=True, header_style="bold magenta")
94
- table.add_column("Organization")
95
- table.add_column("Name | Slug")
96
- table.add_column("Status")
97
- table.add_column("Reservation")
98
-
99
- for hardware in hardware_list:
100
- name = hardware.get("name")
101
- slug = hardware.get("slug")
102
- print_name = name
103
- if name != slug:
104
- print_name = f"{name} | {slug}"
105
- child_table = Table(show_header=False, header_style="bold magenta")
106
- child_table.add_column("Organization")
107
- child_table.add_column("Name | Slug")
108
- child_table.add_column("Status")
109
- child_table.add_column("Reservation", justify="right")
110
-
111
- table.add_row(
112
- hardware.get("organization").get("name"),
113
- print_name,
114
- hardware_status_string(hardware),
115
- f"{hardware.get('activeReservation').get('createdBy').get('username')} | {hardware.get('activeReservation').get('status')}"
116
- if hardware.get("activeReservation", None)
117
- else "",
118
- )
119
-
120
- if len(hardware.get("children", [])) > 0:
121
- for child in hardware.get("children"):
122
- name = child.get("name")
123
- slug = child.get("slug")
124
- print_name = name
125
- if name != slug:
126
- print_name = f"└── {name} | {slug}"
127
- table.add_row(
128
- hardware.get("organization").get("name"),
129
- print_name,
130
- hardware_status_string(hardware),
131
- f"{hardware.get('activeReservation').get('createdBy').get('username')} | {hardware.get('activeReservation').get('status')}"
132
- if hardware.get("activeReservation", None)
133
- else "",
134
- )
135
-
136
- console.print(table)
137
-
138
-
139
72
  @cli.command("list")
140
73
  @click.pass_context
141
74
  def list_command(context):
@@ -0,0 +1,67 @@
1
+ from rich.console import Console
2
+ from rich.table import Table
3
+
4
+
5
+ def render_hardware_table(hardware_list) -> None:
6
+ console = Console()
7
+
8
+ table = Table(show_header=True, header_style="bold #FFA800")
9
+ table.add_column("Organization")
10
+ table.add_column("Name | Slug")
11
+ table.add_column("Status")
12
+ table.add_column("Reservation")
13
+
14
+ for hardware in hardware_list:
15
+ name = hardware.get("name")
16
+ slug = hardware.get("slug")
17
+ print_name = name
18
+ if name != slug:
19
+ print_name = f"{name} | {slug}"
20
+ child_table = Table(show_header=False, header_style="bold #FFA800")
21
+ child_table.add_column("Organization")
22
+ child_table.add_column("Name | Slug")
23
+ child_table.add_column("Status")
24
+ child_table.add_column("Reservation", justify="right")
25
+
26
+ table.add_row(
27
+ hardware.get("organization").get("name"),
28
+ print_name,
29
+ hardware_status_string(hardware),
30
+ f"{hardware.get('activeReservation').get('createdBy').get('username')} | {hardware.get('activeReservation').get('status')}"
31
+ if hardware.get("activeReservation", None)
32
+ else "",
33
+ )
34
+
35
+ if len(hardware.get("children", [])) > 0:
36
+ for child in hardware.get("children"):
37
+ name = child.get("name")
38
+ slug = child.get("slug")
39
+ print_name = name
40
+ if name != slug:
41
+ print_name = f"└── {name} | {slug}"
42
+ table.add_row(
43
+ hardware.get("organization").get("name"),
44
+ print_name,
45
+ hardware_status_string(hardware),
46
+ f"{hardware.get('activeReservation').get('createdBy').get('username')} | {hardware.get('activeReservation').get('status')}"
47
+ if hardware.get("activeReservation", None)
48
+ else "",
49
+ )
50
+
51
+ console.print(table)
52
+
53
+
54
+ def hardware_status_string(hardware) -> str:
55
+ if activeReservation := hardware.get("activeReservation"):
56
+ if activeReservation.get("status", None) == "in_progress":
57
+ return "Reserved"
58
+ if hardware.get("isQuarantined"):
59
+ return "Quarantined"
60
+ if not hardware.get("isOnline"):
61
+ return "Offline"
62
+ if not hardware.get("isHealthy"):
63
+ return "Not healthy"
64
+ if not hardware.get("isAvailable"):
65
+ return "Not available"
66
+ else:
67
+ return "Available"
@@ -0,0 +1,102 @@
1
+ from primitive.utils.actions import BaseAction
2
+ from loguru import logger
3
+ from primitive.__about__ import __version__
4
+ from ..utils.exceptions import P_CLI_100
5
+ import sys
6
+ import psutil
7
+ from ..db import sqlite
8
+ from ..db.models import JobRun
9
+ from time import sleep
10
+
11
+
12
+ class Monitor(BaseAction):
13
+ def start(self):
14
+ logger.remove()
15
+ logger.add(
16
+ sink=sys.stderr,
17
+ format="<green>{time:YYYY-MM-DD HH:mm:ss.SSS}</green> | <level>{level: <8}</level> | <level>{message}</level>",
18
+ backtrace=True,
19
+ diagnose=True,
20
+ level="DEBUG" if self.primitive.DEBUG else "INFO",
21
+ )
22
+ logger.info("[*] primitive monitor")
23
+ logger.info(f"[*] Version: {__version__}")
24
+
25
+ # Initialize the database
26
+ sqlite.init()
27
+
28
+ try:
29
+ # hey stupid:
30
+ # do not set is_available to True here, it will mess up the reservation logic
31
+ # only set is_available after we've checked that no active reservation is present
32
+ # setting is_available of the parent also effects the children,
33
+ # which may have active reservations as well
34
+ self.primitive.hardware.check_in_http(is_online=True)
35
+ except Exception as exception:
36
+ logger.exception(f"Error checking in hardware: {exception}")
37
+ sys.exit(1)
38
+
39
+ try:
40
+ while True:
41
+ logger.debug("Syncing children...")
42
+ self.primitive.hardware._sync_children()
43
+
44
+ # Look for entries in the database
45
+ procs = JobRun.objects.all()
46
+
47
+ # No procs in the database => nothing to monitor
48
+ if len(procs) == 0:
49
+ sleep_amount = 5
50
+ logger.debug(
51
+ f"No active processes found... [sleeping {sleep_amount} seconds]"
52
+ )
53
+ sleep(sleep_amount)
54
+ continue
55
+
56
+ # If there is a process in the database, take over check in from agent
57
+ try:
58
+ self.primitive.hardware.check_in_http(is_online=True)
59
+ except Exception as exception:
60
+ logger.exception(f"Error checking in hardware: {exception}")
61
+
62
+ # For each process, check status and kill if cancelled
63
+ for proc in procs:
64
+ logger.debug(f"Checking process {proc.pid}...")
65
+
66
+ status = self.primitive.jobs.get_job_status(proc.job_run_id)
67
+ status_value = status.data["jobRun"]["status"]
68
+ conclusion_value = status.data["jobRun"]["conclusion"]
69
+
70
+ logger.debug(f"- Status: {status_value}")
71
+ logger.debug(f"- Conclusion: {conclusion_value}")
72
+
73
+ try:
74
+ parent = psutil.Process(proc.pid)
75
+ except psutil.NoSuchProcess:
76
+ logger.debug("Process not found")
77
+ continue
78
+
79
+ children = parent.children(recursive=True)
80
+
81
+ if status_value == "completed" and conclusion_value == "cancelled":
82
+ logger.warning("Job cancelled by user")
83
+ for child in children:
84
+ logger.debug(f"Killing child process {child.pid}...")
85
+ child.kill()
86
+
87
+ logger.debug(f"Killing parent process {parent.pid}...")
88
+ parent.kill()
89
+
90
+ sleep(5)
91
+
92
+ except KeyboardInterrupt:
93
+ logger.info("[*] Stopping primitive monitor...")
94
+ try:
95
+ self.primitive.hardware.check_in_http(
96
+ is_available=False, is_online=False, stopping_agent=True
97
+ )
98
+
99
+ except P_CLI_100 as exception:
100
+ logger.error("[*] Error stopping primitive monitor.")
101
+ logger.error(str(exception))
102
+ sys.exit()
@@ -0,0 +1,13 @@
1
+ import click
2
+ import typing
3
+
4
+ if typing.TYPE_CHECKING:
5
+ from ..client import Primitive
6
+
7
+
8
+ @click.command("monitor")
9
+ @click.pass_context
10
+ def cli(context):
11
+ """monitor"""
12
+ primitive: Primitive = context.obj.get("PRIMITIVE")
13
+ primitive.monitor.start()
@@ -89,7 +89,6 @@ class Reservations(BaseAction):
89
89
  )
90
90
  if messages := result.data.get("reservationCreate").get("messages"):
91
91
  for message in messages:
92
- logger.enable("primitive")
93
92
  if message.get("kind") == "ERROR":
94
93
  logger.error(message.get("message"))
95
94
  else:
@@ -141,7 +140,6 @@ class Reservations(BaseAction):
141
140
  reservation = reservation_result.data["reservation"]
142
141
  current_status = reservation["status"]
143
142
 
144
- logger.enable("primitive")
145
143
  logger.debug(
146
144
  f"Waiting {total_sleep_time}s for reservation {reservation_id} to be in_progress."
147
145
  )
primitive/utils/auth.py CHANGED
@@ -11,7 +11,6 @@ MAX_TIME_FOR_BACKOFF = 60 * 15 # 15 minutes
11
11
 
12
12
 
13
13
  def connection_backoff_handler(details):
14
- logger.enable("primitive")
15
14
  logger.error(
16
15
  "Cannot connect to API. Waiting {wait:0.1f} seconds after {tries} tries.".format(
17
16
  **details
@@ -25,7 +24,6 @@ def create_new_session(primitive):
25
24
  fingerprint = primitive.host_config.get("fingerprint")
26
25
 
27
26
  if not token or not transport:
28
- logger.enable("primitive")
29
27
  logger.error(
30
28
  "CLI is not configured. Run `primitive config` to add an auth token."
31
29
  )
@@ -0,0 +1,54 @@
1
+ from pathlib import Path
2
+ from abc import ABC, abstractmethod
3
+
4
+
5
+ class Daemon(ABC):
6
+ name: str
7
+ label: str
8
+
9
+ @property
10
+ @abstractmethod
11
+ def logs(self) -> Path:
12
+ """Path to to agent or service logs"""
13
+ pass
14
+
15
+ @property
16
+ @abstractmethod
17
+ def file_path(self) -> Path:
18
+ """Path to agent or service definition file"""
19
+ pass
20
+
21
+ @abstractmethod
22
+ def install(self) -> bool:
23
+ """Install the daemon"""
24
+ pass
25
+
26
+ @abstractmethod
27
+ def uninstall(self) -> bool:
28
+ """Uninstall the daemon"""
29
+ pass
30
+
31
+ @abstractmethod
32
+ def start(self) -> bool:
33
+ """Start the daemon"""
34
+ pass
35
+
36
+ @abstractmethod
37
+ def stop(self) -> bool:
38
+ """Stop the daemon"""
39
+ pass
40
+
41
+ @abstractmethod
42
+ def is_installed(self) -> bool:
43
+ """Check if the daemon is installed"""
44
+ pass
45
+
46
+ @abstractmethod
47
+ def is_active(self) -> bool:
48
+ """Check if the daemon is active"""
49
+ pass
50
+
51
+ @abstractmethod
52
+ def view_logs(self) -> None:
53
+ """View the daemon logs"""
54
+ pass
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: primitive
3
- Version: 0.2.9
3
+ Version: 0.2.11
4
4
  Project-URL: Documentation, https://github.com//primitivecorp/primitive-cli#readme
5
5
  Project-URL: Issues, https://github.com//primitivecorp/primitive-cli/issues
6
6
  Project-URL: Source, https://github.com//primitivecorp/primitive-cli
@@ -23,9 +23,11 @@ Requires-Dist: gql[all]
23
23
  Requires-Dist: loguru
24
24
  Requires-Dist: paramiko[invoke]
25
25
  Requires-Dist: primitive-pal==0.1.4
26
+ Requires-Dist: psutil>=7.0.0
26
27
  Requires-Dist: pyyaml
27
28
  Requires-Dist: rich>=13.9.4
28
29
  Requires-Dist: speedtest-cli
30
+ Requires-Dist: sqlalchemy>=2.0.40
29
31
  Description-Content-Type: text/markdown
30
32
 
31
33
  # primitive
@@ -1,11 +1,11 @@
1
- primitive/__about__.py,sha256=V16ToyYKX_TkMalQ8iZqJDttwNhendnTztxFcipRvkM,129
1
+ primitive/__about__.py,sha256=51uVt8anKtwpofvSe0Zwd_GncrkYXPbI0DjswyDbXRs,130
2
2
  primitive/__init__.py,sha256=bwKdgggKNVssJFVPfKSxqFMz4IxSr54WWbmiZqTMPNI,106
3
- primitive/cli.py,sha256=58fn6ayVSC1f4hLKx3FUNT9CkuPLva8dFQg0_YUwpio,2410
4
- primitive/client.py,sha256=PPyIQRvKKSqCF9RRF5mJJ4Vqqolpzy1YXqffNLKIvAA,2390
3
+ primitive/cli.py,sha256=g7EtHI9MATAB0qQu5w-WzbXtxz_8zu8z5E7sETmMkKU,2509
4
+ primitive/client.py,sha256=h8WZVnQylVe0vbpuyC8YZHl2JyITSPC-1HbUcmrE5pc,3623
5
5
  primitive/agent/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
6
- primitive/agent/actions.py,sha256=5Lmqxsf24eH6BDEesbJbn1Xj-8ifVlQ_Y3QR8xpkFtM,6869
6
+ primitive/agent/actions.py,sha256=mmMwc9D8zo1w9aLlaYPBArncQ_qqnG6L9TWadcxvO-g,7018
7
7
  primitive/agent/commands.py,sha256=-dVDilELfkGfbZB7qfEPs77Dm1oT62qJj4tsIk4KoxI,254
8
- primitive/agent/runner.py,sha256=NQeJFVEZrUFdwdn4NWzcbIF-vnWHiVeVp5pblH6yVgQ,13329
8
+ primitive/agent/runner.py,sha256=IuY-UMZ1WupYBXuPr-Ne0dcWeLFeV2_O-6F0SiG3VOs,13942
9
9
  primitive/agent/uploader.py,sha256=6pjUyb1LyUCpHBE6p13pRpXxy6iDxu14qJGvE3R6cVo,3155
10
10
  primitive/auth/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
11
11
  primitive/auth/actions.py,sha256=MPsG9LcKcOPwA7gZ9Ewk0PZJhTQvIrGfODdz4GxSzgA,999
@@ -13,16 +13,20 @@ primitive/auth/commands.py,sha256=2z5u5xX64n0yILucx9emtWh3uQXLvs2QQQQIldZGr94,23
13
13
  primitive/auth/graphql/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
14
14
  primitive/auth/graphql/queries.py,sha256=jhrr_VFzHIn8vcVprMIzUx7V4kkWYdR6CKMKPoVFv60,180
15
15
  primitive/daemons/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
16
- primitive/daemons/actions.py,sha256=Nt3yNtbBhen0jK4sRsH_N7AP3UBuyL48VaUhtC7wYq8,2015
17
- primitive/daemons/commands.py,sha256=-Muh-6ib4uAVtPn_67AcMrDwuCwYlCnRQozCi2Xurmk,1726
18
- primitive/daemons/launch_agents.py,sha256=qovt32gwpjGDd82z_SY5EGCUjaUyNA49pZFajZsw3eE,4796
19
- primitive/daemons/launch_service.py,sha256=FPB9qKEjhllRfEpct0ng2L9lpIaGJbQwn1JdFT8uBA8,5600
16
+ primitive/daemons/actions.py,sha256=V4BUCLS8UoQOZoS2vwEkYQpWAUNdZnMPBhQR19RvQXs,2023
17
+ primitive/daemons/commands.py,sha256=Xt4qFymNrDLdHJhRnEH_4Re-2xX6w1OT-chV9k7dFCs,2670
18
+ primitive/daemons/launch_agents.py,sha256=KD7cqQZDtfDmMyNiYrswTRWEktvS9A1QsqQF1jhMDjw,7940
19
+ primitive/daemons/launch_service.py,sha256=IhvKZqU5juA3hKsvUB2275BP8lNBl5XWkVoqVgdwy-o,8013
20
+ primitive/daemons/ui.py,sha256=Af3OJWJ0jdGlb1nfA5yaGYdhBEqqpM8zP2U2vUQdCbw,1236
21
+ primitive/db/base.py,sha256=mH7f2d_jiyxJSSx9Gk53QBXRa3LiKBsBjkFgvmtH1WA,83
22
+ primitive/db/models.py,sha256=UnbRVhYoIG3rjfcjAQaGaJfSi_c7iJVQWfnpKU9TOp4,2543
23
+ primitive/db/sqlite.py,sha256=t942Yrj7Z1wyRla3ZtLdk5Z7rmKDuGUY3fNKc39UbRQ,735
20
24
  primitive/exec/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
21
- primitive/exec/actions.py,sha256=xw9Qyl3dJsMQQH3P_NUefx77PUFgWQXLDRtJmaSMZAY,4163
25
+ primitive/exec/actions.py,sha256=4d_TCjNDcVFoZ9Zw7ZuBa6hKMv2Xzm7_UX_8wcX1aSk,4124
22
26
  primitive/exec/commands.py,sha256=66LO2kkJC-ynNZQpUCXv4Ol15QoacdSZAHblePDcmLo,510
23
27
  primitive/exec/interactive.py,sha256=TscY6s2ZysijidKPheq6y-fCErUVLS0zcdTW8XyFWGI,2435
24
28
  primitive/files/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
25
- primitive/files/actions.py,sha256=orcKDrHRCFIi8w0e57CXE7MYX0s4oX-lbTercYBl8Ro,12444
29
+ primitive/files/actions.py,sha256=jvsBivYBmPeqb6Ge7gECm_x20AFUL7UYPGJJFmoCeOM,12409
26
30
  primitive/files/commands.py,sha256=ZNW4y8JZF1li7P5ej1r-Xcqu0iGpRRlMYvthuZOLLbQ,1163
27
31
  primitive/files/graphql/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
28
32
  primitive/files/graphql/fragments.py,sha256=II6WHZjzSqX4IELwdiWokqHTKvDq6mMHF5gp3rLnj3U,231
@@ -38,9 +42,10 @@ primitive/graphql/relay.py,sha256=bmij2AjdpURQ6GGVCxwWhauF-r_SxuAU2oJ4sDbLxpI,72
38
42
  primitive/graphql/sdk.py,sha256=KhVWDZms_eMBgt6ftSJitRALguagy-nmrj4IC2taeXY,1535
39
43
  primitive/graphql/utility_fragments.py,sha256=uIjwILC4QtWNyO5vu77VjQf_p0jvP3A9q_6zRq91zqs,303
40
44
  primitive/hardware/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
41
- primitive/hardware/actions.py,sha256=4AKXGXraGwNzIzSRT5PpStLz3elc-Og2k4lKnR1NR6w,26092
45
+ primitive/hardware/actions.py,sha256=8irVoDN4uzMMp58sgA9VOB1aO2NwBBVnJfg_k7i5tmA,25912
42
46
  primitive/hardware/android.py,sha256=tu7pBPxWFrIwb_mm5CEdFFf1_veNDOKjOCQg13i_Lh4,2758
43
- primitive/hardware/commands.py,sha256=cWl8j0XtkXQtPHtpO_C6Gh0-dnAEysOFryf3VnDOTOo,5650
47
+ primitive/hardware/commands.py,sha256=ixMPhDOpsU-eONxmimqKVynus-Eaq2XPKEK017WM_rM,3229
48
+ primitive/hardware/ui.py,sha256=12rucuZ2s-w5R4bKyxON5dEbrdDnVf5sbj3K_nbdo44,2473
44
49
  primitive/hardware/graphql/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
45
50
  primitive/hardware/graphql/fragments.py,sha256=kI6qnTNjaEaUr-C6eD55COphtueVYbYOWZwN5EW_3qw,350
46
51
  primitive/hardware/graphql/mutations.py,sha256=_4Hkbfik9Ron4T-meulu6T-9FR_BZjyPNwn745MPksU,1484
@@ -52,6 +57,8 @@ primitive/jobs/graphql/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3
52
57
  primitive/jobs/graphql/fragments.py,sha256=1_ZttT7dx36KDC3DClJz9M8LMpsPwXySBygHSiUEcGg,619
53
58
  primitive/jobs/graphql/mutations.py,sha256=8ASvCmwQh7cMeeiykOdYaYVryG8FRIuVF6v_J8JJZuw,219
54
59
  primitive/jobs/graphql/queries.py,sha256=BrU_GnLjK0bTAmWsLSmGEUea7EM8MqTKxN1Qp6sSjwc,1597
60
+ primitive/monitor/actions.py,sha256=AHPtZRXdvlZNfzpBJd4PkXF5QxTYj0BYwq-qB8PLZZY,3990
61
+ primitive/monitor/commands.py,sha256=dZsD8WKGU4OYO_AlKawfeRNVTMN0xJ-DFRkmKTS464s,258
55
62
  primitive/organizations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
56
63
  primitive/organizations/actions.py,sha256=Tgp_rox0jcvfhQ-LmcWc9vkPdeJu5Bk6U1rNuT9oDnw,1088
57
64
  primitive/organizations/commands.py,sha256=_dwgVEJCqMa5VgB_7P1wLPFc0AuT1p9dtyR9JRr4kpw,487
@@ -71,7 +78,7 @@ primitive/provisioning/actions.py,sha256=IYZYAbtomtZtlkqDaBxx4e7PFKGkRNqek_tABH6
71
78
  primitive/provisioning/graphql/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
72
79
  primitive/provisioning/graphql/queries.py,sha256=cBtuKa6shoatYZfKSnQoPJP6B8g8y3QhFqJ_pkvMcG0,134
73
80
  primitive/reservations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
74
- primitive/reservations/actions.py,sha256=ELQRl9GEVqE_1c7lBxAFS3C9XJuhUEILgDVQkHv8Evc,6257
81
+ primitive/reservations/actions.py,sha256=FiodRTVUgGgFfoksnN9W0XNdGTd2AxPJTfUrZbmQ0_g,6179
75
82
  primitive/reservations/commands.py,sha256=LFRoV59QGgWIjBdrGjJdffHugg8TLe0Fwlcyu_JaTkk,2369
76
83
  primitive/reservations/graphql/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
77
84
  primitive/reservations/graphql/fragments.py,sha256=o5JXkhrFrftYZbsmOQRj105bNw4WwO6U34yN0X-pbCg,411
@@ -79,17 +86,18 @@ primitive/reservations/graphql/mutations.py,sha256=IqzwQL7OclN7RpIcidrTQo9cGYofY
79
86
  primitive/reservations/graphql/queries.py,sha256=x31wTRelskX2fc0fx2qrY7XT1q74nvzLv_Xef3o9weg,746
80
87
  primitive/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
81
88
  primitive/utils/actions.py,sha256=HOFrmM3-0A_A3NS84MqrZ6JmQEiiPSoDqEeuu6b_qfQ,196
82
- primitive/utils/auth.py,sha256=mfO4CwWZtiRZhF498d6v9qeUnLJxi_3jTViuIZI7ijs,1531
89
+ primitive/utils/auth.py,sha256=uBIZNPF2CpbaPV2UMi6eWVUKghV6WIm-pG3-UM29bNs,1465
83
90
  primitive/utils/cache.py,sha256=FHGmVWYLJFQOazpXXcEwI0YJEZbdkgG39nOLdOv6VNk,1575
84
91
  primitive/utils/chunk_size.py,sha256=PAuVuirUTA9oRXyjo1c6MWxo31WVBRkWMuWw-AS58Bw,2914
85
92
  primitive/utils/config.py,sha256=DlFM5Nglo22WPtbpZSVtH7NX-PTMaKYlcrUE7GPRG4c,1058
93
+ primitive/utils/daemons.py,sha256=YkG-OcrTxMhGedbNJMKLq_e7CdTy30Ba2oCVUY-09Co,1086
86
94
  primitive/utils/exceptions.py,sha256=DrYHTcCAJGC7cCUwOx_FmdlVLWRdpzvDvpLb82heppE,311
87
95
  primitive/utils/memory_size.py,sha256=4xfha21kW82nFvOTtDFx9Jk2ZQoEhkfXii-PGNTpIUk,3058
88
96
  primitive/utils/printer.py,sha256=f1XUpqi5dkTL3GWvYRUGlSwtj2IxU1q745T4Fxo7Tn4,370
89
97
  primitive/utils/shell.py,sha256=jWzb7ky7p987dJas6ZvarK3IJNZ5cwBXcryRWb9Uh6U,2072
90
98
  primitive/utils/text.py,sha256=XiESMnlhjQ534xE2hMNf08WehE1SKaYFRNih0MmnK0k,829
91
- primitive-0.2.9.dist-info/METADATA,sha256=ryhKmpz0GrqIcm7mwytK-iMH8SvGdaGTtX4NbROgYr4,3669
92
- primitive-0.2.9.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
93
- primitive-0.2.9.dist-info/entry_points.txt,sha256=p1K8DMCWka5FqLlqP1sPek5Uovy9jq8u51gUsP-z334,48
94
- primitive-0.2.9.dist-info/licenses/LICENSE.txt,sha256=B8kmQMJ2sxYygjCLBk770uacaMci4mPSoJJ8WoDBY_c,1098
95
- primitive-0.2.9.dist-info/RECORD,,
99
+ primitive-0.2.11.dist-info/METADATA,sha256=MR8wugqoR7n8zbscUyXhhgynbMQnmeXAXMnD2fk4gPs,3733
100
+ primitive-0.2.11.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
101
+ primitive-0.2.11.dist-info/entry_points.txt,sha256=p1K8DMCWka5FqLlqP1sPek5Uovy9jq8u51gUsP-z334,48
102
+ primitive-0.2.11.dist-info/licenses/LICENSE.txt,sha256=B8kmQMJ2sxYygjCLBk770uacaMci4mPSoJJ8WoDBY_c,1098
103
+ primitive-0.2.11.dist-info/RECORD,,