moru 0.1.0__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.
Files changed (152) hide show
  1. moru/__init__.py +174 -0
  2. moru/api/__init__.py +164 -0
  3. moru/api/client/__init__.py +8 -0
  4. moru/api/client/api/__init__.py +1 -0
  5. moru/api/client/api/sandboxes/__init__.py +1 -0
  6. moru/api/client/api/sandboxes/delete_sandboxes_sandbox_id.py +161 -0
  7. moru/api/client/api/sandboxes/get_sandboxes.py +176 -0
  8. moru/api/client/api/sandboxes/get_sandboxes_metrics.py +173 -0
  9. moru/api/client/api/sandboxes/get_sandboxes_sandbox_id.py +163 -0
  10. moru/api/client/api/sandboxes/get_sandboxes_sandbox_id_logs.py +199 -0
  11. moru/api/client/api/sandboxes/get_sandboxes_sandbox_id_metrics.py +212 -0
  12. moru/api/client/api/sandboxes/get_v2_sandboxes.py +230 -0
  13. moru/api/client/api/sandboxes/post_sandboxes.py +172 -0
  14. moru/api/client/api/sandboxes/post_sandboxes_sandbox_id_connect.py +193 -0
  15. moru/api/client/api/sandboxes/post_sandboxes_sandbox_id_pause.py +165 -0
  16. moru/api/client/api/sandboxes/post_sandboxes_sandbox_id_refreshes.py +181 -0
  17. moru/api/client/api/sandboxes/post_sandboxes_sandbox_id_resume.py +189 -0
  18. moru/api/client/api/sandboxes/post_sandboxes_sandbox_id_timeout.py +193 -0
  19. moru/api/client/api/templates/__init__.py +1 -0
  20. moru/api/client/api/templates/delete_templates_template_id.py +157 -0
  21. moru/api/client/api/templates/get_templates.py +172 -0
  22. moru/api/client/api/templates/get_templates_template_id.py +195 -0
  23. moru/api/client/api/templates/get_templates_template_id_builds_build_id_status.py +217 -0
  24. moru/api/client/api/templates/get_templates_template_id_files_hash.py +180 -0
  25. moru/api/client/api/templates/patch_templates_template_id.py +183 -0
  26. moru/api/client/api/templates/post_templates.py +172 -0
  27. moru/api/client/api/templates/post_templates_template_id.py +181 -0
  28. moru/api/client/api/templates/post_templates_template_id_builds_build_id.py +170 -0
  29. moru/api/client/api/templates/post_v2_templates.py +172 -0
  30. moru/api/client/api/templates/post_v3_templates.py +172 -0
  31. moru/api/client/api/templates/post_v_2_templates_template_id_builds_build_id.py +192 -0
  32. moru/api/client/client.py +286 -0
  33. moru/api/client/errors.py +16 -0
  34. moru/api/client/models/__init__.py +123 -0
  35. moru/api/client/models/aws_registry.py +85 -0
  36. moru/api/client/models/aws_registry_type.py +8 -0
  37. moru/api/client/models/build_log_entry.py +89 -0
  38. moru/api/client/models/build_status_reason.py +95 -0
  39. moru/api/client/models/connect_sandbox.py +59 -0
  40. moru/api/client/models/created_access_token.py +100 -0
  41. moru/api/client/models/created_team_api_key.py +166 -0
  42. moru/api/client/models/disk_metrics.py +91 -0
  43. moru/api/client/models/error.py +67 -0
  44. moru/api/client/models/gcp_registry.py +69 -0
  45. moru/api/client/models/gcp_registry_type.py +8 -0
  46. moru/api/client/models/general_registry.py +77 -0
  47. moru/api/client/models/general_registry_type.py +8 -0
  48. moru/api/client/models/identifier_masking_details.py +83 -0
  49. moru/api/client/models/listed_sandbox.py +154 -0
  50. moru/api/client/models/log_level.py +11 -0
  51. moru/api/client/models/max_team_metric.py +78 -0
  52. moru/api/client/models/mcp_type_0.py +44 -0
  53. moru/api/client/models/new_access_token.py +59 -0
  54. moru/api/client/models/new_sandbox.py +172 -0
  55. moru/api/client/models/new_team_api_key.py +59 -0
  56. moru/api/client/models/node.py +155 -0
  57. moru/api/client/models/node_detail.py +165 -0
  58. moru/api/client/models/node_metrics.py +122 -0
  59. moru/api/client/models/node_status.py +11 -0
  60. moru/api/client/models/node_status_change.py +79 -0
  61. moru/api/client/models/post_sandboxes_sandbox_id_refreshes_body.py +59 -0
  62. moru/api/client/models/post_sandboxes_sandbox_id_timeout_body.py +59 -0
  63. moru/api/client/models/resumed_sandbox.py +68 -0
  64. moru/api/client/models/sandbox.py +145 -0
  65. moru/api/client/models/sandbox_detail.py +183 -0
  66. moru/api/client/models/sandbox_log.py +70 -0
  67. moru/api/client/models/sandbox_log_entry.py +93 -0
  68. moru/api/client/models/sandbox_log_entry_fields.py +44 -0
  69. moru/api/client/models/sandbox_logs.py +91 -0
  70. moru/api/client/models/sandbox_metric.py +118 -0
  71. moru/api/client/models/sandbox_network_config.py +92 -0
  72. moru/api/client/models/sandbox_state.py +9 -0
  73. moru/api/client/models/sandboxes_with_metrics.py +59 -0
  74. moru/api/client/models/team.py +83 -0
  75. moru/api/client/models/team_api_key.py +158 -0
  76. moru/api/client/models/team_metric.py +86 -0
  77. moru/api/client/models/team_user.py +68 -0
  78. moru/api/client/models/template.py +217 -0
  79. moru/api/client/models/template_build.py +139 -0
  80. moru/api/client/models/template_build_file_upload.py +70 -0
  81. moru/api/client/models/template_build_info.py +126 -0
  82. moru/api/client/models/template_build_request.py +115 -0
  83. moru/api/client/models/template_build_request_v2.py +88 -0
  84. moru/api/client/models/template_build_request_v3.py +88 -0
  85. moru/api/client/models/template_build_start_v2.py +184 -0
  86. moru/api/client/models/template_build_status.py +11 -0
  87. moru/api/client/models/template_legacy.py +207 -0
  88. moru/api/client/models/template_request_response_v3.py +83 -0
  89. moru/api/client/models/template_step.py +91 -0
  90. moru/api/client/models/template_update_request.py +59 -0
  91. moru/api/client/models/template_with_builds.py +148 -0
  92. moru/api/client/models/update_team_api_key.py +59 -0
  93. moru/api/client/py.typed +1 -0
  94. moru/api/client/types.py +54 -0
  95. moru/api/client_async/__init__.py +50 -0
  96. moru/api/client_sync/__init__.py +52 -0
  97. moru/api/metadata.py +14 -0
  98. moru/connection_config.py +217 -0
  99. moru/envd/api.py +59 -0
  100. moru/envd/filesystem/filesystem_connect.py +193 -0
  101. moru/envd/filesystem/filesystem_pb2.py +76 -0
  102. moru/envd/filesystem/filesystem_pb2.pyi +233 -0
  103. moru/envd/process/process_connect.py +155 -0
  104. moru/envd/process/process_pb2.py +92 -0
  105. moru/envd/process/process_pb2.pyi +304 -0
  106. moru/envd/rpc.py +61 -0
  107. moru/envd/versions.py +6 -0
  108. moru/exceptions.py +95 -0
  109. moru/sandbox/commands/command_handle.py +69 -0
  110. moru/sandbox/commands/main.py +39 -0
  111. moru/sandbox/filesystem/filesystem.py +94 -0
  112. moru/sandbox/filesystem/watch_handle.py +60 -0
  113. moru/sandbox/main.py +210 -0
  114. moru/sandbox/mcp.py +1120 -0
  115. moru/sandbox/network.py +8 -0
  116. moru/sandbox/sandbox_api.py +210 -0
  117. moru/sandbox/signature.py +45 -0
  118. moru/sandbox/utils.py +34 -0
  119. moru/sandbox_async/commands/command.py +336 -0
  120. moru/sandbox_async/commands/command_handle.py +196 -0
  121. moru/sandbox_async/commands/pty.py +240 -0
  122. moru/sandbox_async/filesystem/filesystem.py +531 -0
  123. moru/sandbox_async/filesystem/watch_handle.py +62 -0
  124. moru/sandbox_async/main.py +734 -0
  125. moru/sandbox_async/paginator.py +69 -0
  126. moru/sandbox_async/sandbox_api.py +325 -0
  127. moru/sandbox_async/utils.py +7 -0
  128. moru/sandbox_sync/commands/command.py +328 -0
  129. moru/sandbox_sync/commands/command_handle.py +150 -0
  130. moru/sandbox_sync/commands/pty.py +230 -0
  131. moru/sandbox_sync/filesystem/filesystem.py +518 -0
  132. moru/sandbox_sync/filesystem/watch_handle.py +69 -0
  133. moru/sandbox_sync/main.py +726 -0
  134. moru/sandbox_sync/paginator.py +69 -0
  135. moru/sandbox_sync/sandbox_api.py +308 -0
  136. moru/template/consts.py +30 -0
  137. moru/template/dockerfile_parser.py +275 -0
  138. moru/template/logger.py +232 -0
  139. moru/template/main.py +1360 -0
  140. moru/template/readycmd.py +138 -0
  141. moru/template/types.py +105 -0
  142. moru/template/utils.py +320 -0
  143. moru/template_async/build_api.py +202 -0
  144. moru/template_async/main.py +366 -0
  145. moru/template_sync/build_api.py +199 -0
  146. moru/template_sync/main.py +371 -0
  147. moru-0.1.0.dist-info/METADATA +63 -0
  148. moru-0.1.0.dist-info/RECORD +152 -0
  149. moru-0.1.0.dist-info/WHEEL +4 -0
  150. moru-0.1.0.dist-info/licenses/LICENSE +9 -0
  151. moru_connect/__init__.py +1 -0
  152. moru_connect/client.py +493 -0
