coding-client 1.21.2__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 (109) hide show
  1. coding_client/__init__.py +1 -0
  2. coding_client/api/__init__.py +19 -0
  3. coding_client/api/exception_handlers.py +158 -0
  4. coding_client/api/logging_setup.py +44 -0
  5. coding_client/api/metrics.py +40 -0
  6. coding_client/api/openapi_config.py +124 -0
  7. coding_client/api/request_logging.py +60 -0
  8. coding_client/api/validation.py +150 -0
  9. coding_client/auth/__init__.py +78 -0
  10. coding_client/auth/_default_tenant.py +132 -0
  11. coding_client/auth/_header_trust.py +98 -0
  12. coding_client/auth/_onbehalf.py +315 -0
  13. coding_client/auth/_trusted_networks.py +94 -0
  14. coding_client/auth/dependencies.py +61 -0
  15. coding_client/auth/middleware.py +445 -0
  16. coding_client/auth/models.py +83 -0
  17. coding_client/auth/outbound.py +137 -0
  18. coding_client/auth/rbac.py +21 -0
  19. coding_client/auth/rbac_coding.py +5 -0
  20. coding_client/auth/tenant.py +650 -0
  21. coding_client/auth/websocket.py +148 -0
  22. coding_client/clients/__init__.py +24 -0
  23. coding_client/clients/base.py +131 -0
  24. coding_client/clients/coding_ai.py +33 -0
  25. coding_client/clients/coding_analysis.py +36 -0
  26. coding_client/clients/coding_containers.py +45 -0
  27. coding_client/clients/coding_github.py +127 -0
  28. coding_client/clients/coding_realtime.py +127 -0
  29. coding_client/clients/coding_security.py +51 -0
  30. coding_client/clients/coding_testing.py +31 -0
  31. coding_client/clients/coding_workspaces.py +265 -0
  32. coding_client/config/__init__.py +12 -0
  33. coding_client/config/base_settings.py +61 -0
  34. coding_client/config/yaml_config_loader.py +172 -0
  35. coding_client/db/__init__.py +42 -0
  36. coding_client/db/db_types.py +122 -0
  37. coding_client/db/exceptions.py +59 -0
  38. coding_client/db/postgres_connection.py +572 -0
  39. coding_client/db/tenant_query_helper.py +417 -0
  40. coding_client/db_init.py +49 -0
  41. coding_client/exceptions/__init__.py +67 -0
  42. coding_client/exceptions/api_exceptions.py +395 -0
  43. coding_client/exceptions/pydantic_ai_exceptions.py +533 -0
  44. coding_client/interfaces/__init__.py +22 -0
  45. coding_client/interfaces/cache_interface.py +179 -0
  46. coding_client/interfaces/container_interface.py +49 -0
  47. coding_client/interfaces/docker_interface.py +283 -0
  48. coding_client/interfaces/graph_interface.py +28 -0
  49. coding_client/interfaces/security_interface.py +72 -0
  50. coding_client/interfaces/webhook_interface.py +67 -0
  51. coding_client/llm/__init__.py +54 -0
  52. coding_client/llm/base_agent.py +195 -0
  53. coding_client/llm/context.py +121 -0
  54. coding_client/llm/responses.py +102 -0
  55. coding_client/llm/routing.py +82 -0
  56. coding_client/llm/settings.py +102 -0
  57. coding_client/models/__init__.py +62 -0
  58. coding_client/models/agent.py +38 -0
  59. coding_client/models/ai_test_failure.py +745 -0
  60. coding_client/models/analysis.py +330 -0
  61. coding_client/models/architecture.py +685 -0
  62. coding_client/models/bug.py +128 -0
  63. coding_client/models/code_graph.py +317 -0
  64. coding_client/models/container.py +241 -0
  65. coding_client/models/core.py +878 -0
  66. coding_client/models/docker_container.py +104 -0
  67. coding_client/models/github.py +293 -0
  68. coding_client/models/logging.py +29 -0
  69. coding_client/models/package_manager.py +257 -0
  70. coding_client/models/pr_validation.py +440 -0
  71. coding_client/models/pydantic_ai.py +395 -0
  72. coding_client/models/repo_scanner.py +249 -0
  73. coding_client/models/responses.py +431 -0
  74. coding_client/models/security.py +185 -0
  75. coding_client/models/static_analysis.py +508 -0
  76. coding_client/models/system.py +48 -0
  77. coding_client/models/test_executor.py +204 -0
  78. coding_client/models/testing.py +673 -0
  79. coding_client/models/testing_config.py +200 -0
  80. coding_client/models/validation.py +127 -0
  81. coding_client/models_init.py +272 -0
  82. coding_client/telemetry.py +195 -0
  83. coding_client/testing.py +180 -0
  84. coding_client/types/__init__.py +130 -0
  85. coding_client/types/constraint_types.py +276 -0
  86. coding_client/types/core_types.py +112 -0
  87. coding_client/types/state_machine.py +443 -0
  88. coding_client/utils/__init__.py +86 -0
  89. coding_client/utils/archive_utils.py +387 -0
  90. coding_client/utils/ast_debug.py +45 -0
  91. coding_client/utils/async_timeout.py +364 -0
  92. coding_client/utils/constants.py +518 -0
  93. coding_client/utils/content_processing.py +326 -0
  94. coding_client/utils/database.py +916 -0
  95. coding_client/utils/encoding_helper.py +222 -0
  96. coding_client/utils/enum_helpers.py +166 -0
  97. coding_client/utils/file_operations.py +177 -0
  98. coding_client/utils/filesystem_ops.py +528 -0
  99. coding_client/utils/http_client.py +562 -0
  100. coding_client/utils/path_utils.py +471 -0
  101. coding_client/utils/profiling.py +421 -0
  102. coding_client/utils/response_builder.py +240 -0
  103. coding_client/utils/retry_helper.py +712 -0
  104. coding_client/utils/security_validation.py +423 -0
  105. coding_client-1.21.2.dist-info/METADATA +234 -0
  106. coding_client-1.21.2.dist-info/RECORD +109 -0
  107. coding_client-1.21.2.dist-info/WHEEL +5 -0
  108. coding_client-1.21.2.dist-info/licenses/LICENSE +201 -0
  109. coding_client-1.21.2.dist-info/top_level.txt +1 -0