@@ -0,0 +1,83 @@
1
+ from collections.abc import Mapping
2
+ from typing import Any, TypeVar, cast
3
+
4
+ from attrs import define as _attrs_define
5
+ from attrs import field as _attrs_field
6
+
7
+ T = TypeVar("T", bound="TemplateRequestResponseV3")
8
+
9
+
10
+ @_attrs_define
11
+ class TemplateRequestResponseV3:
12
+ """
13
+ Attributes:
14
+ aliases (list[str]): Aliases of the template
15
+ build_id (str): Identifier of the last successful build for given template
16
+ public (bool): Whether the template is public or only accessible by the team
17
+ template_id (str): Identifier of the template
18
+ """
19
+
20
+ aliases: list[str]
21
+ build_id: str
22
+ public: bool
23
+ template_id: str
24
+ additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
25
+
26
+ def to_dict(self) -> dict[str, Any]:
27
+ aliases = self.aliases
28
+
29
+ build_id = self.build_id
30
+
31
+ public = self.public
32
+
33
+ template_id = self.template_id
34
+
35
+ field_dict: dict[str, Any] = {}
36
+ field_dict.update(self.additional_properties)
37
+ field_dict.update(
38
+ {
39
+ "aliases": aliases,
40
+ "buildID": build_id,
41
+ "public": public,
42
+ "templateID": template_id,
43
+ }
44
+ )
45
+
46
+ return field_dict
47
+
48
+ @classmethod
49
+ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
50
+ d = dict(src_dict)
51
+ aliases = cast(list[str], d.pop("aliases"))
52
+
53
+ build_id = d.pop("buildID")
54
+
55
+ public = d.pop("public")
56
+
57
+ template_id = d.pop("templateID")
58
+
59
+ template_request_response_v3 = cls(
60
+ aliases=aliases,
61
+ build_id=build_id,
62
+ public=public,
63
+ template_id=template_id,
64
+ )
65
+
66
+ template_request_response_v3.additional_properties = d
67
+ return template_request_response_v3
68
+
69
+ @property
70
+ def additional_keys(self) -> list[str]:
71
+ return list(self.additional_properties.keys())
72
+
73
+ def __getitem__(self, key: str) -> Any:
74
+ return self.additional_properties[key]
75
+
76
+ def __setitem__(self, key: str, value: Any) -> None:
77
+ self.additional_properties[key] = value
78
+
79
+ def __delitem__(self, key: str) -> None:
80
+ del self.additional_properties[key]
81
+
82
+ def __contains__(self, key: str) -> bool:
83
+ return key in self.additional_properties
@@ -0,0 +1,91 @@
1
+ from collections.abc import Mapping
2
+ from typing import Any, TypeVar, Union, cast
3
+
4
+ from attrs import define as _attrs_define
5
+ from attrs import field as _attrs_field
6
+
7
+ from ..types import UNSET, Unset
8
+
9
+ T = TypeVar("T", bound="TemplateStep")
10
+
11
+
12
+ @_attrs_define
13
+ class TemplateStep:
14
+ """Step in the template build process
15
+
16
+ Attributes:
17
+ type_ (str): Type of the step
18
+ args (Union[Unset, list[str]]): Arguments for the step
19
+ files_hash (Union[Unset, str]): Hash of the files used in the step
20
+ force (Union[Unset, bool]): Whether the step should be forced to run regardless of the cache Default: False.
21
+ """
22
+
23
+ type_: str
24
+ args: Union[Unset, list[str]] = UNSET
25
+ files_hash: Union[Unset, str] = UNSET
26
+ force: Union[Unset, bool] = False
27
+ additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
28
+
29
+ def to_dict(self) -> dict[str, Any]:
30
+ type_ = self.type_
31
+
32
+ args: Union[Unset, list[str]] = UNSET
33
+ if not isinstance(self.args, Unset):
34
+ args = self.args
35
+
36
+ files_hash = self.files_hash
37
+
38
+ force = self.force
39
+
40
+ field_dict: dict[str, Any] = {}
41
+ field_dict.update(self.additional_properties)
42
+ field_dict.update(
43
+ {
44
+ "type": type_,
45
+ }
46
+ )
47
+ if args is not UNSET:
48
+ field_dict["args"] = args
49
+ if files_hash is not UNSET:
50
+ field_dict["filesHash"] = files_hash
51
+ if force is not UNSET:
52
+ field_dict["force"] = force
53
+
54
+ return field_dict
55
+
56
+ @classmethod
57
+ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
58
+ d = dict(src_dict)
59
+ type_ = d.pop("type")
60
+
61
+ args = cast(list[str], d.pop("args", UNSET))
62
+
63
+ files_hash = d.pop("filesHash", UNSET)
64
+
65
+ force = d.pop("force", UNSET)
66
+
67
+ template_step = cls(
68
+ type_=type_,
69
+ args=args,
70
+ files_hash=files_hash,
71
+ force=force,
72
+ )
73
+
74
+ template_step.additional_properties = d
75
+ return template_step
76
+
77
+ @property
78
+ def additional_keys(self) -> list[str]:
79
+ return list(self.additional_properties.keys())
80
+
81
+ def __getitem__(self, key: str) -> Any:
82
+ return self.additional_properties[key]
83
+
84
+ def __setitem__(self, key: str, value: Any) -> None:
85
+ self.additional_properties[key] = value
86
+
87
+ def __delitem__(self, key: str) -> None:
88
+ del self.additional_properties[key]
89
+
90
+ def __contains__(self, key: str) -> bool:
91
+ return key in self.additional_properties
@@ -0,0 +1,59 @@
1
+ from collections.abc import Mapping
2
+ from typing import Any, TypeVar, Union
3
+
4
+ from attrs import define as _attrs_define
5
+ from attrs import field as _attrs_field
6
+
7
+ from ..types import UNSET, Unset
8
+
9
+ T = TypeVar("T", bound="TemplateUpdateRequest")
10
+
11
+
12
+ @_attrs_define
13
+ class TemplateUpdateRequest:
14
+ """
15
+ Attributes:
16
+ public (Union[Unset, bool]): Whether the template is public or only accessible by the team
17
+ """
18
+
19
+ public: Union[Unset, bool] = UNSET
20
+ additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
21
+
22
+ def to_dict(self) -> dict[str, Any]:
23
+ public = self.public
24
+
25
+ field_dict: dict[str, Any] = {}
26
+ field_dict.update(self.additional_properties)
27
+ field_dict.update({})
28
+ if public is not UNSET:
29
+ field_dict["public"] = public
30
+
31
+ return field_dict
32
+
33
+ @classmethod
34
+ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
35
+ d = dict(src_dict)
36
+ public = d.pop("public", UNSET)
37
+
38
+ template_update_request = cls(
39
+ public=public,
40
+ )
41
+
42
+ template_update_request.additional_properties = d
43
+ return template_update_request
44
+
45
+ @property
46
+ def additional_keys(self) -> list[str]:
47
+ return list(self.additional_properties.keys())
48
+
49
+ def __getitem__(self, key: str) -> Any:
50
+ return self.additional_properties[key]
51
+
52
+ def __setitem__(self, key: str, value: Any) -> None:
53
+ self.additional_properties[key] = value
54
+
55
+ def __delitem__(self, key: str) -> None:
56
+ del self.additional_properties[key]
57
+
58
+ def __contains__(self, key: str) -> bool:
59
+ return key in self.additional_properties
@@ -0,0 +1,148 @@
1
+ import datetime
2
+ from collections.abc import Mapping
3
+ from typing import TYPE_CHECKING, Any, TypeVar, Union, cast
4
+
5
+ from attrs import define as _attrs_define
6
+ from attrs import field as _attrs_field
7
+ from dateutil.parser import isoparse
8
+
9
+ if TYPE_CHECKING:
10
+ from ..models.template_build import TemplateBuild
11
+
12
+
13
+ T = TypeVar("T", bound="TemplateWithBuilds")
14
+
15
+
16
+ @_attrs_define
17
+ class TemplateWithBuilds:
18
+ """
19
+ Attributes:
20
+ aliases (list[str]): Aliases of the template
21
+ builds (list['TemplateBuild']): List of builds for the template
22
+ created_at (datetime.datetime): Time when the template was created
23
+ last_spawned_at (Union[None, datetime.datetime]): Time when the template was last used
24
+ public (bool): Whether the template is public or only accessible by the team
25
+ spawn_count (int): Number of times the template was used
26
+ template_id (str): Identifier of the template
27
+ updated_at (datetime.datetime): Time when the template was last updated
28
+ """
29
+
30
+ aliases: list[str]
31
+ builds: list["TemplateBuild"]
32
+ created_at: datetime.datetime
33
+ last_spawned_at: Union[None, datetime.datetime]
34
+ public: bool
35
+ spawn_count: int
36
+ template_id: str
37
+ updated_at: datetime.datetime
38
+ additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
39
+
40
+ def to_dict(self) -> dict[str, Any]:
41
+ aliases = self.aliases
42
+
43
+ builds = []
44
+ for builds_item_data in self.builds:
45
+ builds_item = builds_item_data.to_dict()
46
+ builds.append(builds_item)
47
+
48
+ created_at = self.created_at.isoformat()
49
+
50
+ last_spawned_at: Union[None, str]
51
+ if isinstance(self.last_spawned_at, datetime.datetime):
52
+ last_spawned_at = self.last_spawned_at.isoformat()
53
+ else:
54
+ last_spawned_at = self.last_spawned_at
55
+
56
+ public = self.public
57
+
58
+ spawn_count = self.spawn_count
59
+
60
+ template_id = self.template_id
61
+
62
+ updated_at = self.updated_at.isoformat()
63
+
64
+ field_dict: dict[str, Any] = {}
65
+ field_dict.update(self.additional_properties)
66
+ field_dict.update(
67
+ {
68
+ "aliases": aliases,
69
+ "builds": builds,
70
+ "createdAt": created_at,
71
+ "lastSpawnedAt": last_spawned_at,
72
+ "public": public,
73
+ "spawnCount": spawn_count,
74
+ "templateID": template_id,
75
+ "updatedAt": updated_at,
76
+ }
77
+ )
78
+
79
+ return field_dict
80
+
81
+ @classmethod
82
+ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
83
+ from ..models.template_build import TemplateBuild
84
+
85
+ d = dict(src_dict)
86
+ aliases = cast(list[str], d.pop("aliases"))
87
+
88
+ builds = []
89
+ _builds = d.pop("builds")
90
+ for builds_item_data in _builds:
91
+ builds_item = TemplateBuild.from_dict(builds_item_data)
92
+
93
+ builds.append(builds_item)
94
+
95
+ created_at = isoparse(d.pop("createdAt"))
96
+
97
+ def _parse_last_spawned_at(data: object) -> Union[None, datetime.datetime]:
98
+ if data is None:
99
+ return data
100
+ try:
101
+ if not isinstance(data, str):
102
+ raise TypeError()
103
+ last_spawned_at_type_0 = isoparse(data)
104
+
105
+ return last_spawned_at_type_0
106
+ except: # noqa: E722
107
+ pass
108
+ return cast(Union[None, datetime.datetime], data)
109
+
110
+ last_spawned_at = _parse_last_spawned_at(d.pop("lastSpawnedAt"))
111
+
112
+ public = d.pop("public")
113
+
114
+ spawn_count = d.pop("spawnCount")
115
+
116
+ template_id = d.pop("templateID")
117
+
118
+ updated_at = isoparse(d.pop("updatedAt"))
119
+
120
+ template_with_builds = cls(
121
+ aliases=aliases,
122
+ builds=builds,
123
+ created_at=created_at,
124
+ last_spawned_at=last_spawned_at,
125
+ public=public,
126
+ spawn_count=spawn_count,
127
+ template_id=template_id,
128
+ updated_at=updated_at,
129
+ )
130
+
131
+ template_with_builds.additional_properties = d
132
+ return template_with_builds
133
+
134
+ @property
135
+ def additional_keys(self) -> list[str]:
136
+ return list(self.additional_properties.keys())
137
+
138
+ def __getitem__(self, key: str) -> Any:
139
+ return self.additional_properties[key]
140
+
141
+ def __setitem__(self, key: str, value: Any) -> None:
142
+ self.additional_properties[key] = value
143
+
144
+ def __delitem__(self, key: str) -> None:
145
+ del self.additional_properties[key]
146
+
147
+ def __contains__(self, key: str) -> bool:
148
+ return key in self.additional_properties
@@ -0,0 +1,59 @@
1
+ from collections.abc import Mapping
2
+ from typing import Any, TypeVar
3
+
4
+ from attrs import define as _attrs_define
5
+ from attrs import field as _attrs_field
6
+
7
+ T = TypeVar("T", bound="UpdateTeamAPIKey")
8
+
9
+
10
+ @_attrs_define
11
+ class UpdateTeamAPIKey:
12
+ """
13
+ Attributes:
14
+ name (str): New name for the API key
15
+ """
16
+
17
+ name: str
18
+ additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
19
+
20
+ def to_dict(self) -> dict[str, Any]:
21
+ name = self.name
22
+
23
+ field_dict: dict[str, Any] = {}
24
+ field_dict.update(self.additional_properties)
25
+ field_dict.update(
26
+ {
27
+ "name": name,
28
+ }
29
+ )
30
+
31
+ return field_dict
32
+
33
+ @classmethod
34
+ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
35
+ d = dict(src_dict)
36
+ name = d.pop("name")
37
+
38
+ update_team_api_key = cls(
39
+ name=name,
40
+ )
41
+
42
+ update_team_api_key.additional_properties = d
43
+ return update_team_api_key
44
+
45
+ @property
46
+ def additional_keys(self) -> list[str]:
47
+ return list(self.additional_properties.keys())
48
+
49
+ def __getitem__(self, key: str) -> Any:
50
+ return self.additional_properties[key]
51
+
52
+ def __setitem__(self, key: str, value: Any) -> None:
53
+ self.additional_properties[key] = value
54
+
55
+ def __delitem__(self, key: str) -> None:
56
+ del self.additional_properties[key]
57
+
58
+ def __contains__(self, key: str) -> bool:
59
+ return key in self.additional_properties
@@ -0,0 +1 @@
1
+ # Marker file for PEP 561
@@ -0,0 +1,54 @@
1
+ """Contains some shared types for properties"""
2
+
3
+ from collections.abc import Mapping, MutableMapping
4
+ from http import HTTPStatus
5
+ from typing import IO, BinaryIO, Generic, Literal, Optional, TypeVar, Union
6
+
7
+ from attrs import define
8
+
9
+
10
+ class Unset:
11
+ def __bool__(self) -> Literal[False]:
12
+ return False
13
+
14
+
15
+ UNSET: Unset = Unset()
16
+
17
+ # The types that `httpx.Client(files=)` can accept, copied from that library.
18
+ FileContent = Union[IO[bytes], bytes, str]
19
+ FileTypes = Union[
20
+ # (filename, file (or bytes), content_type)
21
+ tuple[Optional[str], FileContent, Optional[str]],
22
+ # (filename, file (or bytes), content_type, headers)
23
+ tuple[Optional[str], FileContent, Optional[str], Mapping[str, str]],
24
+ ]
25
+ RequestFiles = list[tuple[str, FileTypes]]
26
+
27
+
28
+ @define
29
+ class File:
30
+ """Contains information for file uploads"""
31
+
32
+ payload: BinaryIO
33
+ file_name: Optional[str] = None
34
+ mime_type: Optional[str] = None
35
+
36
+ def to_tuple(self) -> FileTypes:
37
+ """Return a tuple representation that httpx will accept for multipart/form-data"""
38
+ return self.file_name, self.payload, self.mime_type
39
+
40
+
41
+ T = TypeVar("T")
42
+
43
+
44
+ @define
45
+ class Response(Generic[T]):
46
+ """A response from an endpoint"""
47
+
48
+ status_code: HTTPStatus
49
+ content: bytes
50
+ headers: MutableMapping[str, str]
51
+ parsed: Optional[T]
52
+
53
+
54
+ __all__ = ["UNSET", "File", "FileTypes", "RequestFiles", "Response", "Unset"]
@@ -0,0 +1,50 @@
1
+ import httpx
2
+ import logging
3
+
4
+ from typing import Optional
5
+
6
+ from typing_extensions import Self
7
+
8
+ from moru.connection_config import ConnectionConfig
9
+ from moru.api import limits, AsyncApiClient
10
+
11
+
12
+ logger = logging.getLogger(__name__)
13
+
14
+
15
+ def get_api_client(config: ConnectionConfig, **kwargs) -> AsyncApiClient:
16
+ return AsyncApiClient(
17
+ config,
18
+ transport=get_transport(config),
19
+ **kwargs,
20
+ )
21
+
22
+
23
+ class AsyncTransportWithLogger(httpx.AsyncHTTPTransport):
24
+ singleton: Optional[Self] = None
25
+
26
+ async def handle_async_request(self, request):
27
+ url = f"{request.url.scheme}://{request.url.host}{request.url.path}"
28
+ logger.info(f"Request: {request.method} {url}")
29
+ response = await super().handle_async_request(request)
30
+
31
+ # data = connect.GzipCompressor.decompress(response.read()).decode()
32
+ logger.info(f"Response: {response.status_code} {url}")
33
+
34
+ return response
35
+
36
+ @property
37
+ def pool(self):
38
+ return self._pool
39
+
40
+
41
+ def get_transport(config: ConnectionConfig) -> AsyncTransportWithLogger:
42
+ if AsyncTransportWithLogger.singleton is not None:
43
+ return AsyncTransportWithLogger.singleton
44
+
45
+ transport = AsyncTransportWithLogger(
46
+ limits=limits,
47
+ proxy=config.proxy,
48
+ )
49
+ AsyncTransportWithLogger.singleton = transport
50
+ return transport
@@ -0,0 +1,52 @@
1
+ from typing import Optional
2
+
3
+ import httpx
4
+ import logging
5
+
6
+ from typing_extensions import Self
7
+
8
+ from moru.api import ApiClient, limits
9
+ from moru.connection_config import ConnectionConfig
10
+
11
+ logger = logging.getLogger(__name__)
12
+
13
+
14
+ def get_api_client(config: ConnectionConfig, **kwargs) -> ApiClient:
15
+ return ApiClient(
16
+ config,
17
+ transport=get_transport(config),
18
+ **kwargs,
19
+ )
20
+
21
+
22
+ class TransportWithLogger(httpx.HTTPTransport):
23
+ singleton: Optional[Self] = None
24
+
25
+ def handle_request(self, request):
26
+ url = f"{request.url.scheme}://{request.url.host}{request.url.path}"
27
+ logger.info(f"Request: {request.method} {url}")
28
+ response = super().handle_request(request)
29
+
30
+ # data = connect.GzipCompressor.decompress(response.read()).decode()
31
+ logger.info(f"Response: {response.status_code} {url}")
32
+
33
+ return response
34
+
35
+ @property
36
+ def pool(self):
37
+ return self._pool
38
+
39
+
40
+ _transport: Optional[TransportWithLogger] = None
41
+
42
+
43
+ def get_transport(config: ConnectionConfig) -> TransportWithLogger:
44
+ if TransportWithLogger.singleton is not None:
45
+ return TransportWithLogger.singleton
46
+
47
+ transport = TransportWithLogger(
48
+ limits=limits,
49
+ proxy=config.proxy,
50
+ )
51
+ TransportWithLogger.singleton = transport
52
+ return transport
moru/api/metadata.py ADDED
@@ -0,0 +1,14 @@
1
+ import platform
2
+
3
+ from importlib import metadata
4
+
5
+ package_version = metadata.version("moru")
6
+
7
+ default_headers = {
8
+ "lang": "python",
9
+ "lang_version": platform.python_version(),
10
+ "package_version": metadata.version("moru"),
11
+ "publisher": "moru",
12
+ "sdk_runtime": "python",
13
+ "system": platform.system(),
14
+ }