@@ -0,0 +1,222 @@
1
+ """
2
+ Encoding helper utilities for handling text encoding/decoding.
3
+
4
+ This module centralizes encoding operations to reduce cyclomatic complexity
5
+ across services that handle file content (github_integration_service, etc.).
6
+ """
7
+
8
+ import logging
9
+
10
+ logger = logging.getLogger(__name__)
11
+
12
+ # Default encoding fallback chain
13
+ DEFAULT_ENCODINGS: list[str] = ["utf-8", "latin-1", "cp1252", "iso-8859-1"]
14
+
15
+
16
+ def decode_with_fallback(
17
+ content: bytes,
18
+ encodings: list[str] | None = None,
19
+ errors: str = "strict",
20
+ log_fallback: bool = True,
21
+ ) -> tuple[str, str]:
22
+ """
23
+ Decode bytes to string, trying multiple encodings.
24
+
25
+ Args:
26
+ content: Bytes to decode
27
+ encodings: List of encodings to try (default: utf-8, latin-1, cp1252, iso-8859-1)
28
+ errors: Error handling mode for final attempt ('strict', 'replace', 'ignore')
29
+ log_fallback: Whether to log when falling back to non-utf8 encoding
30
+
31
+ Returns:
32
+ Tuple of (decoded_string, encoding_used)
33
+
34
+ Raises:
35
+ UnicodeDecodeError: If all encodings fail and errors='strict'
36
+
37
+ Example:
38
+ # Instead of:
39
+ # try:
40
+ # content = content.decode("utf-8")
41
+ # except UnicodeDecodeError:
42
+ # for encoding in ["latin-1", "cp1252", "iso-8859-1"]:
43
+ # try:
44
+ # content = content.decode(encoding)
45
+ # break
46
+ # except UnicodeDecodeError:
47
+ # continue
48
+
49
+ # Use:
50
+ content, encoding = decode_with_fallback(raw_bytes)
51
+ """
52
+ if encodings is None:
53
+ encodings = DEFAULT_ENCODINGS.copy()
54
+
55
+ last_error: UnicodeDecodeError | None = None
56
+
57
+ for encoding in encodings:
58
+ try:
59
+ decoded = content.decode(encoding)
60
+ if encoding != "utf-8" and log_fallback:
61
+ logger.debug(f"Decoded content using fallback encoding: {encoding}")
62
+ return decoded, encoding
63
+ except UnicodeDecodeError as e:
64
+ last_error = e
65
+ continue
66
+
67
+ # If all encodings failed, try with error handling
68
+ if errors != "strict":
69
+ try:
70
+ decoded = content.decode("utf-8", errors=errors)
71
+ logger.warning(f"Decoded content with error handling mode: {errors}")
72
+ return decoded, f"utf-8-{errors}"
73
+ except UnicodeDecodeError:
74
+ pass
75
+
76
+ # Raise the last error if nothing worked
77
+ if last_error:
78
+ raise last_error
79
+ raise UnicodeDecodeError("utf-8", content, 0, len(content), "All encodings failed")
80
+
81
+
82
+ def decode_safe(
83
+ content: bytes,
84
+ encodings: list[str] | None = None,
85
+ default: str = "",
86
+ ) -> str:
87
+ """
88
+ Safely decode bytes to string, returning default on failure.
89
+
90
+ Args:
91
+ content: Bytes to decode
92
+ encodings: List of encodings to try
93
+ default: Value to return if decoding fails
94
+
95
+ Returns:
96
+ Decoded string or default
97
+
98
+ Example:
99
+ content = decode_safe(raw_bytes, default="<binary content>")
100
+ """
101
+ try:
102
+ decoded, _ = decode_with_fallback(content, encodings, errors="replace")
103
+ return decoded
104
+ except Exception:
105
+ return default
106
+
107
+
108
+ def encode_safe(
109
+ content: str,
110
+ encoding: str = "utf-8",
111
+ errors: str = "replace",
112
+ ) -> bytes:
113
+ """
114
+ Safely encode string to bytes with error handling.
115
+
116
+ Args:
117
+ content: String to encode
118
+ encoding: Target encoding
119
+ errors: Error handling mode ('strict', 'replace', 'ignore', 'xmlcharrefreplace')
120
+
121
+ Returns:
122
+ Encoded bytes
123
+
124
+ Example:
125
+ # Instead of:
126
+ # content = content.encode("utf-8", errors="replace").decode("utf-8")
127
+ # Use:
128
+ safe_bytes = encode_safe(content)
129
+ """
130
+ return content.encode(encoding, errors=errors)
131
+
132
+
133
+ def normalize_to_utf8(content: str | bytes) -> str:
134
+ """
135
+ Normalize content to UTF-8 string, handling both bytes and strings.
136
+
137
+ Args:
138
+ content: String or bytes to normalize
139
+
140
+ Returns:
141
+ UTF-8 normalized string
142
+
143
+ Example:
144
+ text = normalize_to_utf8(possibly_bytes_or_string)
145
+ """
146
+ if isinstance(content, bytes):
147
+ decoded, _ = decode_with_fallback(content, errors="replace")
148
+ return decoded
149
+ return content.encode("utf-8", errors="replace").decode("utf-8")
150
+
151
+
152
+ def is_binary_content(content: bytes, sample_size: int = 8192) -> bool:
153
+ """
154
+ Detect if content appears to be binary (non-text).
155
+
156
+ Args:
157
+ content: Bytes to check
158
+ sample_size: Number of bytes to sample for detection
159
+
160
+ Returns:
161
+ True if content appears to be binary
162
+
163
+ Example:
164
+ if is_binary_content(file_bytes):
165
+ logger.info("Skipping binary file")
166
+ """
167
+ # Check for null bytes (common indicator of binary)
168
+ sample = content[:sample_size]
169
+ if b"\x00" in sample:
170
+ return True
171
+
172
+ # Try to decode as UTF-8
173
+ try:
174
+ sample.decode("utf-8")
175
+ return False
176
+ except UnicodeDecodeError:
177
+ pass
178
+
179
+ # Try common text encodings
180
+ for encoding in ["latin-1", "cp1252"]:
181
+ try:
182
+ decoded = sample.decode(encoding)
183
+ # Check for high ratio of control characters (likely binary)
184
+ control_chars = sum(1 for c in decoded if ord(c) < 32 and c not in "\n\r\t")
185
+ if control_chars / len(decoded) > 0.1:
186
+ return True
187
+ return False
188
+ except UnicodeDecodeError:
189
+ continue
190
+
191
+ return True
192
+
193
+
194
+ def strip_bom(content: str | bytes) -> str | bytes:
195
+ """
196
+ Remove BOM (Byte Order Mark) from content.
197
+
198
+ Args:
199
+ content: String or bytes that may contain BOM
200
+
201
+ Returns:
202
+ Content with BOM removed
203
+
204
+ Example:
205
+ clean_content = strip_bom(file_content)
206
+ """
207
+ if isinstance(content, bytes):
208
+ # UTF-8 BOM
209
+ if content.startswith(b"\xef\xbb\xbf"):
210
+ return content[3:]
211
+ # UTF-16 BOMs
212
+ if content.startswith((b"\xff\xfe", b"\xfe\xff")):
213
+ return content[2:]
214
+ # UTF-32 BOMs
215
+ if content.startswith((b"\xff\xfe\x00\x00", b"\x00\x00\xfe\xff")):
216
+ return content[4:]
217
+ return content
218
+
219
+ # String version
220
+ if content.startswith("\ufeff"):
221
+ return content[1:]
222
+ return content
@@ -0,0 +1,166 @@
1
+ """
2
+ Enum helper utilities for safe value extraction.
3
+
4
+ This module provides utilities to reduce cyclomatic complexity when
5
+ extracting values from enums or enum-like objects across the codebase.
6
+ """
7
+
8
+ from enum import Enum
9
+ from typing import Any, TypeVar, cast
10
+
11
+ T = TypeVar("T")
12
+
13
+
14
+ def safe_get_enum_value(
15
+ obj: Any,
16
+ attr_name: str,
17
+ default: str = "unknown",
18
+ ) -> str:
19
+ """
20
+ Safely extract enum value from an object attribute.
21
+
22
+ Handles cases where:
23
+ - The attribute doesn't exist
24
+ - The attribute is an Enum (extracts .value)
25
+ - The attribute is already a string
26
+ - The attribute is None
27
+
28
+ Args:
29
+ obj: Object to extract attribute from
30
+ attr_name: Name of the attribute to extract
31
+ default: Default value if attribute not found or None
32
+
33
+ Returns:
34
+ String value of the attribute
35
+
36
+ Example:
37
+ # Instead of:
38
+ # getattr(insight, "severity", "info").value if hasattr(...) else str(...)
39
+
40
+ # Use:
41
+ safe_get_enum_value(insight, "severity", "info")
42
+ """
43
+ value = getattr(obj, attr_name, None)
44
+
45
+ if value is None:
46
+ return default
47
+
48
+ if isinstance(value, Enum):
49
+ return str(value.value)
50
+
51
+ if hasattr(value, "value"):
52
+ return str(value.value)
53
+
54
+ return str(value)
55
+
56
+
57
+ def safe_get_nested_enum(
58
+ obj: Any,
59
+ *attr_path: str,
60
+ default: str = "unknown",
61
+ ) -> str:
62
+ """
63
+ Safely extract enum value from a nested attribute path.
64
+
65
+ Args:
66
+ obj: Root object to start from
67
+ *attr_path: Sequence of attribute names to traverse
68
+ default: Default value if path doesn't exist
69
+
70
+ Returns:
71
+ String value of the final attribute
72
+
73
+ Example:
74
+ # Instead of deeply nested getattr chains:
75
+ safe_get_nested_enum(result, "analysis", "severity", default="low")
76
+ """
77
+ current = obj
78
+
79
+ for attr in attr_path:
80
+ current = getattr(current, attr, None)
81
+ if current is None:
82
+ return default
83
+
84
+ if isinstance(current, Enum):
85
+ return str(current.value)
86
+
87
+ if hasattr(current, "value"):
88
+ return str(current.value)
89
+
90
+ return str(current)
91
+
92
+
93
+ def enum_to_str(value: Enum | str | None, default: str = "unknown") -> str:
94
+ """
95
+ Convert an enum or string to string representation.
96
+
97
+ Args:
98
+ value: Enum instance, string, or None
99
+ default: Default value if None
100
+
101
+ Returns:
102
+ String representation
103
+ """
104
+ if value is None:
105
+ return default
106
+
107
+ if isinstance(value, Enum):
108
+ return str(value.value)
109
+
110
+ if hasattr(value, "value"):
111
+ return str(value.value)
112
+
113
+ return str(value)
114
+
115
+
116
+ def safe_enum_name(value: Enum | str | None, default: str = "unknown") -> str:
117
+ """
118
+ Get the name of an enum (not its value).
119
+
120
+ Args:
121
+ value: Enum instance or string
122
+ default: Default if None
123
+
124
+ Returns:
125
+ Enum name as string
126
+ """
127
+ if value is None:
128
+ return default
129
+
130
+ if isinstance(value, Enum):
131
+ return value.name
132
+
133
+ if hasattr(value, "name"):
134
+ return str(value.name)
135
+
136
+ return str(value)
137
+
138
+
139
+ def get_enum_or_default[T](
140
+ enum_class: type,
141
+ value: Any,
142
+ default: T | None = None,
143
+ ) -> Enum | T | None:
144
+ """
145
+ Safely get an enum member by value, with fallback.
146
+
147
+ Args:
148
+ enum_class: The enum class to look up
149
+ value: Value to look up in the enum
150
+ default: Default to return if not found
151
+
152
+ Returns:
153
+ Enum member or default
154
+
155
+ Example:
156
+ status = get_enum_or_default(StatusEnum, "active", StatusEnum.UNKNOWN)
157
+ """
158
+ if value is None:
159
+ return default
160
+
161
+ try:
162
+ if isinstance(value, enum_class):
163
+ return cast(Enum, value)
164
+ return cast(Enum, enum_class(value))
165
+ except (ValueError, KeyError):
166
+ return default
@@ -0,0 +1,177 @@
1
+ """Common file operation utilities to reduce code duplication.
2
+
3
+ This module provides reusable file handling functions for reading, writing,
4
+ processing, and managing files across the application.
5
+
6
+ This module now serves as a compatibility layer that imports from specialized modules:
7
+ - filesystem_ops: Core file system operations
8
+ - path_utils: Path validation and manipulation
9
+ - content_processing: File content processing (JSON/YAML, encoding)
10
+ - archive_utils: Backup, temp files, and atomic operations
11
+ - security_validation: File security and validation
12
+ """
13
+
14
+ from .archive_utils import ( # Archive and backup operations
15
+ async_atomic_write,
16
+ async_create_backup,
17
+ atomic_write,
18
+ cleanup_temp_files,
19
+ create_backup,
20
+ create_backup_directory,
21
+ create_temp_copy,
22
+ preserve_permissions,
23
+ safe_replace,
24
+ temp_directory,
25
+ temp_file,
26
+ )
27
+ from .content_processing import ( # Content processing
28
+ async_detect_encoding,
29
+ async_process_files,
30
+ async_read_json,
31
+ async_read_yaml,
32
+ async_write_json,
33
+ async_write_yaml,
34
+ detect_encoding,
35
+ format_json,
36
+ format_yaml,
37
+ process_files,
38
+ read_json,
39
+ read_yaml,
40
+ validate_json_content,
41
+ validate_yaml_content,
42
+ write_json,
43
+ write_yaml,
44
+ )
45
+
46
+ # Import all functions from specialized modules for backward compatibility
47
+ from .filesystem_ops import ( # Exceptions; Core file operations
48
+ FileNotFoundError,
49
+ FileOperationError,
50
+ FilePermissionError,
51
+ FileSizeError,
52
+ append_to_file,
53
+ async_read_file,
54
+ async_read_file_chunks,
55
+ async_write_file,
56
+ copy_file,
57
+ delete_directory,
58
+ delete_file,
59
+ ensure_directory,
60
+ move_file,
61
+ read_file,
62
+ read_file_chunks,
63
+ read_file_lines,
64
+ write_file,
65
+ )
66
+ from .path_utils import ( # Path operations
67
+ create_directory_tree,
68
+ find_files_by_extension,
69
+ find_files_by_name,
70
+ find_files_containing,
71
+ get_directory_size,
72
+ get_relative_path,
73
+ is_empty_directory,
74
+ join_paths,
75
+ list_files,
76
+ normalize_path,
77
+ should_ignore_path,
78
+ validate_path,
79
+ )
80
+ from .security_validation import ( # Security and validation
81
+ check_file_integrity,
82
+ get_file_hash,
83
+ get_file_info,
84
+ get_file_permissions,
85
+ get_file_size,
86
+ get_safe_temp_dir,
87
+ is_executable_file,
88
+ is_safe_filename,
89
+ sanitize_filename,
90
+ validate_directory_access,
91
+ validate_file_access,
92
+ verify_file_hash,
93
+ )
94
+
95
+ # Export all public functions for backward compatibility
96
+ __all__ = [
97
+ # Exceptions
98
+ "FileOperationError",
99
+ "FileSizeError",
100
+ "FileNotFoundError",
101
+ "FilePermissionError",
102
+ # Reading
103
+ "read_file",
104
+ "async_read_file",
105
+ "read_file_lines",
106
+ "read_file_chunks",
107
+ "async_read_file_chunks",
108
+ # Writing
109
+ "write_file",
110
+ "async_write_file",
111
+ "append_to_file",
112
+ # JSON
113
+ "read_json",
114
+ "async_read_json",
115
+ "write_json",
116
+ "async_write_json",
117
+ "validate_json_content",
118
+ "format_json",
119
+ # YAML
120
+ "read_yaml",
121
+ "async_read_yaml",
122
+ "write_yaml",
123
+ "async_write_yaml",
124
+ "validate_yaml_content",
125
+ "format_yaml",
126
+ # Directory operations
127
+ "ensure_directory",
128
+ "list_files",
129
+ "should_ignore_path",
130
+ "copy_file",
131
+ "move_file",
132
+ "delete_file",
133
+ "delete_directory",
134
+ # Path utilities
135
+ "normalize_path",
136
+ "validate_path",
137
+ "join_paths",
138
+ "get_relative_path",
139
+ "find_files_by_extension",
140
+ "find_files_by_name",
141
+ "find_files_containing",
142
+ "get_directory_size",
143
+ "is_empty_directory",
144
+ "create_directory_tree",
145
+ # Utilities
146
+ "get_file_size",
147
+ "get_file_hash",
148
+ "verify_file_hash",
149
+ "get_file_info",
150
+ "get_file_permissions",
151
+ "detect_encoding",
152
+ "async_detect_encoding",
153
+ # Security and validation
154
+ "validate_file_access",
155
+ "validate_directory_access",
156
+ "check_file_integrity",
157
+ "is_safe_filename",
158
+ "sanitize_filename",
159
+ "is_executable_file",
160
+ "get_safe_temp_dir",
161
+ # Archive and backup
162
+ "create_backup",
163
+ "async_create_backup",
164
+ "create_backup_directory",
165
+ "create_temp_copy",
166
+ "safe_replace",
167
+ "cleanup_temp_files",
168
+ # Context managers
169
+ "temp_file",
170
+ "temp_directory",
171
+ "atomic_write",
172
+ "async_atomic_write",
173
+ "preserve_permissions",
174
+ # Processing
175
+ "process_files",
176
+ "async_process_files",
177
+ ]