refactor: Major upgrade to v5.1b6 - AWS SSM support & Distributed Architecture
Core & Protocols: - Native AWS SSM support added (aws ssm start-session). - Improved Pexpect logic for ssm, kubectl, and docker. - Cleaned connection success messages (omitting ports for non-IP protocols). gRPC Layer: - Migrated gRPC modules to 'connpy/grpc_layer/'. - Implemented dynamic node naming (e.g. ssm-i-xxxx@aws) for accurate server-side logging. - Added automatic sys.path resolution for gRPC generated modules. - Enhanced InteractNode response with initial connection status. Printer & Concurrency: - Implemented ThreadLocalStream for isolated thread-safe output. - Self-healing Console objects to prevent 'closed file' errors in test/async environments. - Capture clean plugin output in remote executions. AI & Services: - Improved tool registration and debug visualization. - Restored native dictionary returns for AI tools to fix Web UI rendering. - Increased backup retention to 100 copies in SyncService. - Silenced noisy auto-sync CLI messages. Quality & Docs: - Total tests: 267 (all passing). - New test suites for gRPC layer and printer concurrency. - Updated .gitignore to exclude internal planning docs. - Full technical documentation regenerated with pdoc.
This commit is contained in:
@@ -3,7 +3,7 @@
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1">
|
||||
<meta name="generator" content="pdoc3 0.11.5">
|
||||
<meta name="generator" content="pdoc3 0.11.6">
|
||||
<title>connpy.cli.ai_handler API documentation</title>
|
||||
<meta name="description" content="">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/13.0.0/sanitize.min.css" integrity="sha512-y1dtMcuvtTMJc1yPgEqF0ZjQbhnc/bFhyvIyVNb9Zk5mIGtqVaAB1Ttl28su8AvFMOY0EwRbAe+HCLqj6W7/KA==" crossorigin>
|
||||
@@ -371,7 +371,7 @@ el.replaceWith(d);
|
||||
</nav>
|
||||
</main>
|
||||
<footer id="footer">
|
||||
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.11.5</a>.</p>
|
||||
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.11.6</a>.</p>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1">
|
||||
<meta name="generator" content="pdoc3 0.11.5">
|
||||
<meta name="generator" content="pdoc3 0.11.6">
|
||||
<title>connpy.cli.api_handler API documentation</title>
|
||||
<meta name="description" content="">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/13.0.0/sanitize.min.css" integrity="sha512-y1dtMcuvtTMJc1yPgEqF0ZjQbhnc/bFhyvIyVNb9Zk5mIGtqVaAB1Ttl28su8AvFMOY0EwRbAe+HCLqj6W7/KA==" crossorigin>
|
||||
@@ -193,7 +193,7 @@ el.replaceWith(d);
|
||||
</nav>
|
||||
</main>
|
||||
<footer id="footer">
|
||||
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.11.5</a>.</p>
|
||||
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.11.6</a>.</p>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1">
|
||||
<meta name="generator" content="pdoc3 0.11.5">
|
||||
<meta name="generator" content="pdoc3 0.11.6">
|
||||
<title>connpy.cli.config_handler API documentation</title>
|
||||
<meta name="description" content="">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/13.0.0/sanitize.min.css" integrity="sha512-y1dtMcuvtTMJc1yPgEqF0ZjQbhnc/bFhyvIyVNb9Zk5mIGtqVaAB1Ttl28su8AvFMOY0EwRbAe+HCLqj6W7/KA==" crossorigin>
|
||||
@@ -482,7 +482,7 @@ el.replaceWith(d);
|
||||
</nav>
|
||||
</main>
|
||||
<footer id="footer">
|
||||
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.11.5</a>.</p>
|
||||
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.11.6</a>.</p>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1">
|
||||
<meta name="generator" content="pdoc3 0.11.5">
|
||||
<meta name="generator" content="pdoc3 0.11.6">
|
||||
<title>connpy.cli.context_handler API documentation</title>
|
||||
<meta name="description" content="">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/13.0.0/sanitize.min.css" integrity="sha512-y1dtMcuvtTMJc1yPgEqF0ZjQbhnc/bFhyvIyVNb9Zk5mIGtqVaAB1Ttl28su8AvFMOY0EwRbAe+HCLqj6W7/KA==" crossorigin>
|
||||
@@ -249,7 +249,7 @@ el.replaceWith(d);
|
||||
</nav>
|
||||
</main>
|
||||
<footer id="footer">
|
||||
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.11.5</a>.</p>
|
||||
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.11.6</a>.</p>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1">
|
||||
<meta name="generator" content="pdoc3 0.11.5">
|
||||
<meta name="generator" content="pdoc3 0.11.6">
|
||||
<title>connpy.cli.forms API documentation</title>
|
||||
<meta name="description" content="">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/13.0.0/sanitize.min.css" integrity="sha512-y1dtMcuvtTMJc1yPgEqF0ZjQbhnc/bFhyvIyVNb9Zk5mIGtqVaAB1Ttl28su8AvFMOY0EwRbAe+HCLqj6W7/KA==" crossorigin>
|
||||
@@ -517,7 +517,7 @@ el.replaceWith(d);
|
||||
</nav>
|
||||
</main>
|
||||
<footer id="footer">
|
||||
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.11.5</a>.</p>
|
||||
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.11.6</a>.</p>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1">
|
||||
<meta name="generator" content="pdoc3 0.11.5">
|
||||
<meta name="generator" content="pdoc3 0.11.6">
|
||||
<title>connpy.cli.help_text API documentation</title>
|
||||
<meta name="description" content="">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/13.0.0/sanitize.min.css" integrity="sha512-y1dtMcuvtTMJc1yPgEqF0ZjQbhnc/bFhyvIyVNb9Zk5mIGtqVaAB1Ttl28su8AvFMOY0EwRbAe+HCLqj6W7/KA==" crossorigin>
|
||||
@@ -94,6 +94,7 @@ Here are some important instructions and tips for configuring your new node:
|
||||
- telnet
|
||||
- kubectl (`kubectl exec`)
|
||||
- docker (`docker exec`)
|
||||
- ssm (`aws ssm start-session`)
|
||||
|
||||
3. **Optional Values**:
|
||||
- You can leave any value empty except for the hostname/IP.
|
||||
@@ -303,7 +304,7 @@ tasks:
|
||||
</nav>
|
||||
</main>
|
||||
<footer id="footer">
|
||||
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.11.5</a>.</p>
|
||||
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.11.6</a>.</p>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1">
|
||||
<meta name="generator" content="pdoc3 0.11.5">
|
||||
<meta name="generator" content="pdoc3 0.11.6">
|
||||
<title>connpy.cli.helpers API documentation</title>
|
||||
<meta name="description" content="">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/13.0.0/sanitize.min.css" integrity="sha512-y1dtMcuvtTMJc1yPgEqF0ZjQbhnc/bFhyvIyVNb9Zk5mIGtqVaAB1Ttl28su8AvFMOY0EwRbAe+HCLqj6W7/KA==" crossorigin>
|
||||
@@ -207,7 +207,7 @@ el.replaceWith(d);
|
||||
</nav>
|
||||
</main>
|
||||
<footer id="footer">
|
||||
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.11.5</a>.</p>
|
||||
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.11.6</a>.</p>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1">
|
||||
<meta name="generator" content="pdoc3 0.11.5">
|
||||
<meta name="generator" content="pdoc3 0.11.6">
|
||||
<title>connpy.cli.import_export_handler API documentation</title>
|
||||
<meta name="description" content="">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/13.0.0/sanitize.min.css" integrity="sha512-y1dtMcuvtTMJc1yPgEqF0ZjQbhnc/bFhyvIyVNb9Zk5mIGtqVaAB1Ttl28su8AvFMOY0EwRbAe+HCLqj6W7/KA==" crossorigin>
|
||||
@@ -272,7 +272,7 @@ el.replaceWith(d);
|
||||
</nav>
|
||||
</main>
|
||||
<footer id="footer">
|
||||
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.11.5</a>.</p>
|
||||
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.11.6</a>.</p>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1">
|
||||
<meta name="generator" content="pdoc3 0.11.5">
|
||||
<meta name="generator" content="pdoc3 0.11.6">
|
||||
<title>connpy.cli API documentation</title>
|
||||
<meta name="description" content="">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/13.0.0/sanitize.min.css" integrity="sha512-y1dtMcuvtTMJc1yPgEqF0ZjQbhnc/bFhyvIyVNb9Zk5mIGtqVaAB1Ttl28su8AvFMOY0EwRbAe+HCLqj6W7/KA==" crossorigin>
|
||||
@@ -137,7 +137,7 @@ el.replaceWith(d);
|
||||
</nav>
|
||||
</main>
|
||||
<footer id="footer">
|
||||
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.11.5</a>.</p>
|
||||
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.11.6</a>.</p>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1">
|
||||
<meta name="generator" content="pdoc3 0.11.5">
|
||||
<meta name="generator" content="pdoc3 0.11.6">
|
||||
<title>connpy.cli.node_handler API documentation</title>
|
||||
<meta name="description" content="">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/13.0.0/sanitize.min.css" integrity="sha512-y1dtMcuvtTMJc1yPgEqF0ZjQbhnc/bFhyvIyVNb9Zk5mIGtqVaAB1Ttl28su8AvFMOY0EwRbAe+HCLqj6W7/KA==" crossorigin>
|
||||
@@ -168,6 +168,10 @@ el.replaceWith(d);
|
||||
printer.error(f"Node '{args.data}' already exists.")
|
||||
sys.exit(1)
|
||||
uniques = self.app.services.nodes.explode_unique(args.data)
|
||||
|
||||
# Fast fail if parent folder does not exist
|
||||
self.app.services.nodes.validate_parent_folder(args.data)
|
||||
|
||||
printer.console.print(Markdown(get_instructions()))
|
||||
|
||||
new_node_data = self.forms.questions_nodes(args.data, uniques)
|
||||
@@ -310,6 +314,10 @@ el.replaceWith(d);
|
||||
printer.error(f"Node '{args.data}' already exists.")
|
||||
sys.exit(1)
|
||||
uniques = self.app.services.nodes.explode_unique(args.data)
|
||||
|
||||
# Fast fail if parent folder does not exist
|
||||
self.app.services.nodes.validate_parent_folder(args.data)
|
||||
|
||||
printer.console.print(Markdown(get_instructions()))
|
||||
|
||||
new_node_data = self.forms.questions_nodes(args.data, uniques)
|
||||
@@ -598,7 +606,7 @@ el.replaceWith(d);
|
||||
</nav>
|
||||
</main>
|
||||
<footer id="footer">
|
||||
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.11.5</a>.</p>
|
||||
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.11.6</a>.</p>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1">
|
||||
<meta name="generator" content="pdoc3 0.11.5">
|
||||
<meta name="generator" content="pdoc3 0.11.6">
|
||||
<title>connpy.cli.plugin_handler API documentation</title>
|
||||
<meta name="description" content="">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/13.0.0/sanitize.min.css" integrity="sha512-y1dtMcuvtTMJc1yPgEqF0ZjQbhnc/bFhyvIyVNb9Zk5mIGtqVaAB1Ttl28su8AvFMOY0EwRbAe+HCLqj6W7/KA==" crossorigin>
|
||||
@@ -385,7 +385,7 @@ el.replaceWith(d);
|
||||
</nav>
|
||||
</main>
|
||||
<footer id="footer">
|
||||
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.11.5</a>.</p>
|
||||
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.11.6</a>.</p>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1">
|
||||
<meta name="generator" content="pdoc3 0.11.5">
|
||||
<meta name="generator" content="pdoc3 0.11.6">
|
||||
<title>connpy.cli.profile_handler API documentation</title>
|
||||
<meta name="description" content="">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/13.0.0/sanitize.min.css" integrity="sha512-y1dtMcuvtTMJc1yPgEqF0ZjQbhnc/bFhyvIyVNb9Zk5mIGtqVaAB1Ttl28su8AvFMOY0EwRbAe+HCLqj6W7/KA==" crossorigin>
|
||||
@@ -314,7 +314,7 @@ el.replaceWith(d);
|
||||
</nav>
|
||||
</main>
|
||||
<footer id="footer">
|
||||
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.11.5</a>.</p>
|
||||
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.11.6</a>.</p>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1">
|
||||
<meta name="generator" content="pdoc3 0.11.5">
|
||||
<meta name="generator" content="pdoc3 0.11.6">
|
||||
<title>connpy.cli.run_handler API documentation</title>
|
||||
<meta name="description" content="">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/13.0.0/sanitize.min.css" integrity="sha512-y1dtMcuvtTMJc1yPgEqF0ZjQbhnc/bFhyvIyVNb9Zk5mIGtqVaAB1Ttl28su8AvFMOY0EwRbAe+HCLqj6W7/KA==" crossorigin>
|
||||
@@ -363,7 +363,7 @@ el.replaceWith(d);
|
||||
</nav>
|
||||
</main>
|
||||
<footer id="footer">
|
||||
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.11.5</a>.</p>
|
||||
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.11.6</a>.</p>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1">
|
||||
<meta name="generator" content="pdoc3 0.11.5">
|
||||
<meta name="generator" content="pdoc3 0.11.6">
|
||||
<title>connpy.cli.sync_handler API documentation</title>
|
||||
<meta name="description" content="">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/13.0.0/sanitize.min.css" integrity="sha512-y1dtMcuvtTMJc1yPgEqF0ZjQbhnc/bFhyvIyVNb9Zk5mIGtqVaAB1Ttl28su8AvFMOY0EwRbAe+HCLqj6W7/KA==" crossorigin>
|
||||
@@ -427,7 +427,7 @@ el.replaceWith(d);
|
||||
</nav>
|
||||
</main>
|
||||
<footer id="footer">
|
||||
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.11.5</a>.</p>
|
||||
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.11.6</a>.</p>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1">
|
||||
<meta name="generator" content="pdoc3 0.11.5">
|
||||
<meta name="generator" content="pdoc3 0.11.6">
|
||||
<title>connpy.cli.validators API documentation</title>
|
||||
<meta name="description" content="">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/13.0.0/sanitize.min.css" integrity="sha512-y1dtMcuvtTMJc1yPgEqF0ZjQbhnc/bFhyvIyVNb9Zk5mIGtqVaAB1Ttl28su8AvFMOY0EwRbAe+HCLqj6W7/KA==" crossorigin>
|
||||
@@ -67,14 +67,14 @@ el.replaceWith(d);
|
||||
raise inquirer.errors.ValidationError("", reason="Profile {} don't exist".format(current))
|
||||
return True
|
||||
|
||||
def profile_protocol_validation(self, answers, current, regex = "(^ssh$|^telnet$|^kubectl$|^docker$|^$)"):
|
||||
def profile_protocol_validation(self, answers, current, regex = "(^ssh$|^telnet$|^kubectl$|^docker$|^ssm$|^$)"):
|
||||
if not re.match(regex, current):
|
||||
raise inquirer.errors.ValidationError("", reason="Pick between ssh, telnet, kubectl, docker or leave empty")
|
||||
raise inquirer.errors.ValidationError("", reason="Pick between ssh, telnet, kubectl, docker, ssm or leave empty")
|
||||
return True
|
||||
|
||||
def protocol_validation(self, answers, current, regex = "(^ssh$|^telnet$|^kubectl$|^docker$|^$|^@.+$)"):
|
||||
def protocol_validation(self, answers, current, regex = "(^ssh$|^telnet$|^kubectl$|^docker$|^ssm$|^$|^@.+$)"):
|
||||
if not re.match(regex, current):
|
||||
raise inquirer.errors.ValidationError("", reason="Pick between ssh, telnet, kubectl, docker leave empty or @profile")
|
||||
raise inquirer.errors.ValidationError("", reason="Pick between ssh, telnet, kubectl, docker, ssm, leave empty or @profile")
|
||||
if current.startswith("@"):
|
||||
if current[1:] not in self.app.profiles:
|
||||
raise inquirer.errors.ValidationError("", reason="Profile {} don't exist".format(current))
|
||||
@@ -389,16 +389,16 @@ el.replaceWith(d);
|
||||
<div class="desc"></div>
|
||||
</dd>
|
||||
<dt id="connpy.cli.validators.Validators.profile_protocol_validation"><code class="name flex">
|
||||
<span>def <span class="ident">profile_protocol_validation</span></span>(<span>self, answers, current, regex='(^ssh$|^telnet$|^kubectl$|^docker$|^$)')</span>
|
||||
<span>def <span class="ident">profile_protocol_validation</span></span>(<span>self, answers, current, regex='(^ssh$|^telnet$|^kubectl$|^docker$|^ssm$|^$)')</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def profile_protocol_validation(self, answers, current, regex = "(^ssh$|^telnet$|^kubectl$|^docker$|^$)"):
|
||||
<pre><code class="python">def profile_protocol_validation(self, answers, current, regex = "(^ssh$|^telnet$|^kubectl$|^docker$|^ssm$|^$)"):
|
||||
if not re.match(regex, current):
|
||||
raise inquirer.errors.ValidationError("", reason="Pick between ssh, telnet, kubectl, docker or leave empty")
|
||||
raise inquirer.errors.ValidationError("", reason="Pick between ssh, telnet, kubectl, docker, ssm or leave empty")
|
||||
return True</code></pre>
|
||||
</details>
|
||||
<div class="desc"></div>
|
||||
@@ -425,16 +425,16 @@ el.replaceWith(d);
|
||||
<div class="desc"></div>
|
||||
</dd>
|
||||
<dt id="connpy.cli.validators.Validators.protocol_validation"><code class="name flex">
|
||||
<span>def <span class="ident">protocol_validation</span></span>(<span>self, answers, current, regex='(^ssh$|^telnet$|^kubectl$|^docker$|^$|^@.+$)')</span>
|
||||
<span>def <span class="ident">protocol_validation</span></span>(<span>self,<br>answers,<br>current,<br>regex='(^ssh$|^telnet$|^kubectl$|^docker$|^ssm$|^$|^@.+$)')</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def protocol_validation(self, answers, current, regex = "(^ssh$|^telnet$|^kubectl$|^docker$|^$|^@.+$)"):
|
||||
<pre><code class="python">def protocol_validation(self, answers, current, regex = "(^ssh$|^telnet$|^kubectl$|^docker$|^ssm$|^$|^@.+$)"):
|
||||
if not re.match(regex, current):
|
||||
raise inquirer.errors.ValidationError("", reason="Pick between ssh, telnet, kubectl, docker leave empty or @profile")
|
||||
raise inquirer.errors.ValidationError("", reason="Pick between ssh, telnet, kubectl, docker, ssm, leave empty or @profile")
|
||||
if current.startswith("@"):
|
||||
if current[1:] not in self.app.profiles:
|
||||
raise inquirer.errors.ValidationError("", reason="Profile {} don't exist".format(current))
|
||||
@@ -508,7 +508,7 @@ el.replaceWith(d);
|
||||
</nav>
|
||||
</main>
|
||||
<footer id="footer">
|
||||
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.11.5</a>.</p>
|
||||
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.11.6</a>.</p>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1">
|
||||
<meta name="generator" content="pdoc3 0.11.6">
|
||||
<title>connpy.grpc_layer.connpy_pb2 API documentation</title>
|
||||
<meta name="description" content="Generated protocol buffer code.">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/13.0.0/sanitize.min.css" integrity="sha512-y1dtMcuvtTMJc1yPgEqF0ZjQbhnc/bFhyvIyVNb9Zk5mIGtqVaAB1Ttl28su8AvFMOY0EwRbAe+HCLqj6W7/KA==" crossorigin>
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/13.0.0/typography.min.css" integrity="sha512-Y1DYSb995BAfxobCkKepB1BqJJTPrOp3zPL74AWFugHHmmdcvO+C48WLrUOlhGMc0QG7AE3f7gmvvcrmX2fDoA==" crossorigin>
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/default.min.css" crossorigin>
|
||||
<style>:root{--highlight-color:#fe9}.flex{display:flex !important}body{line-height:1.5em}#content{padding:20px}#sidebar{padding:1.5em;overflow:hidden}#sidebar > *:last-child{margin-bottom:2cm}.http-server-breadcrumbs{font-size:130%;margin:0 0 15px 0}#footer{font-size:.75em;padding:5px 30px;border-top:1px solid #ddd;text-align:right}#footer p{margin:0 0 0 1em;display:inline-block}#footer p:last-child{margin-right:30px}h1,h2,h3,h4,h5{font-weight:300}h1{font-size:2.5em;line-height:1.1em}h2{font-size:1.75em;margin:2em 0 .50em 0}h3{font-size:1.4em;margin:1.6em 0 .7em 0}h4{margin:0;font-size:105%}h1:target,h2:target,h3:target,h4:target,h5:target,h6:target{background:var(--highlight-color);padding:.2em 0}a{color:#058;text-decoration:none;transition:color .2s ease-in-out}a:visited{color:#503}a:hover{color:#b62}.title code{font-weight:bold}h2[id^="header-"]{margin-top:2em}.ident{color:#900;font-weight:bold}pre code{font-size:.8em;line-height:1.4em;padding:1em;display:block}code{background:#f3f3f3;font-family:"DejaVu Sans Mono",monospace;padding:1px 4px;overflow-wrap:break-word}h1 code{background:transparent}pre{border-top:1px solid #ccc;border-bottom:1px solid #ccc;margin:1em 0}#http-server-module-list{display:flex;flex-flow:column}#http-server-module-list div{display:flex}#http-server-module-list dt{min-width:10%}#http-server-module-list p{margin-top:0}.toc ul,#index{list-style-type:none;margin:0;padding:0}#index code{background:transparent}#index h3{border-bottom:1px solid #ddd}#index ul{padding:0}#index h4{margin-top:.6em;font-weight:bold}@media (min-width:200ex){#index .two-column{column-count:2}}@media (min-width:300ex){#index .two-column{column-count:3}}dl{margin-bottom:2em}dl dl:last-child{margin-bottom:4em}dd{margin:0 0 1em 3em}#header-classes + dl > dd{margin-bottom:3em}dd dd{margin-left:2em}dd p{margin:10px 0}.name{background:#eee;font-size:.85em;padding:5px 10px;display:inline-block;min-width:40%}.name:hover{background:#e0e0e0}dt:target .name{background:var(--highlight-color)}.name > span:first-child{white-space:nowrap}.name.class > span:nth-child(2){margin-left:.4em}.inherited{color:#999;border-left:5px solid #eee;padding-left:1em}.inheritance em{font-style:normal;font-weight:bold}.desc h2{font-weight:400;font-size:1.25em}.desc h3{font-size:1em}.desc dt code{background:inherit}.source > summary,.git-link-div{color:#666;text-align:right;font-weight:400;font-size:.8em;text-transform:uppercase}.source summary > *{white-space:nowrap;cursor:pointer}.git-link{color:inherit;margin-left:1em}.source pre{max-height:500px;overflow:auto;margin:0}.source pre code{font-size:12px;overflow:visible;min-width:max-content}.hlist{list-style:none}.hlist li{display:inline}.hlist li:after{content:',\2002'}.hlist li:last-child:after{content:none}.hlist .hlist{display:inline;padding-left:1em}img{max-width:100%}td{padding:0 .5em}.admonition{padding:.1em 1em;margin:1em 0}.admonition-title{font-weight:bold}.admonition.note,.admonition.info,.admonition.important{background:#aef}.admonition.todo,.admonition.versionadded,.admonition.tip,.admonition.hint{background:#dfd}.admonition.warning,.admonition.versionchanged,.admonition.deprecated{background:#fd4}.admonition.error,.admonition.danger,.admonition.caution{background:lightpink}</style>
|
||||
<style media="screen and (min-width: 700px)">@media screen and (min-width:700px){#sidebar{width:30%;height:100vh;overflow:auto;position:sticky;top:0}#content{width:70%;max-width:100ch;padding:3em 4em;border-left:1px solid #ddd}pre code{font-size:1em}.name{font-size:1em}main{display:flex;flex-direction:row-reverse;justify-content:flex-end}.toc ul ul,#index ul ul{padding-left:1em}.toc > ul > li{margin-top:.5em}}</style>
|
||||
<style media="print">@media print{#sidebar h1{page-break-before:always}.source{display:none}}@media print{*{background:transparent !important;color:#000 !important;box-shadow:none !important;text-shadow:none !important}a[href]:after{content:" (" attr(href) ")";font-size:90%}a[href][title]:after{content:none}abbr[title]:after{content:" (" attr(title) ")"}.ir a:after,a[href^="javascript:"]:after,a[href^="#"]:after{content:""}pre,blockquote{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}tr,img{page-break-inside:avoid}img{max-width:100% !important}@page{margin:0.5cm}p,h2,h3{orphans:3;widows:3}h1,h2,h3,h4,h5,h6{page-break-after:avoid}}</style>
|
||||
<script defer src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/highlight.min.js" integrity="sha512-D9gUyxqja7hBtkWpPWGt9wfbfaMGVt9gnyCvYa+jojwwPHLCzUm5i8rpk7vD7wNee9bA35eYIjobYPaQuKS1MQ==" crossorigin></script>
|
||||
<script>window.addEventListener('DOMContentLoaded', () => {
|
||||
hljs.configure({languages: ['bash', 'css', 'diff', 'graphql', 'ini', 'javascript', 'json', 'plaintext', 'python', 'python-repl', 'rust', 'shell', 'sql', 'typescript', 'xml', 'yaml']});
|
||||
hljs.highlightAll();
|
||||
/* Collapse source docstrings */
|
||||
setTimeout(() => {
|
||||
[...document.querySelectorAll('.hljs.language-python > .hljs-string')]
|
||||
.filter(el => el.innerHTML.length > 200 && ['"""', "'''"].includes(el.innerHTML.substring(0, 3)))
|
||||
.forEach(el => {
|
||||
let d = document.createElement('details');
|
||||
d.classList.add('hljs-string');
|
||||
d.innerHTML = '<summary>"""</summary>' + el.innerHTML.substring(3);
|
||||
el.replaceWith(d);
|
||||
});
|
||||
}, 100);
|
||||
})</script>
|
||||
</head>
|
||||
<body>
|
||||
<main>
|
||||
<article id="content">
|
||||
<header>
|
||||
<h1 class="title">Module <code>connpy.grpc_layer.connpy_pb2</code></h1>
|
||||
</header>
|
||||
<section id="section-intro">
|
||||
<p>Generated protocol buffer code.</p>
|
||||
</section>
|
||||
<section>
|
||||
</section>
|
||||
<section>
|
||||
</section>
|
||||
<section>
|
||||
</section>
|
||||
<section>
|
||||
</section>
|
||||
</article>
|
||||
<nav id="sidebar">
|
||||
<div class="toc">
|
||||
<ul></ul>
|
||||
</div>
|
||||
<ul id="index">
|
||||
<li><h3>Super-module</h3>
|
||||
<ul>
|
||||
<li><code><a title="connpy.grpc_layer" href="index.html">connpy.grpc_layer</a></code></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
</main>
|
||||
<footer id="footer">
|
||||
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.11.6</a>.</p>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,108 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1">
|
||||
<meta name="generator" content="pdoc3 0.11.6">
|
||||
<title>connpy.grpc_layer API documentation</title>
|
||||
<meta name="description" content="">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/13.0.0/sanitize.min.css" integrity="sha512-y1dtMcuvtTMJc1yPgEqF0ZjQbhnc/bFhyvIyVNb9Zk5mIGtqVaAB1Ttl28su8AvFMOY0EwRbAe+HCLqj6W7/KA==" crossorigin>
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/13.0.0/typography.min.css" integrity="sha512-Y1DYSb995BAfxobCkKepB1BqJJTPrOp3zPL74AWFugHHmmdcvO+C48WLrUOlhGMc0QG7AE3f7gmvvcrmX2fDoA==" crossorigin>
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/default.min.css" crossorigin>
|
||||
<style>:root{--highlight-color:#fe9}.flex{display:flex !important}body{line-height:1.5em}#content{padding:20px}#sidebar{padding:1.5em;overflow:hidden}#sidebar > *:last-child{margin-bottom:2cm}.http-server-breadcrumbs{font-size:130%;margin:0 0 15px 0}#footer{font-size:.75em;padding:5px 30px;border-top:1px solid #ddd;text-align:right}#footer p{margin:0 0 0 1em;display:inline-block}#footer p:last-child{margin-right:30px}h1,h2,h3,h4,h5{font-weight:300}h1{font-size:2.5em;line-height:1.1em}h2{font-size:1.75em;margin:2em 0 .50em 0}h3{font-size:1.4em;margin:1.6em 0 .7em 0}h4{margin:0;font-size:105%}h1:target,h2:target,h3:target,h4:target,h5:target,h6:target{background:var(--highlight-color);padding:.2em 0}a{color:#058;text-decoration:none;transition:color .2s ease-in-out}a:visited{color:#503}a:hover{color:#b62}.title code{font-weight:bold}h2[id^="header-"]{margin-top:2em}.ident{color:#900;font-weight:bold}pre code{font-size:.8em;line-height:1.4em;padding:1em;display:block}code{background:#f3f3f3;font-family:"DejaVu Sans Mono",monospace;padding:1px 4px;overflow-wrap:break-word}h1 code{background:transparent}pre{border-top:1px solid #ccc;border-bottom:1px solid #ccc;margin:1em 0}#http-server-module-list{display:flex;flex-flow:column}#http-server-module-list div{display:flex}#http-server-module-list dt{min-width:10%}#http-server-module-list p{margin-top:0}.toc ul,#index{list-style-type:none;margin:0;padding:0}#index code{background:transparent}#index h3{border-bottom:1px solid #ddd}#index ul{padding:0}#index h4{margin-top:.6em;font-weight:bold}@media (min-width:200ex){#index .two-column{column-count:2}}@media (min-width:300ex){#index .two-column{column-count:3}}dl{margin-bottom:2em}dl dl:last-child{margin-bottom:4em}dd{margin:0 0 1em 3em}#header-classes + dl > dd{margin-bottom:3em}dd dd{margin-left:2em}dd p{margin:10px 0}.name{background:#eee;font-size:.85em;padding:5px 10px;display:inline-block;min-width:40%}.name:hover{background:#e0e0e0}dt:target .name{background:var(--highlight-color)}.name > span:first-child{white-space:nowrap}.name.class > span:nth-child(2){margin-left:.4em}.inherited{color:#999;border-left:5px solid #eee;padding-left:1em}.inheritance em{font-style:normal;font-weight:bold}.desc h2{font-weight:400;font-size:1.25em}.desc h3{font-size:1em}.desc dt code{background:inherit}.source > summary,.git-link-div{color:#666;text-align:right;font-weight:400;font-size:.8em;text-transform:uppercase}.source summary > *{white-space:nowrap;cursor:pointer}.git-link{color:inherit;margin-left:1em}.source pre{max-height:500px;overflow:auto;margin:0}.source pre code{font-size:12px;overflow:visible;min-width:max-content}.hlist{list-style:none}.hlist li{display:inline}.hlist li:after{content:',\2002'}.hlist li:last-child:after{content:none}.hlist .hlist{display:inline;padding-left:1em}img{max-width:100%}td{padding:0 .5em}.admonition{padding:.1em 1em;margin:1em 0}.admonition-title{font-weight:bold}.admonition.note,.admonition.info,.admonition.important{background:#aef}.admonition.todo,.admonition.versionadded,.admonition.tip,.admonition.hint{background:#dfd}.admonition.warning,.admonition.versionchanged,.admonition.deprecated{background:#fd4}.admonition.error,.admonition.danger,.admonition.caution{background:lightpink}</style>
|
||||
<style media="screen and (min-width: 700px)">@media screen and (min-width:700px){#sidebar{width:30%;height:100vh;overflow:auto;position:sticky;top:0}#content{width:70%;max-width:100ch;padding:3em 4em;border-left:1px solid #ddd}pre code{font-size:1em}.name{font-size:1em}main{display:flex;flex-direction:row-reverse;justify-content:flex-end}.toc ul ul,#index ul ul{padding-left:1em}.toc > ul > li{margin-top:.5em}}</style>
|
||||
<style media="print">@media print{#sidebar h1{page-break-before:always}.source{display:none}}@media print{*{background:transparent !important;color:#000 !important;box-shadow:none !important;text-shadow:none !important}a[href]:after{content:" (" attr(href) ")";font-size:90%}a[href][title]:after{content:none}abbr[title]:after{content:" (" attr(title) ")"}.ir a:after,a[href^="javascript:"]:after,a[href^="#"]:after{content:""}pre,blockquote{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}tr,img{page-break-inside:avoid}img{max-width:100% !important}@page{margin:0.5cm}p,h2,h3{orphans:3;widows:3}h1,h2,h3,h4,h5,h6{page-break-after:avoid}}</style>
|
||||
<script defer src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/highlight.min.js" integrity="sha512-D9gUyxqja7hBtkWpPWGt9wfbfaMGVt9gnyCvYa+jojwwPHLCzUm5i8rpk7vD7wNee9bA35eYIjobYPaQuKS1MQ==" crossorigin></script>
|
||||
<script>window.addEventListener('DOMContentLoaded', () => {
|
||||
hljs.configure({languages: ['bash', 'css', 'diff', 'graphql', 'ini', 'javascript', 'json', 'plaintext', 'python', 'python-repl', 'rust', 'shell', 'sql', 'typescript', 'xml', 'yaml']});
|
||||
hljs.highlightAll();
|
||||
/* Collapse source docstrings */
|
||||
setTimeout(() => {
|
||||
[...document.querySelectorAll('.hljs.language-python > .hljs-string')]
|
||||
.filter(el => el.innerHTML.length > 200 && ['"""', "'''"].includes(el.innerHTML.substring(0, 3)))
|
||||
.forEach(el => {
|
||||
let d = document.createElement('details');
|
||||
d.classList.add('hljs-string');
|
||||
d.innerHTML = '<summary>"""</summary>' + el.innerHTML.substring(3);
|
||||
el.replaceWith(d);
|
||||
});
|
||||
}, 100);
|
||||
})</script>
|
||||
</head>
|
||||
<body>
|
||||
<main>
|
||||
<article id="content">
|
||||
<header>
|
||||
<h1 class="title">Module <code>connpy.grpc_layer</code></h1>
|
||||
</header>
|
||||
<section id="section-intro">
|
||||
</section>
|
||||
<section>
|
||||
<h2 class="section-title" id="header-submodules">Sub-modules</h2>
|
||||
<dl>
|
||||
<dt><code class="name"><a title="connpy.grpc_layer.connpy_pb2" href="connpy_pb2.html">connpy.grpc_layer.connpy_pb2</a></code></dt>
|
||||
<dd>
|
||||
<div class="desc"><p>Generated protocol buffer code.</p></div>
|
||||
</dd>
|
||||
<dt><code class="name"><a title="connpy.grpc_layer.connpy_pb2_grpc" href="connpy_pb2_grpc.html">connpy.grpc_layer.connpy_pb2_grpc</a></code></dt>
|
||||
<dd>
|
||||
<div class="desc"><p>Client and server classes corresponding to protobuf-defined services.</p></div>
|
||||
</dd>
|
||||
<dt><code class="name"><a title="connpy.grpc_layer.remote_plugin_pb2" href="remote_plugin_pb2.html">connpy.grpc_layer.remote_plugin_pb2</a></code></dt>
|
||||
<dd>
|
||||
<div class="desc"><p>Generated protocol buffer code.</p></div>
|
||||
</dd>
|
||||
<dt><code class="name"><a title="connpy.grpc_layer.remote_plugin_pb2_grpc" href="remote_plugin_pb2_grpc.html">connpy.grpc_layer.remote_plugin_pb2_grpc</a></code></dt>
|
||||
<dd>
|
||||
<div class="desc"><p>Client and server classes corresponding to protobuf-defined services.</p></div>
|
||||
</dd>
|
||||
<dt><code class="name"><a title="connpy.grpc_layer.server" href="server.html">connpy.grpc_layer.server</a></code></dt>
|
||||
<dd>
|
||||
<div class="desc"></div>
|
||||
</dd>
|
||||
<dt><code class="name"><a title="connpy.grpc_layer.stubs" href="stubs.html">connpy.grpc_layer.stubs</a></code></dt>
|
||||
<dd>
|
||||
<div class="desc"></div>
|
||||
</dd>
|
||||
<dt><code class="name"><a title="connpy.grpc_layer.utils" href="utils.html">connpy.grpc_layer.utils</a></code></dt>
|
||||
<dd>
|
||||
<div class="desc"></div>
|
||||
</dd>
|
||||
</dl>
|
||||
</section>
|
||||
<section>
|
||||
</section>
|
||||
<section>
|
||||
</section>
|
||||
<section>
|
||||
</section>
|
||||
</article>
|
||||
<nav id="sidebar">
|
||||
<div class="toc">
|
||||
<ul></ul>
|
||||
</div>
|
||||
<ul id="index">
|
||||
<li><h3>Super-module</h3>
|
||||
<ul>
|
||||
<li><code><a title="connpy" href="../index.html">connpy</a></code></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><h3><a href="#header-submodules">Sub-modules</a></h3>
|
||||
<ul>
|
||||
<li><code><a title="connpy.grpc_layer.connpy_pb2" href="connpy_pb2.html">connpy.grpc_layer.connpy_pb2</a></code></li>
|
||||
<li><code><a title="connpy.grpc_layer.connpy_pb2_grpc" href="connpy_pb2_grpc.html">connpy.grpc_layer.connpy_pb2_grpc</a></code></li>
|
||||
<li><code><a title="connpy.grpc_layer.remote_plugin_pb2" href="remote_plugin_pb2.html">connpy.grpc_layer.remote_plugin_pb2</a></code></li>
|
||||
<li><code><a title="connpy.grpc_layer.remote_plugin_pb2_grpc" href="remote_plugin_pb2_grpc.html">connpy.grpc_layer.remote_plugin_pb2_grpc</a></code></li>
|
||||
<li><code><a title="connpy.grpc_layer.server" href="server.html">connpy.grpc_layer.server</a></code></li>
|
||||
<li><code><a title="connpy.grpc_layer.stubs" href="stubs.html">connpy.grpc_layer.stubs</a></code></li>
|
||||
<li><code><a title="connpy.grpc_layer.utils" href="utils.html">connpy.grpc_layer.utils</a></code></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
</main>
|
||||
<footer id="footer">
|
||||
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.11.6</a>.</p>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,174 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1">
|
||||
<meta name="generator" content="pdoc3 0.11.6">
|
||||
<title>connpy.grpc_layer.remote_plugin_pb2 API documentation</title>
|
||||
<meta name="description" content="Generated protocol buffer code.">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/13.0.0/sanitize.min.css" integrity="sha512-y1dtMcuvtTMJc1yPgEqF0ZjQbhnc/bFhyvIyVNb9Zk5mIGtqVaAB1Ttl28su8AvFMOY0EwRbAe+HCLqj6W7/KA==" crossorigin>
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/13.0.0/typography.min.css" integrity="sha512-Y1DYSb995BAfxobCkKepB1BqJJTPrOp3zPL74AWFugHHmmdcvO+C48WLrUOlhGMc0QG7AE3f7gmvvcrmX2fDoA==" crossorigin>
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/default.min.css" crossorigin>
|
||||
<style>:root{--highlight-color:#fe9}.flex{display:flex !important}body{line-height:1.5em}#content{padding:20px}#sidebar{padding:1.5em;overflow:hidden}#sidebar > *:last-child{margin-bottom:2cm}.http-server-breadcrumbs{font-size:130%;margin:0 0 15px 0}#footer{font-size:.75em;padding:5px 30px;border-top:1px solid #ddd;text-align:right}#footer p{margin:0 0 0 1em;display:inline-block}#footer p:last-child{margin-right:30px}h1,h2,h3,h4,h5{font-weight:300}h1{font-size:2.5em;line-height:1.1em}h2{font-size:1.75em;margin:2em 0 .50em 0}h3{font-size:1.4em;margin:1.6em 0 .7em 0}h4{margin:0;font-size:105%}h1:target,h2:target,h3:target,h4:target,h5:target,h6:target{background:var(--highlight-color);padding:.2em 0}a{color:#058;text-decoration:none;transition:color .2s ease-in-out}a:visited{color:#503}a:hover{color:#b62}.title code{font-weight:bold}h2[id^="header-"]{margin-top:2em}.ident{color:#900;font-weight:bold}pre code{font-size:.8em;line-height:1.4em;padding:1em;display:block}code{background:#f3f3f3;font-family:"DejaVu Sans Mono",monospace;padding:1px 4px;overflow-wrap:break-word}h1 code{background:transparent}pre{border-top:1px solid #ccc;border-bottom:1px solid #ccc;margin:1em 0}#http-server-module-list{display:flex;flex-flow:column}#http-server-module-list div{display:flex}#http-server-module-list dt{min-width:10%}#http-server-module-list p{margin-top:0}.toc ul,#index{list-style-type:none;margin:0;padding:0}#index code{background:transparent}#index h3{border-bottom:1px solid #ddd}#index ul{padding:0}#index h4{margin-top:.6em;font-weight:bold}@media (min-width:200ex){#index .two-column{column-count:2}}@media (min-width:300ex){#index .two-column{column-count:3}}dl{margin-bottom:2em}dl dl:last-child{margin-bottom:4em}dd{margin:0 0 1em 3em}#header-classes + dl > dd{margin-bottom:3em}dd dd{margin-left:2em}dd p{margin:10px 0}.name{background:#eee;font-size:.85em;padding:5px 10px;display:inline-block;min-width:40%}.name:hover{background:#e0e0e0}dt:target .name{background:var(--highlight-color)}.name > span:first-child{white-space:nowrap}.name.class > span:nth-child(2){margin-left:.4em}.inherited{color:#999;border-left:5px solid #eee;padding-left:1em}.inheritance em{font-style:normal;font-weight:bold}.desc h2{font-weight:400;font-size:1.25em}.desc h3{font-size:1em}.desc dt code{background:inherit}.source > summary,.git-link-div{color:#666;text-align:right;font-weight:400;font-size:.8em;text-transform:uppercase}.source summary > *{white-space:nowrap;cursor:pointer}.git-link{color:inherit;margin-left:1em}.source pre{max-height:500px;overflow:auto;margin:0}.source pre code{font-size:12px;overflow:visible;min-width:max-content}.hlist{list-style:none}.hlist li{display:inline}.hlist li:after{content:',\2002'}.hlist li:last-child:after{content:none}.hlist .hlist{display:inline;padding-left:1em}img{max-width:100%}td{padding:0 .5em}.admonition{padding:.1em 1em;margin:1em 0}.admonition-title{font-weight:bold}.admonition.note,.admonition.info,.admonition.important{background:#aef}.admonition.todo,.admonition.versionadded,.admonition.tip,.admonition.hint{background:#dfd}.admonition.warning,.admonition.versionchanged,.admonition.deprecated{background:#fd4}.admonition.error,.admonition.danger,.admonition.caution{background:lightpink}</style>
|
||||
<style media="screen and (min-width: 700px)">@media screen and (min-width:700px){#sidebar{width:30%;height:100vh;overflow:auto;position:sticky;top:0}#content{width:70%;max-width:100ch;padding:3em 4em;border-left:1px solid #ddd}pre code{font-size:1em}.name{font-size:1em}main{display:flex;flex-direction:row-reverse;justify-content:flex-end}.toc ul ul,#index ul ul{padding-left:1em}.toc > ul > li{margin-top:.5em}}</style>
|
||||
<style media="print">@media print{#sidebar h1{page-break-before:always}.source{display:none}}@media print{*{background:transparent !important;color:#000 !important;box-shadow:none !important;text-shadow:none !important}a[href]:after{content:" (" attr(href) ")";font-size:90%}a[href][title]:after{content:none}abbr[title]:after{content:" (" attr(title) ")"}.ir a:after,a[href^="javascript:"]:after,a[href^="#"]:after{content:""}pre,blockquote{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}tr,img{page-break-inside:avoid}img{max-width:100% !important}@page{margin:0.5cm}p,h2,h3{orphans:3;widows:3}h1,h2,h3,h4,h5,h6{page-break-after:avoid}}</style>
|
||||
<script defer src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/highlight.min.js" integrity="sha512-D9gUyxqja7hBtkWpPWGt9wfbfaMGVt9gnyCvYa+jojwwPHLCzUm5i8rpk7vD7wNee9bA35eYIjobYPaQuKS1MQ==" crossorigin></script>
|
||||
<script>window.addEventListener('DOMContentLoaded', () => {
|
||||
hljs.configure({languages: ['bash', 'css', 'diff', 'graphql', 'ini', 'javascript', 'json', 'plaintext', 'python', 'python-repl', 'rust', 'shell', 'sql', 'typescript', 'xml', 'yaml']});
|
||||
hljs.highlightAll();
|
||||
/* Collapse source docstrings */
|
||||
setTimeout(() => {
|
||||
[...document.querySelectorAll('.hljs.language-python > .hljs-string')]
|
||||
.filter(el => el.innerHTML.length > 200 && ['"""', "'''"].includes(el.innerHTML.substring(0, 3)))
|
||||
.forEach(el => {
|
||||
let d = document.createElement('details');
|
||||
d.classList.add('hljs-string');
|
||||
d.innerHTML = '<summary>"""</summary>' + el.innerHTML.substring(3);
|
||||
el.replaceWith(d);
|
||||
});
|
||||
}, 100);
|
||||
})</script>
|
||||
</head>
|
||||
<body>
|
||||
<main>
|
||||
<article id="content">
|
||||
<header>
|
||||
<h1 class="title">Module <code>connpy.grpc_layer.remote_plugin_pb2</code></h1>
|
||||
</header>
|
||||
<section id="section-intro">
|
||||
<p>Generated protocol buffer code.</p>
|
||||
</section>
|
||||
<section>
|
||||
</section>
|
||||
<section>
|
||||
</section>
|
||||
<section>
|
||||
</section>
|
||||
<section>
|
||||
<h2 class="section-title" id="header-classes">Classes</h2>
|
||||
<dl>
|
||||
<dt id="connpy.grpc_layer.remote_plugin_pb2.IdRequest"><code class="flex name class">
|
||||
<span>class <span class="ident">IdRequest</span></span>
|
||||
<span>(</span><span>*args, **kwargs)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<div class="desc"><p>A ProtocolMessage</p></div>
|
||||
<h3>Ancestors</h3>
|
||||
<ul class="hlist">
|
||||
<li>google._upb._message.Message</li>
|
||||
<li>google.protobuf.message.Message</li>
|
||||
</ul>
|
||||
<h3>Class variables</h3>
|
||||
<dl>
|
||||
<dt id="connpy.grpc_layer.remote_plugin_pb2.IdRequest.DESCRIPTOR"><code class="name">var <span class="ident">DESCRIPTOR</span></code></dt>
|
||||
<dd>
|
||||
<div class="desc"><p>The type of the None singleton.</p></div>
|
||||
</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
<dt id="connpy.grpc_layer.remote_plugin_pb2.OutputChunk"><code class="flex name class">
|
||||
<span>class <span class="ident">OutputChunk</span></span>
|
||||
<span>(</span><span>*args, **kwargs)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<div class="desc"><p>A ProtocolMessage</p></div>
|
||||
<h3>Ancestors</h3>
|
||||
<ul class="hlist">
|
||||
<li>google._upb._message.Message</li>
|
||||
<li>google.protobuf.message.Message</li>
|
||||
</ul>
|
||||
<h3>Class variables</h3>
|
||||
<dl>
|
||||
<dt id="connpy.grpc_layer.remote_plugin_pb2.OutputChunk.DESCRIPTOR"><code class="name">var <span class="ident">DESCRIPTOR</span></code></dt>
|
||||
<dd>
|
||||
<div class="desc"><p>The type of the None singleton.</p></div>
|
||||
</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
<dt id="connpy.grpc_layer.remote_plugin_pb2.PluginInvokeRequest"><code class="flex name class">
|
||||
<span>class <span class="ident">PluginInvokeRequest</span></span>
|
||||
<span>(</span><span>*args, **kwargs)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<div class="desc"><p>A ProtocolMessage</p></div>
|
||||
<h3>Ancestors</h3>
|
||||
<ul class="hlist">
|
||||
<li>google._upb._message.Message</li>
|
||||
<li>google.protobuf.message.Message</li>
|
||||
</ul>
|
||||
<h3>Class variables</h3>
|
||||
<dl>
|
||||
<dt id="connpy.grpc_layer.remote_plugin_pb2.PluginInvokeRequest.DESCRIPTOR"><code class="name">var <span class="ident">DESCRIPTOR</span></code></dt>
|
||||
<dd>
|
||||
<div class="desc"><p>The type of the None singleton.</p></div>
|
||||
</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
<dt id="connpy.grpc_layer.remote_plugin_pb2.StringResponse"><code class="flex name class">
|
||||
<span>class <span class="ident">StringResponse</span></span>
|
||||
<span>(</span><span>*args, **kwargs)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<div class="desc"><p>A ProtocolMessage</p></div>
|
||||
<h3>Ancestors</h3>
|
||||
<ul class="hlist">
|
||||
<li>google._upb._message.Message</li>
|
||||
<li>google.protobuf.message.Message</li>
|
||||
</ul>
|
||||
<h3>Class variables</h3>
|
||||
<dl>
|
||||
<dt id="connpy.grpc_layer.remote_plugin_pb2.StringResponse.DESCRIPTOR"><code class="name">var <span class="ident">DESCRIPTOR</span></code></dt>
|
||||
<dd>
|
||||
<div class="desc"><p>The type of the None singleton.</p></div>
|
||||
</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
</dl>
|
||||
</section>
|
||||
</article>
|
||||
<nav id="sidebar">
|
||||
<div class="toc">
|
||||
<ul></ul>
|
||||
</div>
|
||||
<ul id="index">
|
||||
<li><h3>Super-module</h3>
|
||||
<ul>
|
||||
<li><code><a title="connpy.grpc_layer" href="index.html">connpy.grpc_layer</a></code></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><h3><a href="#header-classes">Classes</a></h3>
|
||||
<ul>
|
||||
<li>
|
||||
<h4><code><a title="connpy.grpc_layer.remote_plugin_pb2.IdRequest" href="#connpy.grpc_layer.remote_plugin_pb2.IdRequest">IdRequest</a></code></h4>
|
||||
<ul class="">
|
||||
<li><code><a title="connpy.grpc_layer.remote_plugin_pb2.IdRequest.DESCRIPTOR" href="#connpy.grpc_layer.remote_plugin_pb2.IdRequest.DESCRIPTOR">DESCRIPTOR</a></code></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>
|
||||
<h4><code><a title="connpy.grpc_layer.remote_plugin_pb2.OutputChunk" href="#connpy.grpc_layer.remote_plugin_pb2.OutputChunk">OutputChunk</a></code></h4>
|
||||
<ul class="">
|
||||
<li><code><a title="connpy.grpc_layer.remote_plugin_pb2.OutputChunk.DESCRIPTOR" href="#connpy.grpc_layer.remote_plugin_pb2.OutputChunk.DESCRIPTOR">DESCRIPTOR</a></code></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>
|
||||
<h4><code><a title="connpy.grpc_layer.remote_plugin_pb2.PluginInvokeRequest" href="#connpy.grpc_layer.remote_plugin_pb2.PluginInvokeRequest">PluginInvokeRequest</a></code></h4>
|
||||
<ul class="">
|
||||
<li><code><a title="connpy.grpc_layer.remote_plugin_pb2.PluginInvokeRequest.DESCRIPTOR" href="#connpy.grpc_layer.remote_plugin_pb2.PluginInvokeRequest.DESCRIPTOR">DESCRIPTOR</a></code></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>
|
||||
<h4><code><a title="connpy.grpc_layer.remote_plugin_pb2.StringResponse" href="#connpy.grpc_layer.remote_plugin_pb2.StringResponse">StringResponse</a></code></h4>
|
||||
<ul class="">
|
||||
<li><code><a title="connpy.grpc_layer.remote_plugin_pb2.StringResponse.DESCRIPTOR" href="#connpy.grpc_layer.remote_plugin_pb2.StringResponse.DESCRIPTOR">DESCRIPTOR</a></code></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
</main>
|
||||
<footer id="footer">
|
||||
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.11.6</a>.</p>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,372 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1">
|
||||
<meta name="generator" content="pdoc3 0.11.6">
|
||||
<title>connpy.grpc_layer.remote_plugin_pb2_grpc API documentation</title>
|
||||
<meta name="description" content="Client and server classes corresponding to protobuf-defined services.">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/13.0.0/sanitize.min.css" integrity="sha512-y1dtMcuvtTMJc1yPgEqF0ZjQbhnc/bFhyvIyVNb9Zk5mIGtqVaAB1Ttl28su8AvFMOY0EwRbAe+HCLqj6W7/KA==" crossorigin>
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/13.0.0/typography.min.css" integrity="sha512-Y1DYSb995BAfxobCkKepB1BqJJTPrOp3zPL74AWFugHHmmdcvO+C48WLrUOlhGMc0QG7AE3f7gmvvcrmX2fDoA==" crossorigin>
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/default.min.css" crossorigin>
|
||||
<style>:root{--highlight-color:#fe9}.flex{display:flex !important}body{line-height:1.5em}#content{padding:20px}#sidebar{padding:1.5em;overflow:hidden}#sidebar > *:last-child{margin-bottom:2cm}.http-server-breadcrumbs{font-size:130%;margin:0 0 15px 0}#footer{font-size:.75em;padding:5px 30px;border-top:1px solid #ddd;text-align:right}#footer p{margin:0 0 0 1em;display:inline-block}#footer p:last-child{margin-right:30px}h1,h2,h3,h4,h5{font-weight:300}h1{font-size:2.5em;line-height:1.1em}h2{font-size:1.75em;margin:2em 0 .50em 0}h3{font-size:1.4em;margin:1.6em 0 .7em 0}h4{margin:0;font-size:105%}h1:target,h2:target,h3:target,h4:target,h5:target,h6:target{background:var(--highlight-color);padding:.2em 0}a{color:#058;text-decoration:none;transition:color .2s ease-in-out}a:visited{color:#503}a:hover{color:#b62}.title code{font-weight:bold}h2[id^="header-"]{margin-top:2em}.ident{color:#900;font-weight:bold}pre code{font-size:.8em;line-height:1.4em;padding:1em;display:block}code{background:#f3f3f3;font-family:"DejaVu Sans Mono",monospace;padding:1px 4px;overflow-wrap:break-word}h1 code{background:transparent}pre{border-top:1px solid #ccc;border-bottom:1px solid #ccc;margin:1em 0}#http-server-module-list{display:flex;flex-flow:column}#http-server-module-list div{display:flex}#http-server-module-list dt{min-width:10%}#http-server-module-list p{margin-top:0}.toc ul,#index{list-style-type:none;margin:0;padding:0}#index code{background:transparent}#index h3{border-bottom:1px solid #ddd}#index ul{padding:0}#index h4{margin-top:.6em;font-weight:bold}@media (min-width:200ex){#index .two-column{column-count:2}}@media (min-width:300ex){#index .two-column{column-count:3}}dl{margin-bottom:2em}dl dl:last-child{margin-bottom:4em}dd{margin:0 0 1em 3em}#header-classes + dl > dd{margin-bottom:3em}dd dd{margin-left:2em}dd p{margin:10px 0}.name{background:#eee;font-size:.85em;padding:5px 10px;display:inline-block;min-width:40%}.name:hover{background:#e0e0e0}dt:target .name{background:var(--highlight-color)}.name > span:first-child{white-space:nowrap}.name.class > span:nth-child(2){margin-left:.4em}.inherited{color:#999;border-left:5px solid #eee;padding-left:1em}.inheritance em{font-style:normal;font-weight:bold}.desc h2{font-weight:400;font-size:1.25em}.desc h3{font-size:1em}.desc dt code{background:inherit}.source > summary,.git-link-div{color:#666;text-align:right;font-weight:400;font-size:.8em;text-transform:uppercase}.source summary > *{white-space:nowrap;cursor:pointer}.git-link{color:inherit;margin-left:1em}.source pre{max-height:500px;overflow:auto;margin:0}.source pre code{font-size:12px;overflow:visible;min-width:max-content}.hlist{list-style:none}.hlist li{display:inline}.hlist li:after{content:',\2002'}.hlist li:last-child:after{content:none}.hlist .hlist{display:inline;padding-left:1em}img{max-width:100%}td{padding:0 .5em}.admonition{padding:.1em 1em;margin:1em 0}.admonition-title{font-weight:bold}.admonition.note,.admonition.info,.admonition.important{background:#aef}.admonition.todo,.admonition.versionadded,.admonition.tip,.admonition.hint{background:#dfd}.admonition.warning,.admonition.versionchanged,.admonition.deprecated{background:#fd4}.admonition.error,.admonition.danger,.admonition.caution{background:lightpink}</style>
|
||||
<style media="screen and (min-width: 700px)">@media screen and (min-width:700px){#sidebar{width:30%;height:100vh;overflow:auto;position:sticky;top:0}#content{width:70%;max-width:100ch;padding:3em 4em;border-left:1px solid #ddd}pre code{font-size:1em}.name{font-size:1em}main{display:flex;flex-direction:row-reverse;justify-content:flex-end}.toc ul ul,#index ul ul{padding-left:1em}.toc > ul > li{margin-top:.5em}}</style>
|
||||
<style media="print">@media print{#sidebar h1{page-break-before:always}.source{display:none}}@media print{*{background:transparent !important;color:#000 !important;box-shadow:none !important;text-shadow:none !important}a[href]:after{content:" (" attr(href) ")";font-size:90%}a[href][title]:after{content:none}abbr[title]:after{content:" (" attr(title) ")"}.ir a:after,a[href^="javascript:"]:after,a[href^="#"]:after{content:""}pre,blockquote{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}tr,img{page-break-inside:avoid}img{max-width:100% !important}@page{margin:0.5cm}p,h2,h3{orphans:3;widows:3}h1,h2,h3,h4,h5,h6{page-break-after:avoid}}</style>
|
||||
<script defer src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/highlight.min.js" integrity="sha512-D9gUyxqja7hBtkWpPWGt9wfbfaMGVt9gnyCvYa+jojwwPHLCzUm5i8rpk7vD7wNee9bA35eYIjobYPaQuKS1MQ==" crossorigin></script>
|
||||
<script>window.addEventListener('DOMContentLoaded', () => {
|
||||
hljs.configure({languages: ['bash', 'css', 'diff', 'graphql', 'ini', 'javascript', 'json', 'plaintext', 'python', 'python-repl', 'rust', 'shell', 'sql', 'typescript', 'xml', 'yaml']});
|
||||
hljs.highlightAll();
|
||||
/* Collapse source docstrings */
|
||||
setTimeout(() => {
|
||||
[...document.querySelectorAll('.hljs.language-python > .hljs-string')]
|
||||
.filter(el => el.innerHTML.length > 200 && ['"""', "'''"].includes(el.innerHTML.substring(0, 3)))
|
||||
.forEach(el => {
|
||||
let d = document.createElement('details');
|
||||
d.classList.add('hljs-string');
|
||||
d.innerHTML = '<summary>"""</summary>' + el.innerHTML.substring(3);
|
||||
el.replaceWith(d);
|
||||
});
|
||||
}, 100);
|
||||
})</script>
|
||||
</head>
|
||||
<body>
|
||||
<main>
|
||||
<article id="content">
|
||||
<header>
|
||||
<h1 class="title">Module <code>connpy.grpc_layer.remote_plugin_pb2_grpc</code></h1>
|
||||
</header>
|
||||
<section id="section-intro">
|
||||
<p>Client and server classes corresponding to protobuf-defined services.</p>
|
||||
</section>
|
||||
<section>
|
||||
</section>
|
||||
<section>
|
||||
</section>
|
||||
<section>
|
||||
<h2 class="section-title" id="header-functions">Functions</h2>
|
||||
<dl>
|
||||
<dt id="connpy.grpc_layer.remote_plugin_pb2_grpc.add_RemotePluginServiceServicer_to_server"><code class="name flex">
|
||||
<span>def <span class="ident">add_RemotePluginServiceServicer_to_server</span></span>(<span>servicer, server)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def add_RemotePluginServiceServicer_to_server(servicer, server):
|
||||
rpc_method_handlers = {
|
||||
'get_plugin_source': grpc.unary_unary_rpc_method_handler(
|
||||
servicer.get_plugin_source,
|
||||
request_deserializer=remote__plugin__pb2.IdRequest.FromString,
|
||||
response_serializer=remote__plugin__pb2.StringResponse.SerializeToString,
|
||||
),
|
||||
'invoke_plugin': grpc.unary_stream_rpc_method_handler(
|
||||
servicer.invoke_plugin,
|
||||
request_deserializer=remote__plugin__pb2.PluginInvokeRequest.FromString,
|
||||
response_serializer=remote__plugin__pb2.OutputChunk.SerializeToString,
|
||||
),
|
||||
}
|
||||
generic_handler = grpc.method_handlers_generic_handler(
|
||||
'connpy_remote.RemotePluginService', rpc_method_handlers)
|
||||
server.add_generic_rpc_handlers((generic_handler,))
|
||||
server.add_registered_method_handlers('connpy_remote.RemotePluginService', rpc_method_handlers)</code></pre>
|
||||
</details>
|
||||
<div class="desc"></div>
|
||||
</dd>
|
||||
</dl>
|
||||
</section>
|
||||
<section>
|
||||
<h2 class="section-title" id="header-classes">Classes</h2>
|
||||
<dl>
|
||||
<dt id="connpy.grpc_layer.remote_plugin_pb2_grpc.RemotePluginService"><code class="flex name class">
|
||||
<span>class <span class="ident">RemotePluginService</span></span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">class RemotePluginService(object):
|
||||
"""Missing associated documentation comment in .proto file."""
|
||||
|
||||
@staticmethod
|
||||
def get_plugin_source(request,
|
||||
target,
|
||||
options=(),
|
||||
channel_credentials=None,
|
||||
call_credentials=None,
|
||||
insecure=False,
|
||||
compression=None,
|
||||
wait_for_ready=None,
|
||||
timeout=None,
|
||||
metadata=None):
|
||||
return grpc.experimental.unary_unary(
|
||||
request,
|
||||
target,
|
||||
'/connpy_remote.RemotePluginService/get_plugin_source',
|
||||
remote__plugin__pb2.IdRequest.SerializeToString,
|
||||
remote__plugin__pb2.StringResponse.FromString,
|
||||
options,
|
||||
channel_credentials,
|
||||
insecure,
|
||||
call_credentials,
|
||||
compression,
|
||||
wait_for_ready,
|
||||
timeout,
|
||||
metadata,
|
||||
_registered_method=True)
|
||||
|
||||
@staticmethod
|
||||
def invoke_plugin(request,
|
||||
target,
|
||||
options=(),
|
||||
channel_credentials=None,
|
||||
call_credentials=None,
|
||||
insecure=False,
|
||||
compression=None,
|
||||
wait_for_ready=None,
|
||||
timeout=None,
|
||||
metadata=None):
|
||||
return grpc.experimental.unary_stream(
|
||||
request,
|
||||
target,
|
||||
'/connpy_remote.RemotePluginService/invoke_plugin',
|
||||
remote__plugin__pb2.PluginInvokeRequest.SerializeToString,
|
||||
remote__plugin__pb2.OutputChunk.FromString,
|
||||
options,
|
||||
channel_credentials,
|
||||
insecure,
|
||||
call_credentials,
|
||||
compression,
|
||||
wait_for_ready,
|
||||
timeout,
|
||||
metadata,
|
||||
_registered_method=True)</code></pre>
|
||||
</details>
|
||||
<div class="desc"><p>Missing associated documentation comment in .proto file.</p></div>
|
||||
<h3>Static methods</h3>
|
||||
<dl>
|
||||
<dt id="connpy.grpc_layer.remote_plugin_pb2_grpc.RemotePluginService.get_plugin_source"><code class="name flex">
|
||||
<span>def <span class="ident">get_plugin_source</span></span>(<span>request,<br>target,<br>options=(),<br>channel_credentials=None,<br>call_credentials=None,<br>insecure=False,<br>compression=None,<br>wait_for_ready=None,<br>timeout=None,<br>metadata=None)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">@staticmethod
|
||||
def get_plugin_source(request,
|
||||
target,
|
||||
options=(),
|
||||
channel_credentials=None,
|
||||
call_credentials=None,
|
||||
insecure=False,
|
||||
compression=None,
|
||||
wait_for_ready=None,
|
||||
timeout=None,
|
||||
metadata=None):
|
||||
return grpc.experimental.unary_unary(
|
||||
request,
|
||||
target,
|
||||
'/connpy_remote.RemotePluginService/get_plugin_source',
|
||||
remote__plugin__pb2.IdRequest.SerializeToString,
|
||||
remote__plugin__pb2.StringResponse.FromString,
|
||||
options,
|
||||
channel_credentials,
|
||||
insecure,
|
||||
call_credentials,
|
||||
compression,
|
||||
wait_for_ready,
|
||||
timeout,
|
||||
metadata,
|
||||
_registered_method=True)</code></pre>
|
||||
</details>
|
||||
<div class="desc"></div>
|
||||
</dd>
|
||||
<dt id="connpy.grpc_layer.remote_plugin_pb2_grpc.RemotePluginService.invoke_plugin"><code class="name flex">
|
||||
<span>def <span class="ident">invoke_plugin</span></span>(<span>request,<br>target,<br>options=(),<br>channel_credentials=None,<br>call_credentials=None,<br>insecure=False,<br>compression=None,<br>wait_for_ready=None,<br>timeout=None,<br>metadata=None)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">@staticmethod
|
||||
def invoke_plugin(request,
|
||||
target,
|
||||
options=(),
|
||||
channel_credentials=None,
|
||||
call_credentials=None,
|
||||
insecure=False,
|
||||
compression=None,
|
||||
wait_for_ready=None,
|
||||
timeout=None,
|
||||
metadata=None):
|
||||
return grpc.experimental.unary_stream(
|
||||
request,
|
||||
target,
|
||||
'/connpy_remote.RemotePluginService/invoke_plugin',
|
||||
remote__plugin__pb2.PluginInvokeRequest.SerializeToString,
|
||||
remote__plugin__pb2.OutputChunk.FromString,
|
||||
options,
|
||||
channel_credentials,
|
||||
insecure,
|
||||
call_credentials,
|
||||
compression,
|
||||
wait_for_ready,
|
||||
timeout,
|
||||
metadata,
|
||||
_registered_method=True)</code></pre>
|
||||
</details>
|
||||
<div class="desc"></div>
|
||||
</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
<dt id="connpy.grpc_layer.remote_plugin_pb2_grpc.RemotePluginServiceServicer"><code class="flex name class">
|
||||
<span>class <span class="ident">RemotePluginServiceServicer</span></span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">class RemotePluginServiceServicer(object):
|
||||
"""Missing associated documentation comment in .proto file."""
|
||||
|
||||
def get_plugin_source(self, request, context):
|
||||
"""Missing associated documentation comment in .proto file."""
|
||||
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
|
||||
context.set_details('Method not implemented!')
|
||||
raise NotImplementedError('Method not implemented!')
|
||||
|
||||
def invoke_plugin(self, request, context):
|
||||
"""Missing associated documentation comment in .proto file."""
|
||||
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
|
||||
context.set_details('Method not implemented!')
|
||||
raise NotImplementedError('Method not implemented!')</code></pre>
|
||||
</details>
|
||||
<div class="desc"><p>Missing associated documentation comment in .proto file.</p></div>
|
||||
<h3>Subclasses</h3>
|
||||
<ul class="hlist">
|
||||
<li><a title="connpy.grpc_layer.server.PluginServicer" href="server.html#connpy.grpc_layer.server.PluginServicer">PluginServicer</a></li>
|
||||
</ul>
|
||||
<h3>Methods</h3>
|
||||
<dl>
|
||||
<dt id="connpy.grpc_layer.remote_plugin_pb2_grpc.RemotePluginServiceServicer.get_plugin_source"><code class="name flex">
|
||||
<span>def <span class="ident">get_plugin_source</span></span>(<span>self, request, context)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def get_plugin_source(self, request, context):
|
||||
"""Missing associated documentation comment in .proto file."""
|
||||
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
|
||||
context.set_details('Method not implemented!')
|
||||
raise NotImplementedError('Method not implemented!')</code></pre>
|
||||
</details>
|
||||
<div class="desc"><p>Missing associated documentation comment in .proto file.</p></div>
|
||||
</dd>
|
||||
<dt id="connpy.grpc_layer.remote_plugin_pb2_grpc.RemotePluginServiceServicer.invoke_plugin"><code class="name flex">
|
||||
<span>def <span class="ident">invoke_plugin</span></span>(<span>self, request, context)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def invoke_plugin(self, request, context):
|
||||
"""Missing associated documentation comment in .proto file."""
|
||||
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
|
||||
context.set_details('Method not implemented!')
|
||||
raise NotImplementedError('Method not implemented!')</code></pre>
|
||||
</details>
|
||||
<div class="desc"><p>Missing associated documentation comment in .proto file.</p></div>
|
||||
</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
<dt id="connpy.grpc_layer.remote_plugin_pb2_grpc.RemotePluginServiceStub"><code class="flex name class">
|
||||
<span>class <span class="ident">RemotePluginServiceStub</span></span>
|
||||
<span>(</span><span>channel)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">class RemotePluginServiceStub(object):
|
||||
"""Missing associated documentation comment in .proto file."""
|
||||
|
||||
def __init__(self, channel):
|
||||
"""Constructor.
|
||||
|
||||
Args:
|
||||
channel: A grpc.Channel.
|
||||
"""
|
||||
self.get_plugin_source = channel.unary_unary(
|
||||
'/connpy_remote.RemotePluginService/get_plugin_source',
|
||||
request_serializer=remote__plugin__pb2.IdRequest.SerializeToString,
|
||||
response_deserializer=remote__plugin__pb2.StringResponse.FromString,
|
||||
_registered_method=True)
|
||||
self.invoke_plugin = channel.unary_stream(
|
||||
'/connpy_remote.RemotePluginService/invoke_plugin',
|
||||
request_serializer=remote__plugin__pb2.PluginInvokeRequest.SerializeToString,
|
||||
response_deserializer=remote__plugin__pb2.OutputChunk.FromString,
|
||||
_registered_method=True)</code></pre>
|
||||
</details>
|
||||
<div class="desc"><p>Missing associated documentation comment in .proto file.</p>
|
||||
<p>Constructor.</p>
|
||||
<h2 id="args">Args</h2>
|
||||
<dl>
|
||||
<dt><strong><code>channel</code></strong></dt>
|
||||
<dd>A grpc.Channel.</dd>
|
||||
</dl></div>
|
||||
</dd>
|
||||
</dl>
|
||||
</section>
|
||||
</article>
|
||||
<nav id="sidebar">
|
||||
<div class="toc">
|
||||
<ul></ul>
|
||||
</div>
|
||||
<ul id="index">
|
||||
<li><h3>Super-module</h3>
|
||||
<ul>
|
||||
<li><code><a title="connpy.grpc_layer" href="index.html">connpy.grpc_layer</a></code></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><h3><a href="#header-functions">Functions</a></h3>
|
||||
<ul class="">
|
||||
<li><code><a title="connpy.grpc_layer.remote_plugin_pb2_grpc.add_RemotePluginServiceServicer_to_server" href="#connpy.grpc_layer.remote_plugin_pb2_grpc.add_RemotePluginServiceServicer_to_server">add_RemotePluginServiceServicer_to_server</a></code></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><h3><a href="#header-classes">Classes</a></h3>
|
||||
<ul>
|
||||
<li>
|
||||
<h4><code><a title="connpy.grpc_layer.remote_plugin_pb2_grpc.RemotePluginService" href="#connpy.grpc_layer.remote_plugin_pb2_grpc.RemotePluginService">RemotePluginService</a></code></h4>
|
||||
<ul class="">
|
||||
<li><code><a title="connpy.grpc_layer.remote_plugin_pb2_grpc.RemotePluginService.get_plugin_source" href="#connpy.grpc_layer.remote_plugin_pb2_grpc.RemotePluginService.get_plugin_source">get_plugin_source</a></code></li>
|
||||
<li><code><a title="connpy.grpc_layer.remote_plugin_pb2_grpc.RemotePluginService.invoke_plugin" href="#connpy.grpc_layer.remote_plugin_pb2_grpc.RemotePluginService.invoke_plugin">invoke_plugin</a></code></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>
|
||||
<h4><code><a title="connpy.grpc_layer.remote_plugin_pb2_grpc.RemotePluginServiceServicer" href="#connpy.grpc_layer.remote_plugin_pb2_grpc.RemotePluginServiceServicer">RemotePluginServiceServicer</a></code></h4>
|
||||
<ul class="">
|
||||
<li><code><a title="connpy.grpc_layer.remote_plugin_pb2_grpc.RemotePluginServiceServicer.get_plugin_source" href="#connpy.grpc_layer.remote_plugin_pb2_grpc.RemotePluginServiceServicer.get_plugin_source">get_plugin_source</a></code></li>
|
||||
<li><code><a title="connpy.grpc_layer.remote_plugin_pb2_grpc.RemotePluginServiceServicer.invoke_plugin" href="#connpy.grpc_layer.remote_plugin_pb2_grpc.RemotePluginServiceServicer.invoke_plugin">invoke_plugin</a></code></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>
|
||||
<h4><code><a title="connpy.grpc_layer.remote_plugin_pb2_grpc.RemotePluginServiceStub" href="#connpy.grpc_layer.remote_plugin_pb2_grpc.RemotePluginServiceStub">RemotePluginServiceStub</a></code></h4>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
</main>
|
||||
<footer id="footer">
|
||||
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.11.6</a>.</p>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,144 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1">
|
||||
<meta name="generator" content="pdoc3 0.11.6">
|
||||
<title>connpy.grpc_layer.utils API documentation</title>
|
||||
<meta name="description" content="">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/13.0.0/sanitize.min.css" integrity="sha512-y1dtMcuvtTMJc1yPgEqF0ZjQbhnc/bFhyvIyVNb9Zk5mIGtqVaAB1Ttl28su8AvFMOY0EwRbAe+HCLqj6W7/KA==" crossorigin>
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/13.0.0/typography.min.css" integrity="sha512-Y1DYSb995BAfxobCkKepB1BqJJTPrOp3zPL74AWFugHHmmdcvO+C48WLrUOlhGMc0QG7AE3f7gmvvcrmX2fDoA==" crossorigin>
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/default.min.css" crossorigin>
|
||||
<style>:root{--highlight-color:#fe9}.flex{display:flex !important}body{line-height:1.5em}#content{padding:20px}#sidebar{padding:1.5em;overflow:hidden}#sidebar > *:last-child{margin-bottom:2cm}.http-server-breadcrumbs{font-size:130%;margin:0 0 15px 0}#footer{font-size:.75em;padding:5px 30px;border-top:1px solid #ddd;text-align:right}#footer p{margin:0 0 0 1em;display:inline-block}#footer p:last-child{margin-right:30px}h1,h2,h3,h4,h5{font-weight:300}h1{font-size:2.5em;line-height:1.1em}h2{font-size:1.75em;margin:2em 0 .50em 0}h3{font-size:1.4em;margin:1.6em 0 .7em 0}h4{margin:0;font-size:105%}h1:target,h2:target,h3:target,h4:target,h5:target,h6:target{background:var(--highlight-color);padding:.2em 0}a{color:#058;text-decoration:none;transition:color .2s ease-in-out}a:visited{color:#503}a:hover{color:#b62}.title code{font-weight:bold}h2[id^="header-"]{margin-top:2em}.ident{color:#900;font-weight:bold}pre code{font-size:.8em;line-height:1.4em;padding:1em;display:block}code{background:#f3f3f3;font-family:"DejaVu Sans Mono",monospace;padding:1px 4px;overflow-wrap:break-word}h1 code{background:transparent}pre{border-top:1px solid #ccc;border-bottom:1px solid #ccc;margin:1em 0}#http-server-module-list{display:flex;flex-flow:column}#http-server-module-list div{display:flex}#http-server-module-list dt{min-width:10%}#http-server-module-list p{margin-top:0}.toc ul,#index{list-style-type:none;margin:0;padding:0}#index code{background:transparent}#index h3{border-bottom:1px solid #ddd}#index ul{padding:0}#index h4{margin-top:.6em;font-weight:bold}@media (min-width:200ex){#index .two-column{column-count:2}}@media (min-width:300ex){#index .two-column{column-count:3}}dl{margin-bottom:2em}dl dl:last-child{margin-bottom:4em}dd{margin:0 0 1em 3em}#header-classes + dl > dd{margin-bottom:3em}dd dd{margin-left:2em}dd p{margin:10px 0}.name{background:#eee;font-size:.85em;padding:5px 10px;display:inline-block;min-width:40%}.name:hover{background:#e0e0e0}dt:target .name{background:var(--highlight-color)}.name > span:first-child{white-space:nowrap}.name.class > span:nth-child(2){margin-left:.4em}.inherited{color:#999;border-left:5px solid #eee;padding-left:1em}.inheritance em{font-style:normal;font-weight:bold}.desc h2{font-weight:400;font-size:1.25em}.desc h3{font-size:1em}.desc dt code{background:inherit}.source > summary,.git-link-div{color:#666;text-align:right;font-weight:400;font-size:.8em;text-transform:uppercase}.source summary > *{white-space:nowrap;cursor:pointer}.git-link{color:inherit;margin-left:1em}.source pre{max-height:500px;overflow:auto;margin:0}.source pre code{font-size:12px;overflow:visible;min-width:max-content}.hlist{list-style:none}.hlist li{display:inline}.hlist li:after{content:',\2002'}.hlist li:last-child:after{content:none}.hlist .hlist{display:inline;padding-left:1em}img{max-width:100%}td{padding:0 .5em}.admonition{padding:.1em 1em;margin:1em 0}.admonition-title{font-weight:bold}.admonition.note,.admonition.info,.admonition.important{background:#aef}.admonition.todo,.admonition.versionadded,.admonition.tip,.admonition.hint{background:#dfd}.admonition.warning,.admonition.versionchanged,.admonition.deprecated{background:#fd4}.admonition.error,.admonition.danger,.admonition.caution{background:lightpink}</style>
|
||||
<style media="screen and (min-width: 700px)">@media screen and (min-width:700px){#sidebar{width:30%;height:100vh;overflow:auto;position:sticky;top:0}#content{width:70%;max-width:100ch;padding:3em 4em;border-left:1px solid #ddd}pre code{font-size:1em}.name{font-size:1em}main{display:flex;flex-direction:row-reverse;justify-content:flex-end}.toc ul ul,#index ul ul{padding-left:1em}.toc > ul > li{margin-top:.5em}}</style>
|
||||
<style media="print">@media print{#sidebar h1{page-break-before:always}.source{display:none}}@media print{*{background:transparent !important;color:#000 !important;box-shadow:none !important;text-shadow:none !important}a[href]:after{content:" (" attr(href) ")";font-size:90%}a[href][title]:after{content:none}abbr[title]:after{content:" (" attr(title) ")"}.ir a:after,a[href^="javascript:"]:after,a[href^="#"]:after{content:""}pre,blockquote{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}tr,img{page-break-inside:avoid}img{max-width:100% !important}@page{margin:0.5cm}p,h2,h3{orphans:3;widows:3}h1,h2,h3,h4,h5,h6{page-break-after:avoid}}</style>
|
||||
<script defer src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/highlight.min.js" integrity="sha512-D9gUyxqja7hBtkWpPWGt9wfbfaMGVt9gnyCvYa+jojwwPHLCzUm5i8rpk7vD7wNee9bA35eYIjobYPaQuKS1MQ==" crossorigin></script>
|
||||
<script>window.addEventListener('DOMContentLoaded', () => {
|
||||
hljs.configure({languages: ['bash', 'css', 'diff', 'graphql', 'ini', 'javascript', 'json', 'plaintext', 'python', 'python-repl', 'rust', 'shell', 'sql', 'typescript', 'xml', 'yaml']});
|
||||
hljs.highlightAll();
|
||||
/* Collapse source docstrings */
|
||||
setTimeout(() => {
|
||||
[...document.querySelectorAll('.hljs.language-python > .hljs-string')]
|
||||
.filter(el => el.innerHTML.length > 200 && ['"""', "'''"].includes(el.innerHTML.substring(0, 3)))
|
||||
.forEach(el => {
|
||||
let d = document.createElement('details');
|
||||
d.classList.add('hljs-string');
|
||||
d.innerHTML = '<summary>"""</summary>' + el.innerHTML.substring(3);
|
||||
el.replaceWith(d);
|
||||
});
|
||||
}, 100);
|
||||
})</script>
|
||||
</head>
|
||||
<body>
|
||||
<main>
|
||||
<article id="content">
|
||||
<header>
|
||||
<h1 class="title">Module <code>connpy.grpc_layer.utils</code></h1>
|
||||
</header>
|
||||
<section id="section-intro">
|
||||
</section>
|
||||
<section>
|
||||
</section>
|
||||
<section>
|
||||
</section>
|
||||
<section>
|
||||
<h2 class="section-title" id="header-functions">Functions</h2>
|
||||
<dl>
|
||||
<dt id="connpy.grpc_layer.utils.from_struct"><code class="name flex">
|
||||
<span>def <span class="ident">from_struct</span></span>(<span>struct)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def from_struct(struct):
|
||||
if not struct:
|
||||
return {}
|
||||
return json_format.MessageToDict(struct, preserving_proto_field_name=True)</code></pre>
|
||||
</details>
|
||||
<div class="desc"></div>
|
||||
</dd>
|
||||
<dt id="connpy.grpc_layer.utils.from_value"><code class="name flex">
|
||||
<span>def <span class="ident">from_value</span></span>(<span>val)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def from_value(val):
|
||||
if not val.HasField("kind"):
|
||||
return None
|
||||
return json.loads(json_format.MessageToJson(val))</code></pre>
|
||||
</details>
|
||||
<div class="desc"></div>
|
||||
</dd>
|
||||
<dt id="connpy.grpc_layer.utils.to_struct"><code class="name flex">
|
||||
<span>def <span class="ident">to_struct</span></span>(<span>obj)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def to_struct(obj):
|
||||
if not obj:
|
||||
return Struct()
|
||||
s = Struct()
|
||||
json_format.ParseDict(obj, s)
|
||||
return s</code></pre>
|
||||
</details>
|
||||
<div class="desc"></div>
|
||||
</dd>
|
||||
<dt id="connpy.grpc_layer.utils.to_value"><code class="name flex">
|
||||
<span>def <span class="ident">to_value</span></span>(<span>obj)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def to_value(obj):
|
||||
if obj is None:
|
||||
v = Value()
|
||||
v.null_value = 0
|
||||
return v
|
||||
json_str = json.dumps(obj)
|
||||
v = Value()
|
||||
json_format.Parse(json_str, v)
|
||||
return v</code></pre>
|
||||
</details>
|
||||
<div class="desc"></div>
|
||||
</dd>
|
||||
</dl>
|
||||
</section>
|
||||
<section>
|
||||
</section>
|
||||
</article>
|
||||
<nav id="sidebar">
|
||||
<div class="toc">
|
||||
<ul></ul>
|
||||
</div>
|
||||
<ul id="index">
|
||||
<li><h3>Super-module</h3>
|
||||
<ul>
|
||||
<li><code><a title="connpy.grpc_layer" href="index.html">connpy.grpc_layer</a></code></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><h3><a href="#header-functions">Functions</a></h3>
|
||||
<ul class="">
|
||||
<li><code><a title="connpy.grpc_layer.utils.from_struct" href="#connpy.grpc_layer.utils.from_struct">from_struct</a></code></li>
|
||||
<li><code><a title="connpy.grpc_layer.utils.from_value" href="#connpy.grpc_layer.utils.from_value">from_value</a></code></li>
|
||||
<li><code><a title="connpy.grpc_layer.utils.to_struct" href="#connpy.grpc_layer.utils.to_struct">to_struct</a></code></li>
|
||||
<li><code><a title="connpy.grpc_layer.utils.to_value" href="#connpy.grpc_layer.utils.to_value">to_value</a></code></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
</main>
|
||||
<footer id="footer">
|
||||
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.11.6</a>.</p>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
||||
+205
-67
@@ -3,7 +3,7 @@
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1">
|
||||
<meta name="generator" content="pdoc3 0.11.5">
|
||||
<meta name="generator" content="pdoc3 0.11.6">
|
||||
<title>connpy API documentation</title>
|
||||
<meta name="description" content="Connection manager …">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/13.0.0/sanitize.min.css" integrity="sha512-y1dtMcuvtTMJc1yPgEqF0ZjQbhnc/bFhyvIyVNb9Zk5mIGtqVaAB1Ttl28su8AvFMOY0EwRbAe+HCLqj6W7/KA==" crossorigin>
|
||||
@@ -37,9 +37,9 @@ el.replaceWith(d);
|
||||
</header>
|
||||
<section id="section-intro">
|
||||
<h2 id="connection-manager">Connection manager</h2>
|
||||
<p>Connpy is a SSH, SFTP, Telnet, kubectl, and Docker pod connection manager and automation module for Linux, Mac, and Docker.</p>
|
||||
<p>Connpy is a SSH, SFTP, Telnet, kubectl, Docker pod, and AWS SSM connection manager and automation module for Linux, Mac, and Docker.</p>
|
||||
<h3 id="features">Features</h3>
|
||||
<pre><code>- Manage connections using SSH, SFTP, Telnet, kubectl, and Docker exec.
|
||||
<pre><code>- Manage connections using SSH, SFTP, Telnet, kubectl, Docker exec, and AWS SSM.
|
||||
- Set contexts to manage specific nodes from specific contexts (work/home/clients/etc).
|
||||
- You can generate profiles and reference them from nodes using @profilename so you don't
|
||||
need to edit multiple nodes when changing passwords or other information.
|
||||
@@ -516,7 +516,7 @@ class Preload:
|
||||
<dd>
|
||||
<div class="desc"></div>
|
||||
</dd>
|
||||
<dt><code class="name"><a title="connpy.grpc" href="grpc/index.html">connpy.grpc</a></code></dt>
|
||||
<dt><code class="name"><a title="connpy.grpc_layer" href="grpc_layer/index.html">connpy.grpc_layer</a></code></dt>
|
||||
<dd>
|
||||
<div class="desc"></div>
|
||||
</dd>
|
||||
@@ -1116,14 +1116,20 @@ class ai:
|
||||
status_formatter (callable): Function(args_dict) -> status string.
|
||||
"""
|
||||
name = tool_definition["function"]["name"]
|
||||
|
||||
# Check if already registered to prevent duplicates
|
||||
if target in ("engineer", "both"):
|
||||
self.external_engineer_tools.append(tool_definition)
|
||||
if not any(t["function"]["name"] == name for t in self.external_engineer_tools):
|
||||
self.external_engineer_tools.append(tool_definition)
|
||||
if target in ("architect", "both"):
|
||||
self.external_architect_tools.append(tool_definition)
|
||||
if not any(t["function"]["name"] == name for t in self.external_architect_tools):
|
||||
self.external_architect_tools.append(tool_definition)
|
||||
|
||||
self.external_tool_handlers[name] = handler
|
||||
if engineer_prompt:
|
||||
|
||||
if engineer_prompt and engineer_prompt not in self.engineer_prompt_extensions:
|
||||
self.engineer_prompt_extensions.append(engineer_prompt)
|
||||
if architect_prompt:
|
||||
if architect_prompt and architect_prompt not in self.architect_prompt_extensions:
|
||||
self.architect_prompt_extensions.append(architect_prompt)
|
||||
if status_formatter:
|
||||
self.tool_status_formatters[name] = status_formatter
|
||||
@@ -1355,12 +1361,46 @@ class ai:
|
||||
|
||||
def _truncate(self, text, limit=None):
|
||||
"""Truncate text to specified limit, keeping head (60%) and tail (40%)."""
|
||||
if not isinstance(text, str): return str(text)
|
||||
final_limit = limit or self.max_truncate
|
||||
if len(text) <= final_limit: return text
|
||||
head_limit = int(final_limit * 0.6)
|
||||
tail_limit = int(final_limit * 0.4)
|
||||
return (text[:head_limit] + f"\n\n[... OUTPUT TRUNCATED ...]\n\n" + text[-tail_limit:])
|
||||
|
||||
def _print_debug_observation(self, fn, obs):
|
||||
"""Prints a tool observation in a readable way during debug mode."""
|
||||
# Try to parse as JSON if it's a string
|
||||
if isinstance(obs, str):
|
||||
try:
|
||||
obs_data = json.loads(obs)
|
||||
except Exception:
|
||||
obs_data = obs
|
||||
else:
|
||||
obs_data = obs
|
||||
|
||||
if isinstance(obs_data, dict):
|
||||
elements = []
|
||||
for k, v in obs_data.items():
|
||||
elements.append(Text(f"• {k}:", style="key"))
|
||||
# Use Text for values to ensure newlines are rendered
|
||||
val = str(v)
|
||||
# If it's a multiline string from a delegation task, keep it clean
|
||||
elements.append(Text(val))
|
||||
|
||||
if not elements:
|
||||
content = Text("Empty data set")
|
||||
else:
|
||||
# Add a small spacer instead of a Rule for cleaner look
|
||||
content = Group(*elements)
|
||||
elif isinstance(obs_data, list):
|
||||
content = Text("\n".join(f"• {item}" for item in obs_data))
|
||||
else:
|
||||
content = Text(str(obs_data))
|
||||
|
||||
title = f"[bold]{fn}[/bold]"
|
||||
self.console.print(Panel(content, title=title, border_style="ai_status"))
|
||||
|
||||
def manage_memory_tool(self, content, action="append"):
|
||||
"""Save or update long-term memory. Only use when user explicitly requests it."""
|
||||
if not content or not content.strip():
|
||||
@@ -1398,8 +1438,8 @@ class ai:
|
||||
ts = data.get("tags")
|
||||
if isinstance(ts, dict): os_tag = ts.get("os", "unknown")
|
||||
res[name] = {"os": os_tag}
|
||||
return json.dumps(res)
|
||||
return json.dumps({"count": len(matched_names), "nodes": matched_names, "note": "Use 'get_node_info' for details."})
|
||||
return res
|
||||
return {"count": len(matched_names), "nodes": matched_names, "note": "Use 'get_node_info' for details."}
|
||||
except Exception as e:
|
||||
return f"Error listing nodes: {str(e)}"
|
||||
|
||||
@@ -1473,7 +1513,7 @@ class ai:
|
||||
if not matched_names: return "No nodes found matching filter."
|
||||
thisnodes_dict = self.config.getitems(matched_names, extract=True)
|
||||
result = nodes(thisnodes_dict, config=self.config).run(commands)
|
||||
return self._truncate(json.dumps(result))
|
||||
return result
|
||||
except Exception as e:
|
||||
return f"Error executing commands: {str(e)}"
|
||||
|
||||
@@ -1482,7 +1522,7 @@ class ai:
|
||||
try:
|
||||
d = self.config.getitem(node_name, extract=True)
|
||||
if 'password' in d: d['password'] = '***'
|
||||
return json.dumps(d)
|
||||
return d
|
||||
except Exception as e:
|
||||
return f"Error getting node info: {str(e)}"
|
||||
|
||||
@@ -1526,7 +1566,7 @@ class ai:
|
||||
self.console.print(f"[warning] You can press Ctrl+C to interrupt and get a summary.[/warning]")
|
||||
soft_limit_warned = True
|
||||
|
||||
if status: status.update(f"[ai_status]Engineer: Analyzing mission... (step {iteration})")
|
||||
if status and not chat_history: status.update(f"[ai_status]Engineer: Analyzing mission... (step {iteration})")
|
||||
|
||||
try:
|
||||
safe_messages = self._sanitize_messages(messages)
|
||||
@@ -1549,8 +1589,8 @@ class ai:
|
||||
for tc in resp_msg.tool_calls:
|
||||
fn, args = tc.function.name, json.loads(tc.function.arguments)
|
||||
|
||||
# Notificación en tiempo real de la tarea técnica
|
||||
if status:
|
||||
# Notificación en tiempo real de la tarea técnica (Only if not in Architect loop)
|
||||
if status and not chat_history:
|
||||
if fn == "list_nodes": status.update(f"[ai_status]Engineer: [SEARCH] {args.get('filter_pattern','.*')}")
|
||||
elif fn == "run_commands":
|
||||
cmds = args.get('commands', [])
|
||||
@@ -1559,7 +1599,8 @@ class ai:
|
||||
elif fn == "get_node_info": status.update(f"[ai_status]Engineer: [INSPECT] {args.get('node_name','')}")
|
||||
elif fn in self.tool_status_formatters: status.update(self.tool_status_formatters[fn](args))
|
||||
|
||||
if debug: self.console.print(Panel(Text(json.dumps(args, indent=2)), title=f"[bold engineer]Engineer Tool: {fn}[/bold engineer]", border_style="engineer"))
|
||||
if debug:
|
||||
self._print_debug_observation(f"Decision: {fn}", args)
|
||||
|
||||
if fn == "list_nodes": obs = self.list_nodes_tool(**args)
|
||||
elif fn == "run_commands": obs = self.run_commands_tool(**args, status=status)
|
||||
@@ -1567,8 +1608,12 @@ class ai:
|
||||
elif fn in self.external_tool_handlers: obs = self.external_tool_handlers[fn](self, **args)
|
||||
else: obs = f"Error: Unknown tool '{fn}'."
|
||||
|
||||
if debug: self.console.print(Panel(Text(str(obs)), title=f"[bold pass]Engineer Observation: {fn}[/bold pass]", border_style="success"))
|
||||
messages.append({"tool_call_id": tc.id, "role": "tool", "name": fn, "content": obs})
|
||||
if debug:
|
||||
self._print_debug_observation(f"Observation: {fn}", obs)
|
||||
|
||||
# Ensure observation is a string and truncated for the LLM
|
||||
obs_str = obs if isinstance(obs, str) else json.dumps(obs)
|
||||
messages.append({"tool_call_id": tc.id, "role": "tool", "name": fn, "content": self._truncate(obs_str)})
|
||||
|
||||
if iteration >= self.hard_limit_iterations:
|
||||
self.console.print(f"[error]⛔ Engineer reached hard limit ({self.hard_limit_iterations} steps). Forcing stop.[/error]")
|
||||
@@ -1582,30 +1627,46 @@ class ai:
|
||||
|
||||
def _get_engineer_tools(self):
|
||||
"""Define tools available to the Engineer."""
|
||||
tools = [
|
||||
base_tools = [
|
||||
{"type": "function", "function": {"name": "list_nodes", "description": "Lists available nodes in the inventory.", "parameters": {"type": "object", "properties": {"filter_pattern": {"type": "string", "description": "Regex to filter nodes (e.g. '.*', 'border.*')."}}}}},
|
||||
{"type": "function", "function": {"name": "run_commands", "description": "Runs one or more commands on matched nodes. MANDATORY: You MUST call 'list_nodes' first to verify the target list.", "parameters": {"type": "object", "properties": {"nodes_filter": {"type": "string", "description": "Exact node name or verified filter pattern."}, "commands": {"type": "array", "items": {"type": "string"}, "description": "List of commands (e.g. ['show ip route', 'show int desc'])."}}, "required": ["nodes_filter", "commands"]}}},
|
||||
{"type": "function", "function": {"name": "get_node_info", "description": "Gets full metadata for a specific node.", "parameters": {"type": "object", "properties": {"node_name": {"type": "string"}}, "required": ["node_name"]}}}
|
||||
]
|
||||
|
||||
if self.architect_key:
|
||||
tools.extend([
|
||||
base_tools.extend([
|
||||
{"type": "function", "function": {"name": "consult_architect", "description": "Ask the Strategic Reasoning Engine for advice on complex design, architecture, or troubleshooting decisions. You remain in control and will present the response to the user. Use this for: configuration planning, design validation, complex troubleshooting.", "parameters": {"type": "object", "properties": {"question": {"type": "string", "description": "Strategic question or decision needed."}, "technical_summary": {"type": "string", "description": "Technical findings and context gathered so far."}}, "required": ["question", "technical_summary"]}}},
|
||||
{"type": "function", "function": {"name": "escalate_to_architect", "description": "Transfer full control to the Strategic Reasoning Engine. Use ONLY when the user explicitly requests the Architect or when the problem requires strategic oversight beyond consultation. After escalation, the Architect takes over the conversation.", "parameters": {"type": "object", "properties": {"reason": {"type": "string", "description": "Why you're escalating (e.g. 'User requested Architect', 'Complex multi-site design needed')."}, "context": {"type": "string", "description": "Full context and findings to hand over."}}, "required": ["reason", "context"]}}}
|
||||
])
|
||||
|
||||
tools.extend(self.external_engineer_tools)
|
||||
return tools
|
||||
# Deduplicate by name to prevent Gemini BadRequestError
|
||||
all_tools = base_tools + self.external_engineer_tools
|
||||
seen_names = set()
|
||||
unique_tools = []
|
||||
for t in all_tools:
|
||||
name = t["function"]["name"]
|
||||
if name not in seen_names:
|
||||
unique_tools.append(t)
|
||||
seen_names.add(name)
|
||||
return unique_tools
|
||||
|
||||
def _get_architect_tools(self):
|
||||
"""Define tools available to the Strategic Reasoning Engine."""
|
||||
tools = [
|
||||
base_tools = [
|
||||
{"type": "function", "function": {"name": "delegate_to_engineer", "description": "Delegates a technical mission to the Engineer.", "parameters": {"type": "object", "properties": {"task": {"type": "string", "description": "Detailed technical mission or goal."}}, "required": ["task"]}}},
|
||||
{"type": "function", "function": {"name": "return_to_engineer", "description": "Return control to the Engineer. Use this when your strategic analysis is complete and the Engineer should handle the rest of the conversation.", "parameters": {"type": "object", "properties": {"summary": {"type": "string", "description": "Brief summary of your analysis to hand over to the Engineer."}}, "required": ["summary"]}}},
|
||||
{"type": "function", "function": {"name": "manage_memory_tool", "description": "Saves information to long-term memory. MANDATORY: Only use this if the user explicitly asks to remember or save something.", "parameters": {"type": "object", "properties": {"content": {"type": "string"}, "action": {"type": "string", "enum": ["append", "replace"]}}, "required": ["content"]}}}
|
||||
]
|
||||
tools.extend(self.external_architect_tools)
|
||||
return tools
|
||||
|
||||
all_tools = base_tools + self.external_architect_tools
|
||||
seen_names = set()
|
||||
unique_tools = []
|
||||
for t in all_tools:
|
||||
name = t["function"]["name"]
|
||||
if name not in seen_names:
|
||||
unique_tools.append(t)
|
||||
seen_names.add(name)
|
||||
return unique_tools
|
||||
|
||||
def _get_sessions(self):
|
||||
"""Returns a list of session metadata sorted by date."""
|
||||
@@ -1809,12 +1870,16 @@ class ai:
|
||||
soft_limit_warned = True
|
||||
|
||||
label = "[architect][bold]Architect[/bold][/architect]" if current_brain == "architect" else "[engineer][bold]Engineer[/bold][/engineer]"
|
||||
if status: status.update(f"{label} is thinking... (step {iteration})")
|
||||
if status:
|
||||
# Notify responder identity ONLY for web/remote clients (StatusBridge has is_web)
|
||||
if getattr(status, "is_web", False):
|
||||
status.update(f"__RESPONDER__:{current_brain}")
|
||||
status.update(f"{label} is thinking... (step {iteration})")
|
||||
|
||||
streamed_response = False
|
||||
try:
|
||||
safe_messages = self._sanitize_messages(messages)
|
||||
if stream and not debug:
|
||||
if stream and (not debug or chunk_callback):
|
||||
response, streamed_response = self._stream_completion(
|
||||
model=model, messages=safe_messages, tools=tools, api_key=key,
|
||||
status=status, label=label, debug=debug, num_retries=3,
|
||||
@@ -1854,7 +1919,10 @@ class ai:
|
||||
messages.append(msg_dict)
|
||||
|
||||
if debug and resp_msg.content:
|
||||
self.console.print(Panel(Markdown(resp_msg.content), title=f"{label} Reasoning", border_style="architect" if current_brain == "architect" else "engineer"))
|
||||
# In CLI debug mode, only print intermediate reasoning if there are tool calls.
|
||||
# If there are no tool calls, this content is the final answer and will be printed by the caller.
|
||||
if resp_msg.tool_calls:
|
||||
self.console.print(Panel(Markdown(resp_msg.content), title=f"[{current_brain}][bold]{label} Reasoning[/bold][/{current_brain}]", border_style="architect" if current_brain == "architect" else "engineer"))
|
||||
|
||||
if not resp_msg.tool_calls: break
|
||||
|
||||
@@ -1874,7 +1942,8 @@ class ai:
|
||||
if fn == "delegate_to_engineer": status.update(f"[architect]Architect: [DELEGATING MISSION] {args.get('task','')[:40]}...")
|
||||
elif fn == "manage_memory_tool": status.update(f"[architect]Architect: [UPDATING MEMORY]")
|
||||
|
||||
if debug: self.console.print(Panel(Text(json.dumps(args, indent=2)), title=f"{label} Decision: {fn}", border_style="debug"))
|
||||
if debug:
|
||||
self._print_debug_observation(f"Decision: {fn}", args)
|
||||
|
||||
if fn == "delegate_to_engineer":
|
||||
obs, eng_usage = self._engineer_loop(args["task"], status=status, debug=debug, chat_history=messages[:-1])
|
||||
@@ -1932,9 +2001,13 @@ class ai:
|
||||
elif fn == "manage_memory_tool": obs = self.manage_memory_tool(**args)
|
||||
elif fn in self.external_tool_handlers: obs = self.external_tool_handlers[fn](self, **args)
|
||||
else: obs = f"Error: {fn} unknown."
|
||||
|
||||
messages.append({"tool_call_id": tc.id, "role": "tool", "name": fn, "content": obs})
|
||||
|
||||
|
||||
if debug and fn not in ["delegate_to_engineer", "consult_architect", "escalate_to_architect", "return_to_engineer"]:
|
||||
self._print_debug_observation(f"Observation: {fn}", obs)
|
||||
|
||||
# Ensure observation is a string and truncated for the LLM
|
||||
obs_str = obs if isinstance(obs, str) else json.dumps(obs)
|
||||
messages.append({"tool_call_id": tc.id, "role": "tool", "name": fn, "content": self._truncate(obs_str)})
|
||||
# Inject pending user message AFTER all tool responses are added
|
||||
if pending_user_message:
|
||||
messages.append({"role": "user", "content": pending_user_message})
|
||||
@@ -1960,14 +2033,25 @@ class ai:
|
||||
if last_msg.get("tool_calls"):
|
||||
for tc in last_msg["tool_calls"]:
|
||||
messages.append({"tool_call_id": tc.get("id"), "role": "tool", "name": tc.get("function", {}).get("name"), "content": "Operation cancelled by user."})
|
||||
messages.append({"role": "user", "content": "USER INTERRUPTED. Briefly summarize what you were doing and stop."})
|
||||
|
||||
# Use a fresh list for the summary call to avoid history corruption
|
||||
summary_messages = list(messages)
|
||||
summary_messages.append({"role": "user", "content": "USER INTERRUPTED. Briefly summarize what you were doing and stop."})
|
||||
try:
|
||||
safe_messages = self._sanitize_messages(messages)
|
||||
safe_messages = self._sanitize_messages(summary_messages)
|
||||
# Use tools=None to force a text summary during interruption
|
||||
response = completion(model=model, messages=safe_messages, tools=None, api_key=key)
|
||||
resp_msg = response.choices[0].message
|
||||
messages.append(resp_msg.model_dump(exclude_none=True))
|
||||
except Exception: pass
|
||||
|
||||
# IMPORTANT: Manually trigger callback for the summary so Web UI sees it
|
||||
if chunk_callback and resp_msg.content:
|
||||
chunk_callback(resp_msg.content)
|
||||
except Exception:
|
||||
error_msg = "Operation interrupted by user. Summary unavailable."
|
||||
messages.append({"role": "assistant", "content": error_msg})
|
||||
if chunk_callback:
|
||||
chunk_callback(error_msg)
|
||||
finally:
|
||||
# Auto-save session
|
||||
self.save_session(messages, model=model)
|
||||
@@ -1989,7 +2073,7 @@ class ai:
|
||||
<dl>
|
||||
<dt id="connpy.ai.SAFE_COMMANDS"><code class="name">var <span class="ident">SAFE_COMMANDS</span></code></dt>
|
||||
<dd>
|
||||
<div class="desc"></div>
|
||||
<div class="desc"><p>The type of the None singleton.</p></div>
|
||||
</dd>
|
||||
</dl>
|
||||
<h3>Instance variables</h3>
|
||||
@@ -2132,12 +2216,16 @@ def ask(self, user_input, dryrun=False, chat_history=None, status=None, debug=Fa
|
||||
soft_limit_warned = True
|
||||
|
||||
label = "[architect][bold]Architect[/bold][/architect]" if current_brain == "architect" else "[engineer][bold]Engineer[/bold][/engineer]"
|
||||
if status: status.update(f"{label} is thinking... (step {iteration})")
|
||||
if status:
|
||||
# Notify responder identity ONLY for web/remote clients (StatusBridge has is_web)
|
||||
if getattr(status, "is_web", False):
|
||||
status.update(f"__RESPONDER__:{current_brain}")
|
||||
status.update(f"{label} is thinking... (step {iteration})")
|
||||
|
||||
streamed_response = False
|
||||
try:
|
||||
safe_messages = self._sanitize_messages(messages)
|
||||
if stream and not debug:
|
||||
if stream and (not debug or chunk_callback):
|
||||
response, streamed_response = self._stream_completion(
|
||||
model=model, messages=safe_messages, tools=tools, api_key=key,
|
||||
status=status, label=label, debug=debug, num_retries=3,
|
||||
@@ -2177,7 +2265,10 @@ def ask(self, user_input, dryrun=False, chat_history=None, status=None, debug=Fa
|
||||
messages.append(msg_dict)
|
||||
|
||||
if debug and resp_msg.content:
|
||||
self.console.print(Panel(Markdown(resp_msg.content), title=f"{label} Reasoning", border_style="architect" if current_brain == "architect" else "engineer"))
|
||||
# In CLI debug mode, only print intermediate reasoning if there are tool calls.
|
||||
# If there are no tool calls, this content is the final answer and will be printed by the caller.
|
||||
if resp_msg.tool_calls:
|
||||
self.console.print(Panel(Markdown(resp_msg.content), title=f"[{current_brain}][bold]{label} Reasoning[/bold][/{current_brain}]", border_style="architect" if current_brain == "architect" else "engineer"))
|
||||
|
||||
if not resp_msg.tool_calls: break
|
||||
|
||||
@@ -2197,7 +2288,8 @@ def ask(self, user_input, dryrun=False, chat_history=None, status=None, debug=Fa
|
||||
if fn == "delegate_to_engineer": status.update(f"[architect]Architect: [DELEGATING MISSION] {args.get('task','')[:40]}...")
|
||||
elif fn == "manage_memory_tool": status.update(f"[architect]Architect: [UPDATING MEMORY]")
|
||||
|
||||
if debug: self.console.print(Panel(Text(json.dumps(args, indent=2)), title=f"{label} Decision: {fn}", border_style="debug"))
|
||||
if debug:
|
||||
self._print_debug_observation(f"Decision: {fn}", args)
|
||||
|
||||
if fn == "delegate_to_engineer":
|
||||
obs, eng_usage = self._engineer_loop(args["task"], status=status, debug=debug, chat_history=messages[:-1])
|
||||
@@ -2255,9 +2347,13 @@ def ask(self, user_input, dryrun=False, chat_history=None, status=None, debug=Fa
|
||||
elif fn == "manage_memory_tool": obs = self.manage_memory_tool(**args)
|
||||
elif fn in self.external_tool_handlers: obs = self.external_tool_handlers[fn](self, **args)
|
||||
else: obs = f"Error: {fn} unknown."
|
||||
|
||||
messages.append({"tool_call_id": tc.id, "role": "tool", "name": fn, "content": obs})
|
||||
|
||||
|
||||
if debug and fn not in ["delegate_to_engineer", "consult_architect", "escalate_to_architect", "return_to_engineer"]:
|
||||
self._print_debug_observation(f"Observation: {fn}", obs)
|
||||
|
||||
# Ensure observation is a string and truncated for the LLM
|
||||
obs_str = obs if isinstance(obs, str) else json.dumps(obs)
|
||||
messages.append({"tool_call_id": tc.id, "role": "tool", "name": fn, "content": self._truncate(obs_str)})
|
||||
# Inject pending user message AFTER all tool responses are added
|
||||
if pending_user_message:
|
||||
messages.append({"role": "user", "content": pending_user_message})
|
||||
@@ -2283,14 +2379,25 @@ def ask(self, user_input, dryrun=False, chat_history=None, status=None, debug=Fa
|
||||
if last_msg.get("tool_calls"):
|
||||
for tc in last_msg["tool_calls"]:
|
||||
messages.append({"tool_call_id": tc.get("id"), "role": "tool", "name": tc.get("function", {}).get("name"), "content": "Operation cancelled by user."})
|
||||
messages.append({"role": "user", "content": "USER INTERRUPTED. Briefly summarize what you were doing and stop."})
|
||||
|
||||
# Use a fresh list for the summary call to avoid history corruption
|
||||
summary_messages = list(messages)
|
||||
summary_messages.append({"role": "user", "content": "USER INTERRUPTED. Briefly summarize what you were doing and stop."})
|
||||
try:
|
||||
safe_messages = self._sanitize_messages(messages)
|
||||
safe_messages = self._sanitize_messages(summary_messages)
|
||||
# Use tools=None to force a text summary during interruption
|
||||
response = completion(model=model, messages=safe_messages, tools=None, api_key=key)
|
||||
resp_msg = response.choices[0].message
|
||||
messages.append(resp_msg.model_dump(exclude_none=True))
|
||||
except Exception: pass
|
||||
|
||||
# IMPORTANT: Manually trigger callback for the summary so Web UI sees it
|
||||
if chunk_callback and resp_msg.content:
|
||||
chunk_callback(resp_msg.content)
|
||||
except Exception:
|
||||
error_msg = "Operation interrupted by user. Summary unavailable."
|
||||
messages.append({"role": "assistant", "content": error_msg})
|
||||
if chunk_callback:
|
||||
chunk_callback(error_msg)
|
||||
finally:
|
||||
# Auto-save session
|
||||
self.save_session(messages, model=model)
|
||||
@@ -2366,7 +2473,7 @@ def confirm(self, user_input): return True</code></pre>
|
||||
try:
|
||||
d = self.config.getitem(node_name, extract=True)
|
||||
if 'password' in d: d['password'] = '***'
|
||||
return json.dumps(d)
|
||||
return d
|
||||
except Exception as e:
|
||||
return f"Error getting node info: {str(e)}"</code></pre>
|
||||
</details>
|
||||
@@ -2394,8 +2501,8 @@ def confirm(self, user_input): return True</code></pre>
|
||||
ts = data.get("tags")
|
||||
if isinstance(ts, dict): os_tag = ts.get("os", "unknown")
|
||||
res[name] = {"os": os_tag}
|
||||
return json.dumps(res)
|
||||
return json.dumps({"count": len(matched_names), "nodes": matched_names, "note": "Use 'get_node_info' for details."})
|
||||
return res
|
||||
return {"count": len(matched_names), "nodes": matched_names, "note": "Use 'get_node_info' for details."}
|
||||
except Exception as e:
|
||||
return f"Error listing nodes: {str(e)}"</code></pre>
|
||||
</details>
|
||||
@@ -2498,14 +2605,20 @@ def confirm(self, user_input): return True</code></pre>
|
||||
status_formatter (callable): Function(args_dict) -> status string.
|
||||
"""
|
||||
name = tool_definition["function"]["name"]
|
||||
|
||||
# Check if already registered to prevent duplicates
|
||||
if target in ("engineer", "both"):
|
||||
self.external_engineer_tools.append(tool_definition)
|
||||
if not any(t["function"]["name"] == name for t in self.external_engineer_tools):
|
||||
self.external_engineer_tools.append(tool_definition)
|
||||
if target in ("architect", "both"):
|
||||
self.external_architect_tools.append(tool_definition)
|
||||
if not any(t["function"]["name"] == name for t in self.external_architect_tools):
|
||||
self.external_architect_tools.append(tool_definition)
|
||||
|
||||
self.external_tool_handlers[name] = handler
|
||||
if engineer_prompt:
|
||||
|
||||
if engineer_prompt and engineer_prompt not in self.engineer_prompt_extensions:
|
||||
self.engineer_prompt_extensions.append(engineer_prompt)
|
||||
if architect_prompt:
|
||||
if architect_prompt and architect_prompt not in self.architect_prompt_extensions:
|
||||
self.architect_prompt_extensions.append(architect_prompt)
|
||||
if status_formatter:
|
||||
self.tool_status_formatters[name] = status_formatter</code></pre>
|
||||
@@ -2601,7 +2714,7 @@ def confirm(self, user_input): return True</code></pre>
|
||||
if not matched_names: return "No nodes found matching filter."
|
||||
thisnodes_dict = self.config.getitems(matched_names, extract=True)
|
||||
result = nodes(thisnodes_dict, config=self.config).run(commands)
|
||||
return self._truncate(json.dumps(result))
|
||||
return result
|
||||
except Exception as e:
|
||||
return f"Error executing commands: {str(e)}"</code></pre>
|
||||
</details>
|
||||
@@ -3761,7 +3874,8 @@ class node:
|
||||
size = re.search('columns=([0-9]+).*lines=([0-9]+)',str(os.get_terminal_size()))
|
||||
self.child.setwinsize(int(size.group(2)),int(size.group(1)))
|
||||
if logger:
|
||||
logger("success", "Connected to " + self.unique + " at " + self.host + (":" if self.port != '' else '') + self.port + " via: " + self.protocol)
|
||||
port_str = f":{self.port}" if self.port and self.protocol not in ["ssm", "kubectl", "docker"] else ""
|
||||
logger("success", f"Connected to {self.unique} at {self.host}{port_str} via: {self.protocol}")
|
||||
|
||||
if 'logfile' in dir(self):
|
||||
# Initialize self.mylog
|
||||
@@ -3840,7 +3954,8 @@ class node:
|
||||
now = datetime.datetime.now().strftime('%Y-%m-%d_%H%M%S')
|
||||
if connect == True:
|
||||
if logger:
|
||||
logger("success", "Connected to " + self.unique + " at " + self.host + (":" if self.port != '' else '') + self.port + " via: " + self.protocol)
|
||||
port_str = f":{self.port}" if self.port and self.protocol not in ["ssm", "kubectl", "docker"] else ""
|
||||
logger("success", f"Connected to {self.unique} at {self.host}{port_str} via: {self.protocol}")
|
||||
|
||||
# Attempt to set the terminal size
|
||||
try:
|
||||
@@ -3941,7 +4056,8 @@ class node:
|
||||
connect = self._connect(timeout = timeout, logger = logger)
|
||||
if connect == True:
|
||||
if logger:
|
||||
logger("success", "Connected to " + self.unique + " at " + self.host + (":" if self.port != '' else '') + self.port + " via: " + self.protocol)
|
||||
port_str = f":{self.port}" if self.port and self.protocol not in ["ssm", "kubectl", "docker"] else ""
|
||||
logger("success", f"Connected to {self.unique} at {self.host}{port_str} via: {self.protocol}")
|
||||
|
||||
# Attempt to set the terminal size
|
||||
try:
|
||||
@@ -4046,6 +4162,19 @@ class node:
|
||||
cmd += f" {docker_command}"
|
||||
return cmd
|
||||
|
||||
@MethodHook
|
||||
def _generate_ssm_cmd(self):
|
||||
region = self.tags.get("region", "") if isinstance(self.tags, dict) else ""
|
||||
profile = self.tags.get("profile", "") if isinstance(self.tags, dict) else ""
|
||||
cmd = f"aws ssm start-session --target {self.host}"
|
||||
if region:
|
||||
cmd += f" --region {region}"
|
||||
if profile:
|
||||
cmd += f" --profile {profile}"
|
||||
if self.options:
|
||||
cmd += f" {self.options}"
|
||||
return cmd
|
||||
|
||||
@MethodHook
|
||||
def _get_cmd(self):
|
||||
if self.protocol in ["ssh", "sftp"]:
|
||||
@@ -4056,6 +4185,8 @@ class node:
|
||||
return self._generate_kube_cmd()
|
||||
elif self.protocol == "docker":
|
||||
return self._generate_docker_cmd()
|
||||
elif self.protocol == "ssm":
|
||||
return self._generate_ssm_cmd()
|
||||
else:
|
||||
printer.error(f"Invalid protocol: {self.protocol}")
|
||||
sys.exit(1)
|
||||
@@ -4076,7 +4207,8 @@ class node:
|
||||
"sftp": ['yes/no', 'refused', 'supported', 'Invalid|[u|U]sage: sftp', 'ssh-keygen.*\"', 'timeout|timed.out', 'unavailable', 'closed', password_prompt, prompt, 'suspend', pexpect.EOF, pexpect.TIMEOUT, "No route to host", "resolve hostname", "no matching", "[b|B]ad (owner|permissions)"],
|
||||
"telnet": ['[u|U]sername:', 'refused', 'supported', 'invalid|unrecognized option', 'ssh-keygen.*\"', 'timeout|timed.out', 'unavailable', 'closed', password_prompt, prompt, 'suspend', pexpect.EOF, pexpect.TIMEOUT, "No route to host", "resolve hostname", "no matching", "[b|B]ad (owner|permissions)"],
|
||||
"kubectl": ['[u|U]sername:', '[r|R]efused', '[E|e]rror', 'DEPRECATED', pexpect.TIMEOUT, password_prompt, prompt, pexpect.EOF, "expired|invalid"],
|
||||
"docker": ['[u|U]sername:', 'Cannot', '[E|e]rror', 'failed', 'not a docker command', 'unknown', 'unable to resolve', pexpect.TIMEOUT, password_prompt, prompt, pexpect.EOF]
|
||||
"docker": ['[u|U]sername:', 'Cannot', '[E|e]rror', 'failed', 'not a docker command', 'unknown', 'unable to resolve', pexpect.TIMEOUT, password_prompt, prompt, pexpect.EOF],
|
||||
"ssm": ['[u|U]sername:', 'Cannot', '[E|e]rror', 'failed', 'SessionManagerPlugin', 'unknown', 'unable to resolve', pexpect.TIMEOUT, password_prompt, prompt, pexpect.EOF]
|
||||
}
|
||||
|
||||
error_indices = {
|
||||
@@ -4084,7 +4216,8 @@ class node:
|
||||
"sftp": [1, 2, 3, 4, 5, 6, 7, 12, 13, 14, 15, 16],
|
||||
"telnet": [1, 2, 3, 4, 5, 6, 7, 12, 13, 14, 15, 16],
|
||||
"kubectl": [1, 2, 3, 4, 8], # Define error indices for kube
|
||||
"docker": [1, 2, 3, 4, 5, 6, 7] # Define error indices for docker
|
||||
"docker": [1, 2, 3, 4, 5, 6, 7], # Define error indices for docker
|
||||
"ssm": [1, 2, 3, 4, 5, 6, 7]
|
||||
}
|
||||
|
||||
eof_indices = {
|
||||
@@ -4092,7 +4225,8 @@ class node:
|
||||
"sftp": [8, 9, 10, 11],
|
||||
"telnet": [8, 9, 10, 11],
|
||||
"kubectl": [5, 6, 7], # Define eof indices for kube
|
||||
"docker": [8, 9, 10] # Define eof indices for docker
|
||||
"docker": [8, 9, 10], # Define eof indices for docker
|
||||
"ssm": [8, 9, 10]
|
||||
}
|
||||
|
||||
initial_indices = {
|
||||
@@ -4100,7 +4234,8 @@ class node:
|
||||
"sftp": [0],
|
||||
"telnet": [0],
|
||||
"kubectl": [0], # Define special indices for kube
|
||||
"docker": [0] # Define special indices for docker
|
||||
"docker": [0], # Define special indices for docker
|
||||
"ssm": [0]
|
||||
}
|
||||
|
||||
attempts = 1
|
||||
@@ -4124,7 +4259,7 @@ class node:
|
||||
if results in initial_indices[self.protocol]:
|
||||
if self.protocol in ["ssh", "sftp"]:
|
||||
child.sendline('yes')
|
||||
elif self.protocol in ["telnet", "kubectl", "docker"]:
|
||||
elif self.protocol in ["telnet", "kubectl", "docker", "ssm"]:
|
||||
if self.user:
|
||||
child.sendline(self.user)
|
||||
else:
|
||||
@@ -4244,7 +4379,8 @@ def interact(self, debug = False, logger = None):
|
||||
size = re.search('columns=([0-9]+).*lines=([0-9]+)',str(os.get_terminal_size()))
|
||||
self.child.setwinsize(int(size.group(2)),int(size.group(1)))
|
||||
if logger:
|
||||
logger("success", "Connected to " + self.unique + " at " + self.host + (":" if self.port != '' else '') + self.port + " via: " + self.protocol)
|
||||
port_str = f":{self.port}" if self.port and self.protocol not in ["ssm", "kubectl", "docker"] else ""
|
||||
logger("success", f"Connected to {self.unique} at {self.host}{port_str} via: {self.protocol}")
|
||||
|
||||
if 'logfile' in dir(self):
|
||||
# Initialize self.mylog
|
||||
@@ -4337,7 +4473,8 @@ def run(self, commands, vars = None,*, folder = '', prompt = r'>$
|
||||
now = datetime.datetime.now().strftime('%Y-%m-%d_%H%M%S')
|
||||
if connect == True:
|
||||
if logger:
|
||||
logger("success", "Connected to " + self.unique + " at " + self.host + (":" if self.port != '' else '') + self.port + " via: " + self.protocol)
|
||||
port_str = f":{self.port}" if self.port and self.protocol not in ["ssm", "kubectl", "docker"] else ""
|
||||
logger("success", f"Connected to {self.unique} at {self.host}{port_str} via: {self.protocol}")
|
||||
|
||||
# Attempt to set the terminal size
|
||||
try:
|
||||
@@ -4479,7 +4616,8 @@ def test(self, commands, expected, vars = None,*, prompt = r'>$|#$|\$$|&g
|
||||
connect = self._connect(timeout = timeout, logger = logger)
|
||||
if connect == True:
|
||||
if logger:
|
||||
logger("success", "Connected to " + self.unique + " at " + self.host + (":" if self.port != '' else '') + self.port + " via: " + self.protocol)
|
||||
port_str = f":{self.port}" if self.port and self.protocol not in ["ssm", "kubectl", "docker"] else ""
|
||||
logger("success", f"Connected to {self.unique} at {self.host}{port_str} via: {self.protocol}")
|
||||
|
||||
# Attempt to set the terminal size
|
||||
try:
|
||||
@@ -5268,7 +5406,7 @@ def test(self, commands, expected, vars = None,*, prompt = None, parallel = 10,
|
||||
<li><h3><a href="#header-submodules">Sub-modules</a></h3>
|
||||
<ul>
|
||||
<li><code><a title="connpy.cli" href="cli/index.html">connpy.cli</a></code></li>
|
||||
<li><code><a title="connpy.grpc" href="grpc/index.html">connpy.grpc</a></code></li>
|
||||
<li><code><a title="connpy.grpc_layer" href="grpc_layer/index.html">connpy.grpc_layer</a></code></li>
|
||||
<li><code><a title="connpy.proto" href="proto/index.html">connpy.proto</a></code></li>
|
||||
<li><code><a title="connpy.services" href="services/index.html">connpy.services</a></code></li>
|
||||
<li><code><a title="connpy.tests" href="tests/index.html">connpy.tests</a></code></li>
|
||||
@@ -5331,7 +5469,7 @@ def test(self, commands, expected, vars = None,*, prompt = None, parallel = 10,
|
||||
</nav>
|
||||
</main>
|
||||
<footer id="footer">
|
||||
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.11.5</a>.</p>
|
||||
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.11.6</a>.</p>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1">
|
||||
<meta name="generator" content="pdoc3 0.11.5">
|
||||
<meta name="generator" content="pdoc3 0.11.6">
|
||||
<title>connpy.proto API documentation</title>
|
||||
<meta name="description" content="">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/13.0.0/sanitize.min.css" integrity="sha512-y1dtMcuvtTMJc1yPgEqF0ZjQbhnc/bFhyvIyVNb9Zk5mIGtqVaAB1Ttl28su8AvFMOY0EwRbAe+HCLqj6W7/KA==" crossorigin>
|
||||
@@ -60,7 +60,7 @@ el.replaceWith(d);
|
||||
</nav>
|
||||
</main>
|
||||
<footer id="footer">
|
||||
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.11.5</a>.</p>
|
||||
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.11.6</a>.</p>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1">
|
||||
<meta name="generator" content="pdoc3 0.11.5">
|
||||
<meta name="generator" content="pdoc3 0.11.6">
|
||||
<title>connpy.services.ai_service API documentation</title>
|
||||
<meta name="description" content="">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/13.0.0/sanitize.min.css" integrity="sha512-y1dtMcuvtTMJc1yPgEqF0ZjQbhnc/bFhyvIyVNb9Zk5mIGtqVaAB1Ttl28su8AvFMOY0EwRbAe+HCLqj6W7/KA==" crossorigin>
|
||||
@@ -265,7 +265,7 @@ el.replaceWith(d);
|
||||
</nav>
|
||||
</main>
|
||||
<footer id="footer">
|
||||
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.11.5</a>.</p>
|
||||
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.11.6</a>.</p>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1">
|
||||
<meta name="generator" content="pdoc3 0.11.5">
|
||||
<meta name="generator" content="pdoc3 0.11.6">
|
||||
<title>connpy.services.base API documentation</title>
|
||||
<meta name="description" content="">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/13.0.0/sanitize.min.css" integrity="sha512-y1dtMcuvtTMJc1yPgEqF0ZjQbhnc/bFhyvIyVNb9Zk5mIGtqVaAB1Ttl28su8AvFMOY0EwRbAe+HCLqj6W7/KA==" crossorigin>
|
||||
@@ -152,7 +152,7 @@ el.replaceWith(d);
|
||||
</nav>
|
||||
</main>
|
||||
<footer id="footer">
|
||||
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.11.5</a>.</p>
|
||||
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.11.6</a>.</p>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1">
|
||||
<meta name="generator" content="pdoc3 0.11.5">
|
||||
<meta name="generator" content="pdoc3 0.11.6">
|
||||
<title>connpy.services.config_service API documentation</title>
|
||||
<meta name="description" content="">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/13.0.0/sanitize.min.css" integrity="sha512-y1dtMcuvtTMJc1yPgEqF0ZjQbhnc/bFhyvIyVNb9Zk5mIGtqVaAB1Ttl28su8AvFMOY0EwRbAe+HCLqj6W7/KA==" crossorigin>
|
||||
@@ -311,7 +311,7 @@ el.replaceWith(d);
|
||||
</nav>
|
||||
</main>
|
||||
<footer id="footer">
|
||||
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.11.5</a>.</p>
|
||||
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.11.6</a>.</p>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1">
|
||||
<meta name="generator" content="pdoc3 0.11.5">
|
||||
<meta name="generator" content="pdoc3 0.11.6">
|
||||
<title>connpy.services.context_service API documentation</title>
|
||||
<meta name="description" content="">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/13.0.0/sanitize.min.css" integrity="sha512-y1dtMcuvtTMJc1yPgEqF0ZjQbhnc/bFhyvIyVNb9Zk5mIGtqVaAB1Ttl28su8AvFMOY0EwRbAe+HCLqj6W7/KA==" crossorigin>
|
||||
@@ -370,7 +370,7 @@ def current_context(self) -> str:
|
||||
</nav>
|
||||
</main>
|
||||
<footer id="footer">
|
||||
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.11.5</a>.</p>
|
||||
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.11.6</a>.</p>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1">
|
||||
<meta name="generator" content="pdoc3 0.11.5">
|
||||
<meta name="generator" content="pdoc3 0.11.6">
|
||||
<title>connpy.services.exceptions API documentation</title>
|
||||
<meta name="description" content="">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/13.0.0/sanitize.min.css" integrity="sha512-y1dtMcuvtTMJc1yPgEqF0ZjQbhnc/bFhyvIyVNb9Zk5mIGtqVaAB1Ttl28su8AvFMOY0EwRbAe+HCLqj6W7/KA==" crossorigin>
|
||||
@@ -268,7 +268,7 @@ el.replaceWith(d);
|
||||
</nav>
|
||||
</main>
|
||||
<footer id="footer">
|
||||
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.11.5</a>.</p>
|
||||
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.11.6</a>.</p>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1">
|
||||
<meta name="generator" content="pdoc3 0.11.5">
|
||||
<meta name="generator" content="pdoc3 0.11.6">
|
||||
<title>connpy.services.execution_service API documentation</title>
|
||||
<meta name="description" content="">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/13.0.0/sanitize.min.css" integrity="sha512-y1dtMcuvtTMJc1yPgEqF0ZjQbhnc/bFhyvIyVNb9Zk5mIGtqVaAB1Ttl28su8AvFMOY0EwRbAe+HCLqj6W7/KA==" crossorigin>
|
||||
@@ -395,7 +395,7 @@ el.replaceWith(d);
|
||||
</nav>
|
||||
</main>
|
||||
<footer id="footer">
|
||||
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.11.5</a>.</p>
|
||||
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.11.6</a>.</p>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1">
|
||||
<meta name="generator" content="pdoc3 0.11.5">
|
||||
<meta name="generator" content="pdoc3 0.11.6">
|
||||
<title>connpy.services.import_export_service API documentation</title>
|
||||
<meta name="description" content="">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/13.0.0/sanitize.min.css" integrity="sha512-y1dtMcuvtTMJc1yPgEqF0ZjQbhnc/bFhyvIyVNb9Zk5mIGtqVaAB1Ttl28su8AvFMOY0EwRbAe+HCLqj6W7/KA==" crossorigin>
|
||||
@@ -279,7 +279,7 @@ el.replaceWith(d);
|
||||
</nav>
|
||||
</main>
|
||||
<footer id="footer">
|
||||
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.11.5</a>.</p>
|
||||
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.11.6</a>.</p>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1">
|
||||
<meta name="generator" content="pdoc3 0.11.5">
|
||||
<meta name="generator" content="pdoc3 0.11.6">
|
||||
<title>connpy.services API documentation</title>
|
||||
<meta name="description" content="">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/13.0.0/sanitize.min.css" integrity="sha512-y1dtMcuvtTMJc1yPgEqF0ZjQbhnc/bFhyvIyVNb9Zk5mIGtqVaAB1Ttl28su8AvFMOY0EwRbAe+HCLqj6W7/KA==" crossorigin>
|
||||
@@ -1234,10 +1234,13 @@ el.replaceWith(d);
|
||||
|
||||
def get_node_details(self, unique_id):
|
||||
"""Return full configuration dictionary for a specific node."""
|
||||
details = self.config.getitem(unique_id)
|
||||
if not details:
|
||||
try:
|
||||
details = self.config.getitem(unique_id)
|
||||
if not details:
|
||||
raise NodeNotFoundError(f"Node '{unique_id}' not found.")
|
||||
return details
|
||||
except (KeyError, TypeError):
|
||||
raise NodeNotFoundError(f"Node '{unique_id}' not found.")
|
||||
return details
|
||||
|
||||
def explode_unique(self, unique_id):
|
||||
"""Explode a unique ID into a dictionary of its parts."""
|
||||
@@ -1247,6 +1250,14 @@ el.replaceWith(d);
|
||||
"""Generate and update the internal nodes cache."""
|
||||
self.config._generate_nodes_cache(nodes=nodes, folders=folders, profiles=profiles)
|
||||
|
||||
def validate_parent_folder(self, unique_id):
|
||||
"""Check if parent folder exists for a given node unique ID."""
|
||||
node_folder = unique_id.partition("@")[2]
|
||||
if node_folder:
|
||||
parent_folder = f"@{node_folder}"
|
||||
if parent_folder not in self.config._getallfolders():
|
||||
raise NodeNotFoundError(f"Folder '{parent_folder}' not found.")
|
||||
|
||||
|
||||
def add_node(self, unique_id, data, is_folder=False):
|
||||
"""Logic for adding a new node or folder to configuration."""
|
||||
@@ -1265,9 +1276,7 @@ el.replaceWith(d);
|
||||
|
||||
# Check if parent folder exists when creating a subfolder
|
||||
if "subfolder" in uniques:
|
||||
parent_folder = f"@{uniques['folder']}"
|
||||
if parent_folder not in all_folders:
|
||||
raise NodeNotFoundError(f"Folder '{parent_folder}' not found.")
|
||||
self.validate_parent_folder(unique_id)
|
||||
|
||||
self.config._folder_add(**uniques)
|
||||
self.config._saveconfig(self.config.file)
|
||||
@@ -1276,11 +1285,7 @@ el.replaceWith(d);
|
||||
raise NodeAlreadyExistsError(f"Node '{unique_id}' already exists.")
|
||||
|
||||
# Check if parent folder exists when creating a node in a folder
|
||||
node_folder = unique_id.partition("@")[2]
|
||||
if node_folder:
|
||||
parent_folder = f"@{node_folder}"
|
||||
if parent_folder not in all_folders:
|
||||
raise NodeNotFoundError(f"Folder '{parent_folder}' not found.")
|
||||
self.validate_parent_folder(unique_id)
|
||||
|
||||
# Ensure 'id' is in data for config._connections_add
|
||||
if "id" not in data:
|
||||
@@ -1453,9 +1458,7 @@ el.replaceWith(d);
|
||||
|
||||
# Check if parent folder exists when creating a subfolder
|
||||
if "subfolder" in uniques:
|
||||
parent_folder = f"@{uniques['folder']}"
|
||||
if parent_folder not in all_folders:
|
||||
raise NodeNotFoundError(f"Folder '{parent_folder}' not found.")
|
||||
self.validate_parent_folder(unique_id)
|
||||
|
||||
self.config._folder_add(**uniques)
|
||||
self.config._saveconfig(self.config.file)
|
||||
@@ -1464,11 +1467,7 @@ el.replaceWith(d);
|
||||
raise NodeAlreadyExistsError(f"Node '{unique_id}' already exists.")
|
||||
|
||||
# Check if parent folder exists when creating a node in a folder
|
||||
node_folder = unique_id.partition("@")[2]
|
||||
if node_folder:
|
||||
parent_folder = f"@{node_folder}"
|
||||
if parent_folder not in all_folders:
|
||||
raise NodeNotFoundError(f"Folder '{parent_folder}' not found.")
|
||||
self.validate_parent_folder(unique_id)
|
||||
|
||||
# Ensure 'id' is in data for config._connections_add
|
||||
if "id" not in data:
|
||||
@@ -1651,10 +1650,13 @@ el.replaceWith(d);
|
||||
</summary>
|
||||
<pre><code class="python">def get_node_details(self, unique_id):
|
||||
"""Return full configuration dictionary for a specific node."""
|
||||
details = self.config.getitem(unique_id)
|
||||
if not details:
|
||||
raise NodeNotFoundError(f"Node '{unique_id}' not found.")
|
||||
return details</code></pre>
|
||||
try:
|
||||
details = self.config.getitem(unique_id)
|
||||
if not details:
|
||||
raise NodeNotFoundError(f"Node '{unique_id}' not found.")
|
||||
return details
|
||||
except (KeyError, TypeError):
|
||||
raise NodeNotFoundError(f"Node '{unique_id}' not found.")</code></pre>
|
||||
</details>
|
||||
<div class="desc"><p>Return full configuration dictionary for a specific node.</p></div>
|
||||
</dd>
|
||||
@@ -1801,6 +1803,24 @@ el.replaceWith(d);
|
||||
</details>
|
||||
<div class="desc"><p>Explicitly update an existing node.</p></div>
|
||||
</dd>
|
||||
<dt id="connpy.services.NodeService.validate_parent_folder"><code class="name flex">
|
||||
<span>def <span class="ident">validate_parent_folder</span></span>(<span>self, unique_id)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def validate_parent_folder(self, unique_id):
|
||||
"""Check if parent folder exists for a given node unique ID."""
|
||||
node_folder = unique_id.partition("@")[2]
|
||||
if node_folder:
|
||||
parent_folder = f"@{node_folder}"
|
||||
if parent_folder not in self.config._getallfolders():
|
||||
raise NodeNotFoundError(f"Folder '{parent_folder}' not found.")</code></pre>
|
||||
</details>
|
||||
<div class="desc"><p>Check if parent folder exists for a given node unique ID.</p></div>
|
||||
</dd>
|
||||
</dl>
|
||||
<h3>Inherited members</h3>
|
||||
<ul class="hlist">
|
||||
@@ -1996,6 +2016,7 @@ el.replaceWith(d);
|
||||
from ..services.exceptions import InvalidConfigurationError
|
||||
from connpy.plugins import Plugins
|
||||
class MockApp:
|
||||
is_mock = True
|
||||
def __init__(self, config):
|
||||
from ..core import node, nodes
|
||||
from ..ai import ai
|
||||
@@ -2007,14 +2028,20 @@ el.replaceWith(d);
|
||||
self.ai = ai
|
||||
|
||||
self.services = ServiceProvider(config, mode="local")
|
||||
|
||||
# Get settings for CLI behavior
|
||||
settings = self.services.config_svc.get_settings()
|
||||
self.case = settings.get("case", False)
|
||||
self.fzf = settings.get("fzf", False)
|
||||
|
||||
try:
|
||||
self.nodes_list = self.services.nodes.list_nodes()
|
||||
self.folders = self.services.nodes.list_folders()
|
||||
self.profiles = self.services.profiles.list_profiles()
|
||||
except Exception:
|
||||
self.nodes_list = {}
|
||||
self.folders = {}
|
||||
self.profiles = {}
|
||||
self.nodes_list = []
|
||||
self.folders = []
|
||||
self.profiles = []
|
||||
|
||||
args = Namespace(**args_dict)
|
||||
|
||||
@@ -2041,26 +2068,26 @@ el.replaceWith(d);
|
||||
from .. import printer
|
||||
from rich.console import Console
|
||||
|
||||
from rich.console import Console
|
||||
buf = io.StringIO()
|
||||
old_console = printer.console
|
||||
old_err_console = printer.err_console
|
||||
old_console = printer._get_console()
|
||||
old_err_console = printer._get_err_console()
|
||||
|
||||
printer.console = Console(file=buf, theme=printer.connpy_theme, force_terminal=True)
|
||||
printer.err_console = Console(file=buf, theme=printer.connpy_theme, force_terminal=True)
|
||||
|
||||
old_stdout = sys.stdout
|
||||
sys.stdout = buf
|
||||
printer.set_thread_console(Console(file=buf, theme=printer.connpy_theme, force_terminal=True))
|
||||
printer.set_thread_err_console(Console(file=buf, theme=printer.connpy_theme, force_terminal=True))
|
||||
printer.set_thread_stream(buf)
|
||||
|
||||
try:
|
||||
if hasattr(module, "Entrypoint"):
|
||||
module.Entrypoint(args, parser, app)
|
||||
except Exception as e:
|
||||
import traceback
|
||||
printer.err_console.print(traceback.format_exc())
|
||||
except BaseException as e:
|
||||
if not isinstance(e, SystemExit):
|
||||
import traceback
|
||||
printer.err_console.print(traceback.format_exc())
|
||||
finally:
|
||||
sys.stdout = old_stdout
|
||||
printer.console = old_console
|
||||
printer.err_console = old_err_console
|
||||
printer.set_thread_console(old_console)
|
||||
printer.set_thread_err_console(old_err_console)
|
||||
printer.set_thread_stream(None)
|
||||
|
||||
for line in buf.getvalue().splitlines(keepends=True):
|
||||
yield line</code></pre>
|
||||
@@ -2265,6 +2292,7 @@ el.replaceWith(d);
|
||||
from ..services.exceptions import InvalidConfigurationError
|
||||
from connpy.plugins import Plugins
|
||||
class MockApp:
|
||||
is_mock = True
|
||||
def __init__(self, config):
|
||||
from ..core import node, nodes
|
||||
from ..ai import ai
|
||||
@@ -2276,14 +2304,20 @@ el.replaceWith(d);
|
||||
self.ai = ai
|
||||
|
||||
self.services = ServiceProvider(config, mode="local")
|
||||
|
||||
# Get settings for CLI behavior
|
||||
settings = self.services.config_svc.get_settings()
|
||||
self.case = settings.get("case", False)
|
||||
self.fzf = settings.get("fzf", False)
|
||||
|
||||
try:
|
||||
self.nodes_list = self.services.nodes.list_nodes()
|
||||
self.folders = self.services.nodes.list_folders()
|
||||
self.profiles = self.services.profiles.list_profiles()
|
||||
except Exception:
|
||||
self.nodes_list = {}
|
||||
self.folders = {}
|
||||
self.profiles = {}
|
||||
self.nodes_list = []
|
||||
self.folders = []
|
||||
self.profiles = []
|
||||
|
||||
args = Namespace(**args_dict)
|
||||
|
||||
@@ -2310,26 +2344,26 @@ el.replaceWith(d);
|
||||
from .. import printer
|
||||
from rich.console import Console
|
||||
|
||||
from rich.console import Console
|
||||
buf = io.StringIO()
|
||||
old_console = printer.console
|
||||
old_err_console = printer.err_console
|
||||
old_console = printer._get_console()
|
||||
old_err_console = printer._get_err_console()
|
||||
|
||||
printer.console = Console(file=buf, theme=printer.connpy_theme, force_terminal=True)
|
||||
printer.err_console = Console(file=buf, theme=printer.connpy_theme, force_terminal=True)
|
||||
|
||||
old_stdout = sys.stdout
|
||||
sys.stdout = buf
|
||||
printer.set_thread_console(Console(file=buf, theme=printer.connpy_theme, force_terminal=True))
|
||||
printer.set_thread_err_console(Console(file=buf, theme=printer.connpy_theme, force_terminal=True))
|
||||
printer.set_thread_stream(buf)
|
||||
|
||||
try:
|
||||
if hasattr(module, "Entrypoint"):
|
||||
module.Entrypoint(args, parser, app)
|
||||
except Exception as e:
|
||||
import traceback
|
||||
printer.err_console.print(traceback.format_exc())
|
||||
except BaseException as e:
|
||||
if not isinstance(e, SystemExit):
|
||||
import traceback
|
||||
printer.err_console.print(traceback.format_exc())
|
||||
finally:
|
||||
sys.stdout = old_stdout
|
||||
printer.console = old_console
|
||||
printer.err_console = old_err_console
|
||||
printer.set_thread_console(old_console)
|
||||
printer.set_thread_err_console(old_err_console)
|
||||
printer.set_thread_stream(None)
|
||||
|
||||
for line in buf.getvalue().splitlines(keepends=True):
|
||||
yield line</code></pre>
|
||||
@@ -3118,7 +3152,7 @@ el.replaceWith(d);
|
||||
</li>
|
||||
<li>
|
||||
<h4><code><a title="connpy.services.NodeService" href="#connpy.services.NodeService">NodeService</a></code></h4>
|
||||
<ul class="two-column">
|
||||
<ul class="">
|
||||
<li><code><a title="connpy.services.NodeService.add_node" href="#connpy.services.NodeService.add_node">add_node</a></code></li>
|
||||
<li><code><a title="connpy.services.NodeService.bulk_add" href="#connpy.services.NodeService.bulk_add">bulk_add</a></code></li>
|
||||
<li><code><a title="connpy.services.NodeService.connect_node" href="#connpy.services.NodeService.connect_node">connect_node</a></code></li>
|
||||
@@ -3132,6 +3166,7 @@ el.replaceWith(d);
|
||||
<li><code><a title="connpy.services.NodeService.list_nodes" href="#connpy.services.NodeService.list_nodes">list_nodes</a></code></li>
|
||||
<li><code><a title="connpy.services.NodeService.move_node" href="#connpy.services.NodeService.move_node">move_node</a></code></li>
|
||||
<li><code><a title="connpy.services.NodeService.update_node" href="#connpy.services.NodeService.update_node">update_node</a></code></li>
|
||||
<li><code><a title="connpy.services.NodeService.validate_parent_folder" href="#connpy.services.NodeService.validate_parent_folder">validate_parent_folder</a></code></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>
|
||||
@@ -3180,7 +3215,7 @@ el.replaceWith(d);
|
||||
</nav>
|
||||
</main>
|
||||
<footer id="footer">
|
||||
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.11.5</a>.</p>
|
||||
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.11.6</a>.</p>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1">
|
||||
<meta name="generator" content="pdoc3 0.11.5">
|
||||
<meta name="generator" content="pdoc3 0.11.6">
|
||||
<title>connpy.services.node_service API documentation</title>
|
||||
<meta name="description" content="">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/13.0.0/sanitize.min.css" integrity="sha512-y1dtMcuvtTMJc1yPgEqF0ZjQbhnc/bFhyvIyVNb9Zk5mIGtqVaAB1Ttl28su8AvFMOY0EwRbAe+HCLqj6W7/KA==" crossorigin>
|
||||
@@ -123,10 +123,13 @@ el.replaceWith(d);
|
||||
|
||||
def get_node_details(self, unique_id):
|
||||
"""Return full configuration dictionary for a specific node."""
|
||||
details = self.config.getitem(unique_id)
|
||||
if not details:
|
||||
try:
|
||||
details = self.config.getitem(unique_id)
|
||||
if not details:
|
||||
raise NodeNotFoundError(f"Node '{unique_id}' not found.")
|
||||
return details
|
||||
except (KeyError, TypeError):
|
||||
raise NodeNotFoundError(f"Node '{unique_id}' not found.")
|
||||
return details
|
||||
|
||||
def explode_unique(self, unique_id):
|
||||
"""Explode a unique ID into a dictionary of its parts."""
|
||||
@@ -136,6 +139,14 @@ el.replaceWith(d);
|
||||
"""Generate and update the internal nodes cache."""
|
||||
self.config._generate_nodes_cache(nodes=nodes, folders=folders, profiles=profiles)
|
||||
|
||||
def validate_parent_folder(self, unique_id):
|
||||
"""Check if parent folder exists for a given node unique ID."""
|
||||
node_folder = unique_id.partition("@")[2]
|
||||
if node_folder:
|
||||
parent_folder = f"@{node_folder}"
|
||||
if parent_folder not in self.config._getallfolders():
|
||||
raise NodeNotFoundError(f"Folder '{parent_folder}' not found.")
|
||||
|
||||
|
||||
def add_node(self, unique_id, data, is_folder=False):
|
||||
"""Logic for adding a new node or folder to configuration."""
|
||||
@@ -154,9 +165,7 @@ el.replaceWith(d);
|
||||
|
||||
# Check if parent folder exists when creating a subfolder
|
||||
if "subfolder" in uniques:
|
||||
parent_folder = f"@{uniques['folder']}"
|
||||
if parent_folder not in all_folders:
|
||||
raise NodeNotFoundError(f"Folder '{parent_folder}' not found.")
|
||||
self.validate_parent_folder(unique_id)
|
||||
|
||||
self.config._folder_add(**uniques)
|
||||
self.config._saveconfig(self.config.file)
|
||||
@@ -165,11 +174,7 @@ el.replaceWith(d);
|
||||
raise NodeAlreadyExistsError(f"Node '{unique_id}' already exists.")
|
||||
|
||||
# Check if parent folder exists when creating a node in a folder
|
||||
node_folder = unique_id.partition("@")[2]
|
||||
if node_folder:
|
||||
parent_folder = f"@{node_folder}"
|
||||
if parent_folder not in all_folders:
|
||||
raise NodeNotFoundError(f"Folder '{parent_folder}' not found.")
|
||||
self.validate_parent_folder(unique_id)
|
||||
|
||||
# Ensure 'id' is in data for config._connections_add
|
||||
if "id" not in data:
|
||||
@@ -342,9 +347,7 @@ el.replaceWith(d);
|
||||
|
||||
# Check if parent folder exists when creating a subfolder
|
||||
if "subfolder" in uniques:
|
||||
parent_folder = f"@{uniques['folder']}"
|
||||
if parent_folder not in all_folders:
|
||||
raise NodeNotFoundError(f"Folder '{parent_folder}' not found.")
|
||||
self.validate_parent_folder(unique_id)
|
||||
|
||||
self.config._folder_add(**uniques)
|
||||
self.config._saveconfig(self.config.file)
|
||||
@@ -353,11 +356,7 @@ el.replaceWith(d);
|
||||
raise NodeAlreadyExistsError(f"Node '{unique_id}' already exists.")
|
||||
|
||||
# Check if parent folder exists when creating a node in a folder
|
||||
node_folder = unique_id.partition("@")[2]
|
||||
if node_folder:
|
||||
parent_folder = f"@{node_folder}"
|
||||
if parent_folder not in all_folders:
|
||||
raise NodeNotFoundError(f"Folder '{parent_folder}' not found.")
|
||||
self.validate_parent_folder(unique_id)
|
||||
|
||||
# Ensure 'id' is in data for config._connections_add
|
||||
if "id" not in data:
|
||||
@@ -540,10 +539,13 @@ el.replaceWith(d);
|
||||
</summary>
|
||||
<pre><code class="python">def get_node_details(self, unique_id):
|
||||
"""Return full configuration dictionary for a specific node."""
|
||||
details = self.config.getitem(unique_id)
|
||||
if not details:
|
||||
raise NodeNotFoundError(f"Node '{unique_id}' not found.")
|
||||
return details</code></pre>
|
||||
try:
|
||||
details = self.config.getitem(unique_id)
|
||||
if not details:
|
||||
raise NodeNotFoundError(f"Node '{unique_id}' not found.")
|
||||
return details
|
||||
except (KeyError, TypeError):
|
||||
raise NodeNotFoundError(f"Node '{unique_id}' not found.")</code></pre>
|
||||
</details>
|
||||
<div class="desc"><p>Return full configuration dictionary for a specific node.</p></div>
|
||||
</dd>
|
||||
@@ -690,6 +692,24 @@ el.replaceWith(d);
|
||||
</details>
|
||||
<div class="desc"><p>Explicitly update an existing node.</p></div>
|
||||
</dd>
|
||||
<dt id="connpy.services.node_service.NodeService.validate_parent_folder"><code class="name flex">
|
||||
<span>def <span class="ident">validate_parent_folder</span></span>(<span>self, unique_id)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def validate_parent_folder(self, unique_id):
|
||||
"""Check if parent folder exists for a given node unique ID."""
|
||||
node_folder = unique_id.partition("@")[2]
|
||||
if node_folder:
|
||||
parent_folder = f"@{node_folder}"
|
||||
if parent_folder not in self.config._getallfolders():
|
||||
raise NodeNotFoundError(f"Folder '{parent_folder}' not found.")</code></pre>
|
||||
</details>
|
||||
<div class="desc"><p>Check if parent folder exists for a given node unique ID.</p></div>
|
||||
</dd>
|
||||
</dl>
|
||||
<h3>Inherited members</h3>
|
||||
<ul class="hlist">
|
||||
@@ -717,7 +737,7 @@ el.replaceWith(d);
|
||||
<ul>
|
||||
<li>
|
||||
<h4><code><a title="connpy.services.node_service.NodeService" href="#connpy.services.node_service.NodeService">NodeService</a></code></h4>
|
||||
<ul class="two-column">
|
||||
<ul class="">
|
||||
<li><code><a title="connpy.services.node_service.NodeService.add_node" href="#connpy.services.node_service.NodeService.add_node">add_node</a></code></li>
|
||||
<li><code><a title="connpy.services.node_service.NodeService.bulk_add" href="#connpy.services.node_service.NodeService.bulk_add">bulk_add</a></code></li>
|
||||
<li><code><a title="connpy.services.node_service.NodeService.connect_node" href="#connpy.services.node_service.NodeService.connect_node">connect_node</a></code></li>
|
||||
@@ -731,6 +751,7 @@ el.replaceWith(d);
|
||||
<li><code><a title="connpy.services.node_service.NodeService.list_nodes" href="#connpy.services.node_service.NodeService.list_nodes">list_nodes</a></code></li>
|
||||
<li><code><a title="connpy.services.node_service.NodeService.move_node" href="#connpy.services.node_service.NodeService.move_node">move_node</a></code></li>
|
||||
<li><code><a title="connpy.services.node_service.NodeService.update_node" href="#connpy.services.node_service.NodeService.update_node">update_node</a></code></li>
|
||||
<li><code><a title="connpy.services.node_service.NodeService.validate_parent_folder" href="#connpy.services.node_service.NodeService.validate_parent_folder">validate_parent_folder</a></code></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
@@ -739,7 +760,7 @@ el.replaceWith(d);
|
||||
</nav>
|
||||
</main>
|
||||
<footer id="footer">
|
||||
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.11.5</a>.</p>
|
||||
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.11.6</a>.</p>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1">
|
||||
<meta name="generator" content="pdoc3 0.11.5">
|
||||
<meta name="generator" content="pdoc3 0.11.6">
|
||||
<title>connpy.services.plugin_service API documentation</title>
|
||||
<meta name="description" content="">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/13.0.0/sanitize.min.css" integrity="sha512-y1dtMcuvtTMJc1yPgEqF0ZjQbhnc/bFhyvIyVNb9Zk5mIGtqVaAB1Ttl28su8AvFMOY0EwRbAe+HCLqj6W7/KA==" crossorigin>
|
||||
@@ -231,6 +231,7 @@ el.replaceWith(d);
|
||||
from ..services.exceptions import InvalidConfigurationError
|
||||
from connpy.plugins import Plugins
|
||||
class MockApp:
|
||||
is_mock = True
|
||||
def __init__(self, config):
|
||||
from ..core import node, nodes
|
||||
from ..ai import ai
|
||||
@@ -242,14 +243,20 @@ el.replaceWith(d);
|
||||
self.ai = ai
|
||||
|
||||
self.services = ServiceProvider(config, mode="local")
|
||||
|
||||
# Get settings for CLI behavior
|
||||
settings = self.services.config_svc.get_settings()
|
||||
self.case = settings.get("case", False)
|
||||
self.fzf = settings.get("fzf", False)
|
||||
|
||||
try:
|
||||
self.nodes_list = self.services.nodes.list_nodes()
|
||||
self.folders = self.services.nodes.list_folders()
|
||||
self.profiles = self.services.profiles.list_profiles()
|
||||
except Exception:
|
||||
self.nodes_list = {}
|
||||
self.folders = {}
|
||||
self.profiles = {}
|
||||
self.nodes_list = []
|
||||
self.folders = []
|
||||
self.profiles = []
|
||||
|
||||
args = Namespace(**args_dict)
|
||||
|
||||
@@ -276,26 +283,26 @@ el.replaceWith(d);
|
||||
from .. import printer
|
||||
from rich.console import Console
|
||||
|
||||
from rich.console import Console
|
||||
buf = io.StringIO()
|
||||
old_console = printer.console
|
||||
old_err_console = printer.err_console
|
||||
old_console = printer._get_console()
|
||||
old_err_console = printer._get_err_console()
|
||||
|
||||
printer.console = Console(file=buf, theme=printer.connpy_theme, force_terminal=True)
|
||||
printer.err_console = Console(file=buf, theme=printer.connpy_theme, force_terminal=True)
|
||||
|
||||
old_stdout = sys.stdout
|
||||
sys.stdout = buf
|
||||
printer.set_thread_console(Console(file=buf, theme=printer.connpy_theme, force_terminal=True))
|
||||
printer.set_thread_err_console(Console(file=buf, theme=printer.connpy_theme, force_terminal=True))
|
||||
printer.set_thread_stream(buf)
|
||||
|
||||
try:
|
||||
if hasattr(module, "Entrypoint"):
|
||||
module.Entrypoint(args, parser, app)
|
||||
except Exception as e:
|
||||
import traceback
|
||||
printer.err_console.print(traceback.format_exc())
|
||||
except BaseException as e:
|
||||
if not isinstance(e, SystemExit):
|
||||
import traceback
|
||||
printer.err_console.print(traceback.format_exc())
|
||||
finally:
|
||||
sys.stdout = old_stdout
|
||||
printer.console = old_console
|
||||
printer.err_console = old_err_console
|
||||
printer.set_thread_console(old_console)
|
||||
printer.set_thread_err_console(old_err_console)
|
||||
printer.set_thread_stream(None)
|
||||
|
||||
for line in buf.getvalue().splitlines(keepends=True):
|
||||
yield line</code></pre>
|
||||
@@ -500,6 +507,7 @@ el.replaceWith(d);
|
||||
from ..services.exceptions import InvalidConfigurationError
|
||||
from connpy.plugins import Plugins
|
||||
class MockApp:
|
||||
is_mock = True
|
||||
def __init__(self, config):
|
||||
from ..core import node, nodes
|
||||
from ..ai import ai
|
||||
@@ -511,14 +519,20 @@ el.replaceWith(d);
|
||||
self.ai = ai
|
||||
|
||||
self.services = ServiceProvider(config, mode="local")
|
||||
|
||||
# Get settings for CLI behavior
|
||||
settings = self.services.config_svc.get_settings()
|
||||
self.case = settings.get("case", False)
|
||||
self.fzf = settings.get("fzf", False)
|
||||
|
||||
try:
|
||||
self.nodes_list = self.services.nodes.list_nodes()
|
||||
self.folders = self.services.nodes.list_folders()
|
||||
self.profiles = self.services.profiles.list_profiles()
|
||||
except Exception:
|
||||
self.nodes_list = {}
|
||||
self.folders = {}
|
||||
self.profiles = {}
|
||||
self.nodes_list = []
|
||||
self.folders = []
|
||||
self.profiles = []
|
||||
|
||||
args = Namespace(**args_dict)
|
||||
|
||||
@@ -545,26 +559,26 @@ el.replaceWith(d);
|
||||
from .. import printer
|
||||
from rich.console import Console
|
||||
|
||||
from rich.console import Console
|
||||
buf = io.StringIO()
|
||||
old_console = printer.console
|
||||
old_err_console = printer.err_console
|
||||
old_console = printer._get_console()
|
||||
old_err_console = printer._get_err_console()
|
||||
|
||||
printer.console = Console(file=buf, theme=printer.connpy_theme, force_terminal=True)
|
||||
printer.err_console = Console(file=buf, theme=printer.connpy_theme, force_terminal=True)
|
||||
|
||||
old_stdout = sys.stdout
|
||||
sys.stdout = buf
|
||||
printer.set_thread_console(Console(file=buf, theme=printer.connpy_theme, force_terminal=True))
|
||||
printer.set_thread_err_console(Console(file=buf, theme=printer.connpy_theme, force_terminal=True))
|
||||
printer.set_thread_stream(buf)
|
||||
|
||||
try:
|
||||
if hasattr(module, "Entrypoint"):
|
||||
module.Entrypoint(args, parser, app)
|
||||
except Exception as e:
|
||||
import traceback
|
||||
printer.err_console.print(traceback.format_exc())
|
||||
except BaseException as e:
|
||||
if not isinstance(e, SystemExit):
|
||||
import traceback
|
||||
printer.err_console.print(traceback.format_exc())
|
||||
finally:
|
||||
sys.stdout = old_stdout
|
||||
printer.console = old_console
|
||||
printer.err_console = old_err_console
|
||||
printer.set_thread_console(old_console)
|
||||
printer.set_thread_err_console(old_err_console)
|
||||
printer.set_thread_stream(None)
|
||||
|
||||
for line in buf.getvalue().splitlines(keepends=True):
|
||||
yield line</code></pre>
|
||||
@@ -657,7 +671,7 @@ el.replaceWith(d);
|
||||
</nav>
|
||||
</main>
|
||||
<footer id="footer">
|
||||
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.11.5</a>.</p>
|
||||
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.11.6</a>.</p>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1">
|
||||
<meta name="generator" content="pdoc3 0.11.5">
|
||||
<meta name="generator" content="pdoc3 0.11.6">
|
||||
<title>connpy.services.profile_service API documentation</title>
|
||||
<meta name="description" content="">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/13.0.0/sanitize.min.css" integrity="sha512-y1dtMcuvtTMJc1yPgEqF0ZjQbhnc/bFhyvIyVNb9Zk5mIGtqVaAB1Ttl28su8AvFMOY0EwRbAe+HCLqj6W7/KA==" crossorigin>
|
||||
@@ -429,7 +429,7 @@ el.replaceWith(d);
|
||||
</nav>
|
||||
</main>
|
||||
<footer id="footer">
|
||||
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.11.5</a>.</p>
|
||||
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.11.6</a>.</p>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1">
|
||||
<meta name="generator" content="pdoc3 0.11.5">
|
||||
<meta name="generator" content="pdoc3 0.11.6">
|
||||
<title>connpy.services.provider API documentation</title>
|
||||
<meta name="description" content="">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/13.0.0/sanitize.min.css" integrity="sha512-y1dtMcuvtTMJc1yPgEqF0ZjQbhnc/bFhyvIyVNb9Zk5mIGtqVaAB1Ttl28su8AvFMOY0EwRbAe+HCLqj6W7/KA==" crossorigin>
|
||||
@@ -123,7 +123,7 @@ el.replaceWith(d);
|
||||
raise InvalidConfigurationError("Remote host must be specified in remote mode")
|
||||
|
||||
import grpc
|
||||
from ..grpc.stubs import NodeStub, ProfileStub, PluginStub, AIStub, ExecutionStub, ImportExportStub, SystemStub
|
||||
from ..grpc_layer.stubs import NodeStub, ProfileStub, PluginStub, AIStub, ExecutionStub, ImportExportStub, SystemStub
|
||||
|
||||
channel = grpc.insecure_channel(self.remote_host)
|
||||
|
||||
@@ -164,7 +164,7 @@ el.replaceWith(d);
|
||||
</nav>
|
||||
</main>
|
||||
<footer id="footer">
|
||||
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.11.5</a>.</p>
|
||||
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.11.6</a>.</p>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1">
|
||||
<meta name="generator" content="pdoc3 0.11.5">
|
||||
<meta name="generator" content="pdoc3 0.11.6">
|
||||
<title>connpy.services.sync_service API documentation</title>
|
||||
<meta name="description" content="">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/13.0.0/sanitize.min.css" integrity="sha512-y1dtMcuvtTMJc1yPgEqF0ZjQbhnc/bFhyvIyVNb9Zk5mIGtqVaAB1Ttl28su8AvFMOY0EwRbAe+HCLqj6W7/KA==" crossorigin>
|
||||
@@ -195,9 +195,9 @@ el.replaceWith(d);
|
||||
if os.path.exists(self.config.key):
|
||||
zipf.write(self.config.key, ".osk")
|
||||
|
||||
# Manage retention (max 10 backups)
|
||||
# Manage retention (max 100 backups)
|
||||
backups = self.list_backups()
|
||||
if len(backups) >= 10:
|
||||
if len(backups) >= 100:
|
||||
oldest = min(backups, key=lambda x: x['timestamp'] or '0')
|
||||
self.delete_backup(oldest['id'])
|
||||
|
||||
@@ -398,7 +398,7 @@ el.replaceWith(d);
|
||||
|
||||
if not sync_enabled: return
|
||||
|
||||
printer.info("Triggering auto-sync...")
|
||||
|
||||
if self.check_login_status() != True:
|
||||
printer.warning("Auto-sync: Not logged in to Google Drive.")
|
||||
return
|
||||
@@ -549,9 +549,9 @@ el.replaceWith(d);
|
||||
if os.path.exists(self.config.key):
|
||||
zipf.write(self.config.key, ".osk")
|
||||
|
||||
# Manage retention (max 10 backups)
|
||||
# Manage retention (max 100 backups)
|
||||
backups = self.list_backups()
|
||||
if len(backups) >= 10:
|
||||
if len(backups) >= 100:
|
||||
oldest = min(backups, key=lambda x: x['timestamp'] or '0')
|
||||
self.delete_backup(oldest['id'])
|
||||
|
||||
@@ -819,7 +819,7 @@ el.replaceWith(d);
|
||||
|
||||
if not sync_enabled: return
|
||||
|
||||
printer.info("Triggering auto-sync...")
|
||||
|
||||
if self.check_login_status() != True:
|
||||
printer.warning("Auto-sync: Not logged in to Google Drive.")
|
||||
return
|
||||
@@ -964,7 +964,7 @@ el.replaceWith(d);
|
||||
</nav>
|
||||
</main>
|
||||
<footer id="footer">
|
||||
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.11.5</a>.</p>
|
||||
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.11.6</a>.</p>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1">
|
||||
<meta name="generator" content="pdoc3 0.11.5">
|
||||
<meta name="generator" content="pdoc3 0.11.6">
|
||||
<title>connpy.services.system_service API documentation</title>
|
||||
<meta name="description" content="">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/13.0.0/sanitize.min.css" integrity="sha512-y1dtMcuvtTMJc1yPgEqF0ZjQbhnc/bFhyvIyVNb9Zk5mIGtqVaAB1Ttl28su8AvFMOY0EwRbAe+HCLqj6W7/KA==" crossorigin>
|
||||
@@ -325,7 +325,7 @@ el.replaceWith(d);
|
||||
</nav>
|
||||
</main>
|
||||
<footer id="footer">
|
||||
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.11.5</a>.</p>
|
||||
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.11.6</a>.</p>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1">
|
||||
<meta name="generator" content="pdoc3 0.11.5">
|
||||
<meta name="generator" content="pdoc3 0.11.6">
|
||||
<title>connpy.tests.conftest API documentation</title>
|
||||
<meta name="description" content="Shared fixtures for connpy tests …">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/13.0.0/sanitize.min.css" integrity="sha512-y1dtMcuvtTMJc1yPgEqF0ZjQbhnc/bFhyvIyVNb9Zk5mIGtqVaAB1Ttl28su8AvFMOY0EwRbAe+HCLqj6W7/KA==" crossorigin>
|
||||
@@ -258,7 +258,7 @@ def tmp_config_dir(tmp_path):
|
||||
</nav>
|
||||
</main>
|
||||
<footer id="footer">
|
||||
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.11.5</a>.</p>
|
||||
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.11.6</a>.</p>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1">
|
||||
<meta name="generator" content="pdoc3 0.11.5">
|
||||
<meta name="generator" content="pdoc3 0.11.6">
|
||||
<title>connpy.tests API documentation</title>
|
||||
<meta name="description" content="">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/13.0.0/sanitize.min.css" integrity="sha512-y1dtMcuvtTMJc1yPgEqF0ZjQbhnc/bFhyvIyVNb9Zk5mIGtqVaAB1Ttl28su8AvFMOY0EwRbAe+HCLqj6W7/KA==" crossorigin>
|
||||
@@ -72,6 +72,10 @@ el.replaceWith(d);
|
||||
<dd>
|
||||
<div class="desc"></div>
|
||||
</dd>
|
||||
<dt><code class="name"><a title="connpy.tests.test_grpc_layer" href="test_grpc_layer.html">connpy.tests.test_grpc_layer</a></code></dt>
|
||||
<dd>
|
||||
<div class="desc"></div>
|
||||
</dd>
|
||||
<dt><code class="name"><a title="connpy.tests.test_hooks" href="test_hooks.html">connpy.tests.test_hooks</a></code></dt>
|
||||
<dd>
|
||||
<div class="desc"><p>Tests for connpy.hooks module — MethodHook and ClassHook.</p></div>
|
||||
@@ -88,6 +92,10 @@ el.replaceWith(d);
|
||||
<dd>
|
||||
<div class="desc"><p>Tests for connpy.printer module.</p></div>
|
||||
</dd>
|
||||
<dt><code class="name"><a title="connpy.tests.test_printer_concurrency" href="test_printer_concurrency.html">connpy.tests.test_printer_concurrency</a></code></dt>
|
||||
<dd>
|
||||
<div class="desc"></div>
|
||||
</dd>
|
||||
<dt><code class="name"><a title="connpy.tests.test_profile_service" href="test_profile_service.html">connpy.tests.test_profile_service</a></code></dt>
|
||||
<dd>
|
||||
<div class="desc"></div>
|
||||
@@ -129,10 +137,12 @@ el.replaceWith(d);
|
||||
<li><code><a title="connpy.tests.test_connapp" href="test_connapp.html">connpy.tests.test_connapp</a></code></li>
|
||||
<li><code><a title="connpy.tests.test_core" href="test_core.html">connpy.tests.test_core</a></code></li>
|
||||
<li><code><a title="connpy.tests.test_execution_service" href="test_execution_service.html">connpy.tests.test_execution_service</a></code></li>
|
||||
<li><code><a title="connpy.tests.test_grpc_layer" href="test_grpc_layer.html">connpy.tests.test_grpc_layer</a></code></li>
|
||||
<li><code><a title="connpy.tests.test_hooks" href="test_hooks.html">connpy.tests.test_hooks</a></code></li>
|
||||
<li><code><a title="connpy.tests.test_node_service" href="test_node_service.html">connpy.tests.test_node_service</a></code></li>
|
||||
<li><code><a title="connpy.tests.test_plugins" href="test_plugins.html">connpy.tests.test_plugins</a></code></li>
|
||||
<li><code><a title="connpy.tests.test_printer" href="test_printer.html">connpy.tests.test_printer</a></code></li>
|
||||
<li><code><a title="connpy.tests.test_printer_concurrency" href="test_printer_concurrency.html">connpy.tests.test_printer_concurrency</a></code></li>
|
||||
<li><code><a title="connpy.tests.test_profile_service" href="test_profile_service.html">connpy.tests.test_profile_service</a></code></li>
|
||||
<li><code><a title="connpy.tests.test_provider" href="test_provider.html">connpy.tests.test_provider</a></code></li>
|
||||
<li><code><a title="connpy.tests.test_sync" href="test_sync.html">connpy.tests.test_sync</a></code></li>
|
||||
@@ -142,7 +152,7 @@ el.replaceWith(d);
|
||||
</nav>
|
||||
</main>
|
||||
<footer id="footer">
|
||||
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.11.5</a>.</p>
|
||||
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.11.6</a>.</p>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1">
|
||||
<meta name="generator" content="pdoc3 0.11.5">
|
||||
<meta name="generator" content="pdoc3 0.11.6">
|
||||
<title>connpy.tests.test_ai API documentation</title>
|
||||
<meta name="description" content="Tests for connpy.ai module.">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/13.0.0/sanitize.min.css" integrity="sha512-y1dtMcuvtTMJc1yPgEqF0ZjQbhnc/bFhyvIyVNb9Zk5mIGtqVaAB1Ttl28su8AvFMOY0EwRbAe+HCLqj6W7/KA==" crossorigin>
|
||||
@@ -1339,16 +1339,16 @@ def myai(self, ai_config, mock_litellm):
|
||||
|
||||
def test_list_nodes_tool_found(self, myai):
|
||||
result = myai.list_nodes_tool("router.*")
|
||||
parsed = json.loads(result)
|
||||
parsed = json.loads(result) if isinstance(result, str) else result
|
||||
assert "router1" in str(parsed)
|
||||
|
||||
def test_list_nodes_tool_not_found(self, myai):
|
||||
result = myai.list_nodes_tool("nonexistent_pattern_xyz")
|
||||
assert "No nodes found" in result
|
||||
assert "No nodes found" in str(result)
|
||||
|
||||
def test_get_node_info_masks_password(self, myai):
|
||||
result = myai.get_node_info_tool("router1")
|
||||
parsed = json.loads(result)
|
||||
parsed = json.loads(result) if isinstance(result, str) else result
|
||||
assert parsed["password"] == "***"
|
||||
|
||||
def test_is_safe_command_show(self, myai):
|
||||
@@ -1393,7 +1393,7 @@ def myai(self, ai_config, mock_litellm):
|
||||
</summary>
|
||||
<pre><code class="python">def test_get_node_info_masks_password(self, myai):
|
||||
result = myai.get_node_info_tool("router1")
|
||||
parsed = json.loads(result)
|
||||
parsed = json.loads(result) if isinstance(result, str) else result
|
||||
assert parsed["password"] == "***"</code></pre>
|
||||
</details>
|
||||
<div class="desc"></div>
|
||||
@@ -1462,7 +1462,7 @@ def myai(self, ai_config, mock_litellm):
|
||||
</summary>
|
||||
<pre><code class="python">def test_list_nodes_tool_found(self, myai):
|
||||
result = myai.list_nodes_tool("router.*")
|
||||
parsed = json.loads(result)
|
||||
parsed = json.loads(result) if isinstance(result, str) else result
|
||||
assert "router1" in str(parsed)</code></pre>
|
||||
</details>
|
||||
<div class="desc"></div>
|
||||
@@ -1477,7 +1477,7 @@ def myai(self, ai_config, mock_litellm):
|
||||
</summary>
|
||||
<pre><code class="python">def test_list_nodes_tool_not_found(self, myai):
|
||||
result = myai.list_nodes_tool("nonexistent_pattern_xyz")
|
||||
assert "No nodes found" in result</code></pre>
|
||||
assert "No nodes found" in str(result)</code></pre>
|
||||
</details>
|
||||
<div class="desc"></div>
|
||||
</dd>
|
||||
@@ -1731,7 +1731,7 @@ def myai(self, ai_config, mock_litellm):
|
||||
</nav>
|
||||
</main>
|
||||
<footer id="footer">
|
||||
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.11.5</a>.</p>
|
||||
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.11.6</a>.</p>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1">
|
||||
<meta name="generator" content="pdoc3 0.11.5">
|
||||
<meta name="generator" content="pdoc3 0.11.6">
|
||||
<title>connpy.tests.test_capture API documentation</title>
|
||||
<meta name="description" content="Tests for connpy.core_plugins.capture">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/13.0.0/sanitize.min.css" integrity="sha512-y1dtMcuvtTMJc1yPgEqF0ZjQbhnc/bFhyvIyVNb9Zk5mIGtqVaAB1Ttl28su8AvFMOY0EwRbAe+HCLqj6W7/KA==" crossorigin>
|
||||
@@ -245,7 +245,7 @@ def mock_connapp():
|
||||
</nav>
|
||||
</main>
|
||||
<footer id="footer">
|
||||
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.11.5</a>.</p>
|
||||
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.11.6</a>.</p>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1">
|
||||
<meta name="generator" content="pdoc3 0.11.5">
|
||||
<meta name="generator" content="pdoc3 0.11.6">
|
||||
<title>connpy.tests.test_completion API documentation</title>
|
||||
<meta name="description" content="Tests for connpy.completion module.">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/13.0.0/sanitize.min.css" integrity="sha512-y1dtMcuvtTMJc1yPgEqF0ZjQbhnc/bFhyvIyVNb9Zk5mIGtqVaAB1Ttl28su8AvFMOY0EwRbAe+HCLqj6W7/KA==" crossorigin>
|
||||
@@ -257,7 +257,7 @@ el.replaceWith(d);
|
||||
</nav>
|
||||
</main>
|
||||
<footer id="footer">
|
||||
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.11.5</a>.</p>
|
||||
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.11.6</a>.</p>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1">
|
||||
<meta name="generator" content="pdoc3 0.11.5">
|
||||
<meta name="generator" content="pdoc3 0.11.6">
|
||||
<title>connpy.tests.test_configfile API documentation</title>
|
||||
<meta name="description" content="Tests for connpy.configfile module.">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/13.0.0/sanitize.min.css" integrity="sha512-y1dtMcuvtTMJc1yPgEqF0ZjQbhnc/bFhyvIyVNb9Zk5mIGtqVaAB1Ttl28su8AvFMOY0EwRbAe+HCLqj6W7/KA==" crossorigin>
|
||||
@@ -2005,7 +2005,7 @@ el.replaceWith(d);
|
||||
</nav>
|
||||
</main>
|
||||
<footer id="footer">
|
||||
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.11.5</a>.</p>
|
||||
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.11.6</a>.</p>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1">
|
||||
<meta name="generator" content="pdoc3 0.11.5">
|
||||
<meta name="generator" content="pdoc3 0.11.6">
|
||||
<title>connpy.tests.test_connapp API documentation</title>
|
||||
<meta name="description" content="">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/13.0.0/sanitize.min.css" integrity="sha512-y1dtMcuvtTMJc1yPgEqF0ZjQbhnc/bFhyvIyVNb9Zk5mIGtqVaAB1Ttl28su8AvFMOY0EwRbAe+HCLqj6W7/KA==" crossorigin>
|
||||
@@ -699,7 +699,7 @@ def test_run(mock_run_commands, app):
|
||||
</nav>
|
||||
</main>
|
||||
<footer id="footer">
|
||||
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.11.5</a>.</p>
|
||||
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.11.6</a>.</p>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1">
|
||||
<meta name="generator" content="pdoc3 0.11.5">
|
||||
<meta name="generator" content="pdoc3 0.11.6">
|
||||
<title>connpy.tests.test_core API documentation</title>
|
||||
<meta name="description" content="Tests for connpy.core module — node and nodes classes.">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/13.0.0/sanitize.min.css" integrity="sha512-y1dtMcuvtTMJc1yPgEqF0ZjQbhnc/bFhyvIyVNb9Zk5mIGtqVaAB1Ttl28su8AvFMOY0EwRbAe+HCLqj6W7/KA==" crossorigin>
|
||||
@@ -93,6 +93,23 @@ el.replaceWith(d);
|
||||
assert "telnet 10.0.0.1" in cmd
|
||||
assert "23" in cmd
|
||||
|
||||
def test_ssm_cmd_basic(self):
|
||||
n = self._make_node(protocol="ssm", host="i-12345")
|
||||
cmd = n._get_cmd()
|
||||
assert "aws ssm start-session" in cmd
|
||||
assert "--target i-12345" in cmd
|
||||
|
||||
def test_ssm_cmd_tags(self):
|
||||
n = self._make_node(protocol="ssm", host="i-12345", tags={"region": "us-west-2", "profile": "prod"})
|
||||
cmd = n._get_cmd()
|
||||
assert "--region us-west-2" in cmd
|
||||
assert "--profile prod" in cmd
|
||||
|
||||
def test_ssm_cmd_options(self):
|
||||
n = self._make_node(protocol="ssm", host="i-12345", options="--document-name AWS-StartInteractiveCommand")
|
||||
cmd = n._get_cmd()
|
||||
assert "--document-name AWS-StartInteractiveCommand" in cmd
|
||||
|
||||
def test_kubectl_cmd(self):
|
||||
n = self._make_node(protocol="kubectl", host="my-pod", tags={"kube_command": "/bin/sh"})
|
||||
cmd = n._get_cmd()
|
||||
@@ -271,6 +288,53 @@ el.replaceWith(d);
|
||||
</details>
|
||||
<div class="desc"></div>
|
||||
</dd>
|
||||
<dt id="connpy.tests.test_core.TestCommandGeneration.test_ssm_cmd_basic"><code class="name flex">
|
||||
<span>def <span class="ident">test_ssm_cmd_basic</span></span>(<span>self)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def test_ssm_cmd_basic(self):
|
||||
n = self._make_node(protocol="ssm", host="i-12345")
|
||||
cmd = n._get_cmd()
|
||||
assert "aws ssm start-session" in cmd
|
||||
assert "--target i-12345" in cmd</code></pre>
|
||||
</details>
|
||||
<div class="desc"></div>
|
||||
</dd>
|
||||
<dt id="connpy.tests.test_core.TestCommandGeneration.test_ssm_cmd_options"><code class="name flex">
|
||||
<span>def <span class="ident">test_ssm_cmd_options</span></span>(<span>self)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def test_ssm_cmd_options(self):
|
||||
n = self._make_node(protocol="ssm", host="i-12345", options="--document-name AWS-StartInteractiveCommand")
|
||||
cmd = n._get_cmd()
|
||||
assert "--document-name AWS-StartInteractiveCommand" in cmd</code></pre>
|
||||
</details>
|
||||
<div class="desc"></div>
|
||||
</dd>
|
||||
<dt id="connpy.tests.test_core.TestCommandGeneration.test_ssm_cmd_tags"><code class="name flex">
|
||||
<span>def <span class="ident">test_ssm_cmd_tags</span></span>(<span>self)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def test_ssm_cmd_tags(self):
|
||||
n = self._make_node(protocol="ssm", host="i-12345", tags={"region": "us-west-2", "profile": "prod"})
|
||||
cmd = n._get_cmd()
|
||||
assert "--region us-west-2" in cmd
|
||||
assert "--profile prod" in cmd</code></pre>
|
||||
</details>
|
||||
<div class="desc"></div>
|
||||
</dd>
|
||||
<dt id="connpy.tests.test_core.TestCommandGeneration.test_telnet_cmd"><code class="name flex">
|
||||
<span>def <span class="ident">test_telnet_cmd</span></span>(<span>self)</span>
|
||||
</code></dt>
|
||||
@@ -1239,6 +1303,9 @@ el.replaceWith(d);
|
||||
<li><code><a title="connpy.tests.test_core.TestCommandGeneration.test_ssh_cmd_no_user" href="#connpy.tests.test_core.TestCommandGeneration.test_ssh_cmd_no_user">test_ssh_cmd_no_user</a></code></li>
|
||||
<li><code><a title="connpy.tests.test_core.TestCommandGeneration.test_ssh_cmd_options" href="#connpy.tests.test_core.TestCommandGeneration.test_ssh_cmd_options">test_ssh_cmd_options</a></code></li>
|
||||
<li><code><a title="connpy.tests.test_core.TestCommandGeneration.test_ssh_cmd_port" href="#connpy.tests.test_core.TestCommandGeneration.test_ssh_cmd_port">test_ssh_cmd_port</a></code></li>
|
||||
<li><code><a title="connpy.tests.test_core.TestCommandGeneration.test_ssm_cmd_basic" href="#connpy.tests.test_core.TestCommandGeneration.test_ssm_cmd_basic">test_ssm_cmd_basic</a></code></li>
|
||||
<li><code><a title="connpy.tests.test_core.TestCommandGeneration.test_ssm_cmd_options" href="#connpy.tests.test_core.TestCommandGeneration.test_ssm_cmd_options">test_ssm_cmd_options</a></code></li>
|
||||
<li><code><a title="connpy.tests.test_core.TestCommandGeneration.test_ssm_cmd_tags" href="#connpy.tests.test_core.TestCommandGeneration.test_ssm_cmd_tags">test_ssm_cmd_tags</a></code></li>
|
||||
<li><code><a title="connpy.tests.test_core.TestCommandGeneration.test_telnet_cmd" href="#connpy.tests.test_core.TestCommandGeneration.test_telnet_cmd">test_telnet_cmd</a></code></li>
|
||||
</ul>
|
||||
</li>
|
||||
@@ -1302,7 +1369,7 @@ el.replaceWith(d);
|
||||
</nav>
|
||||
</main>
|
||||
<footer id="footer">
|
||||
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.11.5</a>.</p>
|
||||
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.11.6</a>.</p>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1">
|
||||
<meta name="generator" content="pdoc3 0.11.5">
|
||||
<meta name="generator" content="pdoc3 0.11.6">
|
||||
<title>connpy.tests.test_execution_service API documentation</title>
|
||||
<meta name="description" content="">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/13.0.0/sanitize.min.css" integrity="sha512-y1dtMcuvtTMJc1yPgEqF0ZjQbhnc/bFhyvIyVNb9Zk5mIGtqVaAB1Ttl28su8AvFMOY0EwRbAe+HCLqj6W7/KA==" crossorigin>
|
||||
@@ -142,7 +142,7 @@ Regression: ExecutionService.test_commands currently ignores on_node_complete.</
|
||||
</nav>
|
||||
</main>
|
||||
<footer id="footer">
|
||||
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.11.5</a>.</p>
|
||||
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.11.6</a>.</p>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -0,0 +1,715 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1">
|
||||
<meta name="generator" content="pdoc3 0.11.6">
|
||||
<title>connpy.tests.test_grpc_layer API documentation</title>
|
||||
<meta name="description" content="">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/13.0.0/sanitize.min.css" integrity="sha512-y1dtMcuvtTMJc1yPgEqF0ZjQbhnc/bFhyvIyVNb9Zk5mIGtqVaAB1Ttl28su8AvFMOY0EwRbAe+HCLqj6W7/KA==" crossorigin>
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/13.0.0/typography.min.css" integrity="sha512-Y1DYSb995BAfxobCkKepB1BqJJTPrOp3zPL74AWFugHHmmdcvO+C48WLrUOlhGMc0QG7AE3f7gmvvcrmX2fDoA==" crossorigin>
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/default.min.css" crossorigin>
|
||||
<style>:root{--highlight-color:#fe9}.flex{display:flex !important}body{line-height:1.5em}#content{padding:20px}#sidebar{padding:1.5em;overflow:hidden}#sidebar > *:last-child{margin-bottom:2cm}.http-server-breadcrumbs{font-size:130%;margin:0 0 15px 0}#footer{font-size:.75em;padding:5px 30px;border-top:1px solid #ddd;text-align:right}#footer p{margin:0 0 0 1em;display:inline-block}#footer p:last-child{margin-right:30px}h1,h2,h3,h4,h5{font-weight:300}h1{font-size:2.5em;line-height:1.1em}h2{font-size:1.75em;margin:2em 0 .50em 0}h3{font-size:1.4em;margin:1.6em 0 .7em 0}h4{margin:0;font-size:105%}h1:target,h2:target,h3:target,h4:target,h5:target,h6:target{background:var(--highlight-color);padding:.2em 0}a{color:#058;text-decoration:none;transition:color .2s ease-in-out}a:visited{color:#503}a:hover{color:#b62}.title code{font-weight:bold}h2[id^="header-"]{margin-top:2em}.ident{color:#900;font-weight:bold}pre code{font-size:.8em;line-height:1.4em;padding:1em;display:block}code{background:#f3f3f3;font-family:"DejaVu Sans Mono",monospace;padding:1px 4px;overflow-wrap:break-word}h1 code{background:transparent}pre{border-top:1px solid #ccc;border-bottom:1px solid #ccc;margin:1em 0}#http-server-module-list{display:flex;flex-flow:column}#http-server-module-list div{display:flex}#http-server-module-list dt{min-width:10%}#http-server-module-list p{margin-top:0}.toc ul,#index{list-style-type:none;margin:0;padding:0}#index code{background:transparent}#index h3{border-bottom:1px solid #ddd}#index ul{padding:0}#index h4{margin-top:.6em;font-weight:bold}@media (min-width:200ex){#index .two-column{column-count:2}}@media (min-width:300ex){#index .two-column{column-count:3}}dl{margin-bottom:2em}dl dl:last-child{margin-bottom:4em}dd{margin:0 0 1em 3em}#header-classes + dl > dd{margin-bottom:3em}dd dd{margin-left:2em}dd p{margin:10px 0}.name{background:#eee;font-size:.85em;padding:5px 10px;display:inline-block;min-width:40%}.name:hover{background:#e0e0e0}dt:target .name{background:var(--highlight-color)}.name > span:first-child{white-space:nowrap}.name.class > span:nth-child(2){margin-left:.4em}.inherited{color:#999;border-left:5px solid #eee;padding-left:1em}.inheritance em{font-style:normal;font-weight:bold}.desc h2{font-weight:400;font-size:1.25em}.desc h3{font-size:1em}.desc dt code{background:inherit}.source > summary,.git-link-div{color:#666;text-align:right;font-weight:400;font-size:.8em;text-transform:uppercase}.source summary > *{white-space:nowrap;cursor:pointer}.git-link{color:inherit;margin-left:1em}.source pre{max-height:500px;overflow:auto;margin:0}.source pre code{font-size:12px;overflow:visible;min-width:max-content}.hlist{list-style:none}.hlist li{display:inline}.hlist li:after{content:',\2002'}.hlist li:last-child:after{content:none}.hlist .hlist{display:inline;padding-left:1em}img{max-width:100%}td{padding:0 .5em}.admonition{padding:.1em 1em;margin:1em 0}.admonition-title{font-weight:bold}.admonition.note,.admonition.info,.admonition.important{background:#aef}.admonition.todo,.admonition.versionadded,.admonition.tip,.admonition.hint{background:#dfd}.admonition.warning,.admonition.versionchanged,.admonition.deprecated{background:#fd4}.admonition.error,.admonition.danger,.admonition.caution{background:lightpink}</style>
|
||||
<style media="screen and (min-width: 700px)">@media screen and (min-width:700px){#sidebar{width:30%;height:100vh;overflow:auto;position:sticky;top:0}#content{width:70%;max-width:100ch;padding:3em 4em;border-left:1px solid #ddd}pre code{font-size:1em}.name{font-size:1em}main{display:flex;flex-direction:row-reverse;justify-content:flex-end}.toc ul ul,#index ul ul{padding-left:1em}.toc > ul > li{margin-top:.5em}}</style>
|
||||
<style media="print">@media print{#sidebar h1{page-break-before:always}.source{display:none}}@media print{*{background:transparent !important;color:#000 !important;box-shadow:none !important;text-shadow:none !important}a[href]:after{content:" (" attr(href) ")";font-size:90%}a[href][title]:after{content:none}abbr[title]:after{content:" (" attr(title) ")"}.ir a:after,a[href^="javascript:"]:after,a[href^="#"]:after{content:""}pre,blockquote{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}tr,img{page-break-inside:avoid}img{max-width:100% !important}@page{margin:0.5cm}p,h2,h3{orphans:3;widows:3}h1,h2,h3,h4,h5,h6{page-break-after:avoid}}</style>
|
||||
<script defer src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/highlight.min.js" integrity="sha512-D9gUyxqja7hBtkWpPWGt9wfbfaMGVt9gnyCvYa+jojwwPHLCzUm5i8rpk7vD7wNee9bA35eYIjobYPaQuKS1MQ==" crossorigin></script>
|
||||
<script>window.addEventListener('DOMContentLoaded', () => {
|
||||
hljs.configure({languages: ['bash', 'css', 'diff', 'graphql', 'ini', 'javascript', 'json', 'plaintext', 'python', 'python-repl', 'rust', 'shell', 'sql', 'typescript', 'xml', 'yaml']});
|
||||
hljs.highlightAll();
|
||||
/* Collapse source docstrings */
|
||||
setTimeout(() => {
|
||||
[...document.querySelectorAll('.hljs.language-python > .hljs-string')]
|
||||
.filter(el => el.innerHTML.length > 200 && ['"""', "'''"].includes(el.innerHTML.substring(0, 3)))
|
||||
.forEach(el => {
|
||||
let d = document.createElement('details');
|
||||
d.classList.add('hljs-string');
|
||||
d.innerHTML = '<summary>"""</summary>' + el.innerHTML.substring(3);
|
||||
el.replaceWith(d);
|
||||
});
|
||||
}, 100);
|
||||
})</script>
|
||||
</head>
|
||||
<body>
|
||||
<main>
|
||||
<article id="content">
|
||||
<header>
|
||||
<h1 class="title">Module <code>connpy.tests.test_grpc_layer</code></h1>
|
||||
</header>
|
||||
<section id="section-intro">
|
||||
</section>
|
||||
<section>
|
||||
</section>
|
||||
<section>
|
||||
</section>
|
||||
<section>
|
||||
</section>
|
||||
<section>
|
||||
<h2 class="section-title" id="header-classes">Classes</h2>
|
||||
<dl>
|
||||
<dt id="connpy.tests.test_grpc_layer.MockContext"><code class="flex name class">
|
||||
<span>class <span class="ident">MockContext</span></span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">class MockContext:
|
||||
def abort(self, code, details):
|
||||
raise Exception(f"gRPC Abort: {code} - {details}")</code></pre>
|
||||
</details>
|
||||
<div class="desc"></div>
|
||||
<h3>Methods</h3>
|
||||
<dl>
|
||||
<dt id="connpy.tests.test_grpc_layer.MockContext.abort"><code class="name flex">
|
||||
<span>def <span class="ident">abort</span></span>(<span>self, code, details)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def abort(self, code, details):
|
||||
raise Exception(f"gRPC Abort: {code} - {details}")</code></pre>
|
||||
</details>
|
||||
<div class="desc"></div>
|
||||
</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
<dt id="connpy.tests.test_grpc_layer.TestGRPCIntegration"><code class="flex name class">
|
||||
<span>class <span class="ident">TestGRPCIntegration</span></span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">class TestGRPCIntegration:
|
||||
@pytest.fixture
|
||||
def grpc_server(self, populated_config):
|
||||
"""Starts a local gRPC server for integration testing."""
|
||||
srv = grpc.server(futures.ThreadPoolExecutor(max_workers=5))
|
||||
|
||||
# Register services
|
||||
connpy_pb2_grpc.add_NodeServiceServicer_to_server(server.NodeServicer(populated_config), srv)
|
||||
connpy_pb2_grpc.add_ProfileServiceServicer_to_server(server.ProfileServicer(populated_config), srv)
|
||||
connpy_pb2_grpc.add_ConfigServiceServicer_to_server(server.ConfigServicer(populated_config), srv)
|
||||
connpy_pb2_grpc.add_ExecutionServiceServicer_to_server(server.ExecutionServicer(populated_config), srv)
|
||||
connpy_pb2_grpc.add_ImportExportServiceServicer_to_server(server.ImportExportServicer(populated_config), srv)
|
||||
|
||||
port = srv.add_insecure_port('127.0.0.1:0')
|
||||
srv.start()
|
||||
yield f"127.0.0.1:{port}"
|
||||
srv.stop(0)
|
||||
|
||||
@pytest.fixture
|
||||
def channel(self, grpc_server):
|
||||
with grpc.insecure_channel(grpc_server) as channel:
|
||||
yield channel
|
||||
|
||||
@pytest.fixture
|
||||
def node_stub(self, channel):
|
||||
return stubs.NodeStub(channel, "localhost")
|
||||
|
||||
@pytest.fixture
|
||||
def profile_stub(self, channel):
|
||||
return stubs.ProfileStub(channel, "localhost")
|
||||
|
||||
@pytest.fixture
|
||||
def config_stub(self, channel):
|
||||
return stubs.ConfigStub(channel, "localhost")
|
||||
|
||||
def test_list_nodes_integration(self, node_stub):
|
||||
nodes = node_stub.list_nodes()
|
||||
assert "router1" in nodes
|
||||
assert "server1@office" in nodes
|
||||
|
||||
def test_get_node_details_integration(self, node_stub):
|
||||
details = node_stub.get_node_details("router1")
|
||||
assert details["host"] == "10.0.0.1"
|
||||
|
||||
def test_node_not_found_integration(self, node_stub):
|
||||
with pytest.raises(ConnpyError) as exc:
|
||||
node_stub.get_node_details("non-existent")
|
||||
assert "Node 'non-existent' not found." in str(exc.value)
|
||||
|
||||
def test_list_profiles_integration(self, profile_stub):
|
||||
profiles = profile_stub.list_profiles()
|
||||
assert "office-user" in profiles
|
||||
|
||||
def test_get_settings_integration(self, config_stub):
|
||||
settings = config_stub.get_settings()
|
||||
assert "idletime" in settings
|
||||
|
||||
def test_update_setting_integration(self, config_stub):
|
||||
config_stub.update_setting("idletime", 99)
|
||||
settings = config_stub.get_settings()
|
||||
assert settings["idletime"] == 99
|
||||
|
||||
def test_add_delete_node_integration(self, node_stub):
|
||||
node_stub.add_node("integration-test-node", {"host": "9.9.9.9"})
|
||||
assert "integration-test-node" in node_stub.list_nodes()
|
||||
node_stub.delete_node("integration-test-node")
|
||||
assert "integration-test-node" not in node_stub.list_nodes()
|
||||
|
||||
def test_import_yaml_integration(self, channel, node_stub):
|
||||
import yaml
|
||||
from connpy.grpc_layer import stubs
|
||||
stub = stubs.ImportExportStub(channel, "localhost")
|
||||
|
||||
# ImportExportService expects a flat dict of nodes, not a full config structure
|
||||
inventory = {
|
||||
"imported-node": {"host": "8.8.8.8", "protocol": "ssh", "type": "connection"}
|
||||
}
|
||||
yaml_content = yaml.dump(inventory)
|
||||
|
||||
import tempfile
|
||||
with tempfile.NamedTemporaryFile(mode="w", suffix=".yaml", delete=False) as f:
|
||||
f.write(yaml_content)
|
||||
temp_path = f.name
|
||||
|
||||
try:
|
||||
stub.import_from_file(temp_path)
|
||||
# Verify the node was imported and is visible via NodeStub
|
||||
nodes = node_stub.list_nodes()
|
||||
assert "imported-node" in nodes
|
||||
finally:
|
||||
if os.path.exists(temp_path):
|
||||
os.remove(temp_path)</code></pre>
|
||||
</details>
|
||||
<div class="desc"></div>
|
||||
<h3>Methods</h3>
|
||||
<dl>
|
||||
<dt id="connpy.tests.test_grpc_layer.TestGRPCIntegration.channel"><code class="name flex">
|
||||
<span>def <span class="ident">channel</span></span>(<span>self, grpc_server)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">@pytest.fixture
|
||||
def channel(self, grpc_server):
|
||||
with grpc.insecure_channel(grpc_server) as channel:
|
||||
yield channel</code></pre>
|
||||
</details>
|
||||
<div class="desc"></div>
|
||||
</dd>
|
||||
<dt id="connpy.tests.test_grpc_layer.TestGRPCIntegration.config_stub"><code class="name flex">
|
||||
<span>def <span class="ident">config_stub</span></span>(<span>self, channel)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">@pytest.fixture
|
||||
def config_stub(self, channel):
|
||||
return stubs.ConfigStub(channel, "localhost")</code></pre>
|
||||
</details>
|
||||
<div class="desc"></div>
|
||||
</dd>
|
||||
<dt id="connpy.tests.test_grpc_layer.TestGRPCIntegration.grpc_server"><code class="name flex">
|
||||
<span>def <span class="ident">grpc_server</span></span>(<span>self, populated_config)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">@pytest.fixture
|
||||
def grpc_server(self, populated_config):
|
||||
"""Starts a local gRPC server for integration testing."""
|
||||
srv = grpc.server(futures.ThreadPoolExecutor(max_workers=5))
|
||||
|
||||
# Register services
|
||||
connpy_pb2_grpc.add_NodeServiceServicer_to_server(server.NodeServicer(populated_config), srv)
|
||||
connpy_pb2_grpc.add_ProfileServiceServicer_to_server(server.ProfileServicer(populated_config), srv)
|
||||
connpy_pb2_grpc.add_ConfigServiceServicer_to_server(server.ConfigServicer(populated_config), srv)
|
||||
connpy_pb2_grpc.add_ExecutionServiceServicer_to_server(server.ExecutionServicer(populated_config), srv)
|
||||
connpy_pb2_grpc.add_ImportExportServiceServicer_to_server(server.ImportExportServicer(populated_config), srv)
|
||||
|
||||
port = srv.add_insecure_port('127.0.0.1:0')
|
||||
srv.start()
|
||||
yield f"127.0.0.1:{port}"
|
||||
srv.stop(0)</code></pre>
|
||||
</details>
|
||||
<div class="desc"><p>Starts a local gRPC server for integration testing.</p></div>
|
||||
</dd>
|
||||
<dt id="connpy.tests.test_grpc_layer.TestGRPCIntegration.node_stub"><code class="name flex">
|
||||
<span>def <span class="ident">node_stub</span></span>(<span>self, channel)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">@pytest.fixture
|
||||
def node_stub(self, channel):
|
||||
return stubs.NodeStub(channel, "localhost")</code></pre>
|
||||
</details>
|
||||
<div class="desc"></div>
|
||||
</dd>
|
||||
<dt id="connpy.tests.test_grpc_layer.TestGRPCIntegration.profile_stub"><code class="name flex">
|
||||
<span>def <span class="ident">profile_stub</span></span>(<span>self, channel)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">@pytest.fixture
|
||||
def profile_stub(self, channel):
|
||||
return stubs.ProfileStub(channel, "localhost")</code></pre>
|
||||
</details>
|
||||
<div class="desc"></div>
|
||||
</dd>
|
||||
<dt id="connpy.tests.test_grpc_layer.TestGRPCIntegration.test_add_delete_node_integration"><code class="name flex">
|
||||
<span>def <span class="ident">test_add_delete_node_integration</span></span>(<span>self, node_stub)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def test_add_delete_node_integration(self, node_stub):
|
||||
node_stub.add_node("integration-test-node", {"host": "9.9.9.9"})
|
||||
assert "integration-test-node" in node_stub.list_nodes()
|
||||
node_stub.delete_node("integration-test-node")
|
||||
assert "integration-test-node" not in node_stub.list_nodes()</code></pre>
|
||||
</details>
|
||||
<div class="desc"></div>
|
||||
</dd>
|
||||
<dt id="connpy.tests.test_grpc_layer.TestGRPCIntegration.test_get_node_details_integration"><code class="name flex">
|
||||
<span>def <span class="ident">test_get_node_details_integration</span></span>(<span>self, node_stub)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def test_get_node_details_integration(self, node_stub):
|
||||
details = node_stub.get_node_details("router1")
|
||||
assert details["host"] == "10.0.0.1"</code></pre>
|
||||
</details>
|
||||
<div class="desc"></div>
|
||||
</dd>
|
||||
<dt id="connpy.tests.test_grpc_layer.TestGRPCIntegration.test_get_settings_integration"><code class="name flex">
|
||||
<span>def <span class="ident">test_get_settings_integration</span></span>(<span>self, config_stub)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def test_get_settings_integration(self, config_stub):
|
||||
settings = config_stub.get_settings()
|
||||
assert "idletime" in settings</code></pre>
|
||||
</details>
|
||||
<div class="desc"></div>
|
||||
</dd>
|
||||
<dt id="connpy.tests.test_grpc_layer.TestGRPCIntegration.test_import_yaml_integration"><code class="name flex">
|
||||
<span>def <span class="ident">test_import_yaml_integration</span></span>(<span>self, channel, node_stub)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def test_import_yaml_integration(self, channel, node_stub):
|
||||
import yaml
|
||||
from connpy.grpc_layer import stubs
|
||||
stub = stubs.ImportExportStub(channel, "localhost")
|
||||
|
||||
# ImportExportService expects a flat dict of nodes, not a full config structure
|
||||
inventory = {
|
||||
"imported-node": {"host": "8.8.8.8", "protocol": "ssh", "type": "connection"}
|
||||
}
|
||||
yaml_content = yaml.dump(inventory)
|
||||
|
||||
import tempfile
|
||||
with tempfile.NamedTemporaryFile(mode="w", suffix=".yaml", delete=False) as f:
|
||||
f.write(yaml_content)
|
||||
temp_path = f.name
|
||||
|
||||
try:
|
||||
stub.import_from_file(temp_path)
|
||||
# Verify the node was imported and is visible via NodeStub
|
||||
nodes = node_stub.list_nodes()
|
||||
assert "imported-node" in nodes
|
||||
finally:
|
||||
if os.path.exists(temp_path):
|
||||
os.remove(temp_path)</code></pre>
|
||||
</details>
|
||||
<div class="desc"></div>
|
||||
</dd>
|
||||
<dt id="connpy.tests.test_grpc_layer.TestGRPCIntegration.test_list_nodes_integration"><code class="name flex">
|
||||
<span>def <span class="ident">test_list_nodes_integration</span></span>(<span>self, node_stub)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def test_list_nodes_integration(self, node_stub):
|
||||
nodes = node_stub.list_nodes()
|
||||
assert "router1" in nodes
|
||||
assert "server1@office" in nodes</code></pre>
|
||||
</details>
|
||||
<div class="desc"></div>
|
||||
</dd>
|
||||
<dt id="connpy.tests.test_grpc_layer.TestGRPCIntegration.test_list_profiles_integration"><code class="name flex">
|
||||
<span>def <span class="ident">test_list_profiles_integration</span></span>(<span>self, profile_stub)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def test_list_profiles_integration(self, profile_stub):
|
||||
profiles = profile_stub.list_profiles()
|
||||
assert "office-user" in profiles</code></pre>
|
||||
</details>
|
||||
<div class="desc"></div>
|
||||
</dd>
|
||||
<dt id="connpy.tests.test_grpc_layer.TestGRPCIntegration.test_node_not_found_integration"><code class="name flex">
|
||||
<span>def <span class="ident">test_node_not_found_integration</span></span>(<span>self, node_stub)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def test_node_not_found_integration(self, node_stub):
|
||||
with pytest.raises(ConnpyError) as exc:
|
||||
node_stub.get_node_details("non-existent")
|
||||
assert "Node 'non-existent' not found." in str(exc.value)</code></pre>
|
||||
</details>
|
||||
<div class="desc"></div>
|
||||
</dd>
|
||||
<dt id="connpy.tests.test_grpc_layer.TestGRPCIntegration.test_update_setting_integration"><code class="name flex">
|
||||
<span>def <span class="ident">test_update_setting_integration</span></span>(<span>self, config_stub)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def test_update_setting_integration(self, config_stub):
|
||||
config_stub.update_setting("idletime", 99)
|
||||
settings = config_stub.get_settings()
|
||||
assert settings["idletime"] == 99</code></pre>
|
||||
</details>
|
||||
<div class="desc"></div>
|
||||
</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
<dt id="connpy.tests.test_grpc_layer.TestNodeServicerNaming"><code class="flex name class">
|
||||
<span>class <span class="ident">TestNodeServicerNaming</span></span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">class TestNodeServicerNaming:
|
||||
@pytest.fixture
|
||||
def servicer(self, populated_config):
|
||||
return server.NodeServicer(populated_config)
|
||||
|
||||
@patch("connpy.core.node")
|
||||
def test_interact_node_uses_passed_name(self, mock_node, servicer):
|
||||
# Setup request with custom name
|
||||
params = {"name": "custom-node-name@test", "host": "1.2.3.4", "protocol": "ssh"}
|
||||
request = connpy_pb2.InteractRequest(
|
||||
id="dynamic",
|
||||
connection_params_json=json.dumps(params)
|
||||
)
|
||||
|
||||
# Mock node to allow _connect
|
||||
mock_node_instance = MagicMock()
|
||||
mock_node_instance._connect.return_value = True
|
||||
mock_node.return_value = mock_node_instance
|
||||
|
||||
# We only need the first iteration of the generator to check naming
|
||||
gen = servicer.interact_node(iter([request]), MockContext())
|
||||
next(gen) # Skip the success response
|
||||
|
||||
# Verify that node() was called with the custom name
|
||||
mock_node.assert_called()
|
||||
found = False
|
||||
for call in mock_node.call_args_list:
|
||||
if call.args[0] == "custom-node-name@test":
|
||||
found = True
|
||||
break
|
||||
assert found
|
||||
|
||||
@patch("connpy.core.node")
|
||||
def test_interact_node_fallback_naming(self, mock_node, servicer):
|
||||
# Setup request without custom name but with host
|
||||
params = {"host": "my-instance", "protocol": "ssm"}
|
||||
request = connpy_pb2.InteractRequest(
|
||||
id="dynamic",
|
||||
connection_params_json=json.dumps(params)
|
||||
)
|
||||
|
||||
mock_node_instance = MagicMock()
|
||||
mock_node_instance._connect.return_value = True
|
||||
mock_node.return_value = mock_node_instance
|
||||
|
||||
gen = servicer.interact_node(iter([request]), MockContext())
|
||||
next(gen)
|
||||
|
||||
# Verify fallback name: dynamic-{host}@remote
|
||||
found = False
|
||||
for call in mock_node.call_args_list:
|
||||
if call.args[0] == "dynamic-my-instance@remote":
|
||||
found = True
|
||||
break
|
||||
assert found</code></pre>
|
||||
</details>
|
||||
<div class="desc"></div>
|
||||
<h3>Methods</h3>
|
||||
<dl>
|
||||
<dt id="connpy.tests.test_grpc_layer.TestNodeServicerNaming.servicer"><code class="name flex">
|
||||
<span>def <span class="ident">servicer</span></span>(<span>self, populated_config)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">@pytest.fixture
|
||||
def servicer(self, populated_config):
|
||||
return server.NodeServicer(populated_config)</code></pre>
|
||||
</details>
|
||||
<div class="desc"></div>
|
||||
</dd>
|
||||
<dt id="connpy.tests.test_grpc_layer.TestNodeServicerNaming.test_interact_node_fallback_naming"><code class="name flex">
|
||||
<span>def <span class="ident">test_interact_node_fallback_naming</span></span>(<span>self, mock_node, servicer)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">@patch("connpy.core.node")
|
||||
def test_interact_node_fallback_naming(self, mock_node, servicer):
|
||||
# Setup request without custom name but with host
|
||||
params = {"host": "my-instance", "protocol": "ssm"}
|
||||
request = connpy_pb2.InteractRequest(
|
||||
id="dynamic",
|
||||
connection_params_json=json.dumps(params)
|
||||
)
|
||||
|
||||
mock_node_instance = MagicMock()
|
||||
mock_node_instance._connect.return_value = True
|
||||
mock_node.return_value = mock_node_instance
|
||||
|
||||
gen = servicer.interact_node(iter([request]), MockContext())
|
||||
next(gen)
|
||||
|
||||
# Verify fallback name: dynamic-{host}@remote
|
||||
found = False
|
||||
for call in mock_node.call_args_list:
|
||||
if call.args[0] == "dynamic-my-instance@remote":
|
||||
found = True
|
||||
break
|
||||
assert found</code></pre>
|
||||
</details>
|
||||
<div class="desc"></div>
|
||||
</dd>
|
||||
<dt id="connpy.tests.test_grpc_layer.TestNodeServicerNaming.test_interact_node_uses_passed_name"><code class="name flex">
|
||||
<span>def <span class="ident">test_interact_node_uses_passed_name</span></span>(<span>self, mock_node, servicer)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">@patch("connpy.core.node")
|
||||
def test_interact_node_uses_passed_name(self, mock_node, servicer):
|
||||
# Setup request with custom name
|
||||
params = {"name": "custom-node-name@test", "host": "1.2.3.4", "protocol": "ssh"}
|
||||
request = connpy_pb2.InteractRequest(
|
||||
id="dynamic",
|
||||
connection_params_json=json.dumps(params)
|
||||
)
|
||||
|
||||
# Mock node to allow _connect
|
||||
mock_node_instance = MagicMock()
|
||||
mock_node_instance._connect.return_value = True
|
||||
mock_node.return_value = mock_node_instance
|
||||
|
||||
# We only need the first iteration of the generator to check naming
|
||||
gen = servicer.interact_node(iter([request]), MockContext())
|
||||
next(gen) # Skip the success response
|
||||
|
||||
# Verify that node() was called with the custom name
|
||||
mock_node.assert_called()
|
||||
found = False
|
||||
for call in mock_node.call_args_list:
|
||||
if call.args[0] == "custom-node-name@test":
|
||||
found = True
|
||||
break
|
||||
assert found</code></pre>
|
||||
</details>
|
||||
<div class="desc"></div>
|
||||
</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
<dt id="connpy.tests.test_grpc_layer.TestStubsMessageFormatting"><code class="flex name class">
|
||||
<span>class <span class="ident">TestStubsMessageFormatting</span></span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">class TestStubsMessageFormatting:
|
||||
@patch("termios.tcsetattr")
|
||||
@patch("termios.tcgetattr")
|
||||
@patch("tty.setraw")
|
||||
@patch("os.read")
|
||||
@patch("select.select")
|
||||
def test_connect_dynamic_msg_formatting_ssm(self, mock_select, mock_read, mock_setraw, mock_getattr, mock_setattr):
|
||||
from connpy.grpc_layer.stubs import NodeStub
|
||||
|
||||
mock_getattr.return_value = [0, 0, 0, 0, 0, 0, [0] * 32]
|
||||
mock_channel = MagicMock()
|
||||
stub = NodeStub(mock_channel, "localhost:8048")
|
||||
|
||||
mock_resp = MagicMock()
|
||||
mock_resp.success = True
|
||||
stub.stub.interact_node.return_value = iter([mock_resp])
|
||||
|
||||
with patch("connpy.printer.success") as mock_success:
|
||||
with patch("sys.stdin.fileno", return_value=0):
|
||||
mock_select.return_value = ([], [], [])
|
||||
params = {"protocol": "ssm", "host": "i-12345", "name": "my-ssm-node@aws"}
|
||||
|
||||
with patch("select.select", side_effect=KeyboardInterrupt):
|
||||
try:
|
||||
stub.connect_dynamic(params)
|
||||
except KeyboardInterrupt:
|
||||
pass
|
||||
|
||||
mock_success.assert_called()
|
||||
msg = mock_success.call_args[0][0]
|
||||
assert "Connected to my-ssm-node@aws" in msg
|
||||
assert "at i-12345" in msg
|
||||
assert ":22" not in msg
|
||||
assert "via: ssm" in msg</code></pre>
|
||||
</details>
|
||||
<div class="desc"></div>
|
||||
<h3>Methods</h3>
|
||||
<dl>
|
||||
<dt id="connpy.tests.test_grpc_layer.TestStubsMessageFormatting.test_connect_dynamic_msg_formatting_ssm"><code class="name flex">
|
||||
<span>def <span class="ident">test_connect_dynamic_msg_formatting_ssm</span></span>(<span>self, mock_select, mock_read, mock_setraw, mock_getattr, mock_setattr)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">@patch("termios.tcsetattr")
|
||||
@patch("termios.tcgetattr")
|
||||
@patch("tty.setraw")
|
||||
@patch("os.read")
|
||||
@patch("select.select")
|
||||
def test_connect_dynamic_msg_formatting_ssm(self, mock_select, mock_read, mock_setraw, mock_getattr, mock_setattr):
|
||||
from connpy.grpc_layer.stubs import NodeStub
|
||||
|
||||
mock_getattr.return_value = [0, 0, 0, 0, 0, 0, [0] * 32]
|
||||
mock_channel = MagicMock()
|
||||
stub = NodeStub(mock_channel, "localhost:8048")
|
||||
|
||||
mock_resp = MagicMock()
|
||||
mock_resp.success = True
|
||||
stub.stub.interact_node.return_value = iter([mock_resp])
|
||||
|
||||
with patch("connpy.printer.success") as mock_success:
|
||||
with patch("sys.stdin.fileno", return_value=0):
|
||||
mock_select.return_value = ([], [], [])
|
||||
params = {"protocol": "ssm", "host": "i-12345", "name": "my-ssm-node@aws"}
|
||||
|
||||
with patch("select.select", side_effect=KeyboardInterrupt):
|
||||
try:
|
||||
stub.connect_dynamic(params)
|
||||
except KeyboardInterrupt:
|
||||
pass
|
||||
|
||||
mock_success.assert_called()
|
||||
msg = mock_success.call_args[0][0]
|
||||
assert "Connected to my-ssm-node@aws" in msg
|
||||
assert "at i-12345" in msg
|
||||
assert ":22" not in msg
|
||||
assert "via: ssm" in msg</code></pre>
|
||||
</details>
|
||||
<div class="desc"></div>
|
||||
</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
</dl>
|
||||
</section>
|
||||
</article>
|
||||
<nav id="sidebar">
|
||||
<div class="toc">
|
||||
<ul></ul>
|
||||
</div>
|
||||
<ul id="index">
|
||||
<li><h3>Super-module</h3>
|
||||
<ul>
|
||||
<li><code><a title="connpy.tests" href="index.html">connpy.tests</a></code></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><h3><a href="#header-classes">Classes</a></h3>
|
||||
<ul>
|
||||
<li>
|
||||
<h4><code><a title="connpy.tests.test_grpc_layer.MockContext" href="#connpy.tests.test_grpc_layer.MockContext">MockContext</a></code></h4>
|
||||
<ul class="">
|
||||
<li><code><a title="connpy.tests.test_grpc_layer.MockContext.abort" href="#connpy.tests.test_grpc_layer.MockContext.abort">abort</a></code></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>
|
||||
<h4><code><a title="connpy.tests.test_grpc_layer.TestGRPCIntegration" href="#connpy.tests.test_grpc_layer.TestGRPCIntegration">TestGRPCIntegration</a></code></h4>
|
||||
<ul class="">
|
||||
<li><code><a title="connpy.tests.test_grpc_layer.TestGRPCIntegration.channel" href="#connpy.tests.test_grpc_layer.TestGRPCIntegration.channel">channel</a></code></li>
|
||||
<li><code><a title="connpy.tests.test_grpc_layer.TestGRPCIntegration.config_stub" href="#connpy.tests.test_grpc_layer.TestGRPCIntegration.config_stub">config_stub</a></code></li>
|
||||
<li><code><a title="connpy.tests.test_grpc_layer.TestGRPCIntegration.grpc_server" href="#connpy.tests.test_grpc_layer.TestGRPCIntegration.grpc_server">grpc_server</a></code></li>
|
||||
<li><code><a title="connpy.tests.test_grpc_layer.TestGRPCIntegration.node_stub" href="#connpy.tests.test_grpc_layer.TestGRPCIntegration.node_stub">node_stub</a></code></li>
|
||||
<li><code><a title="connpy.tests.test_grpc_layer.TestGRPCIntegration.profile_stub" href="#connpy.tests.test_grpc_layer.TestGRPCIntegration.profile_stub">profile_stub</a></code></li>
|
||||
<li><code><a title="connpy.tests.test_grpc_layer.TestGRPCIntegration.test_add_delete_node_integration" href="#connpy.tests.test_grpc_layer.TestGRPCIntegration.test_add_delete_node_integration">test_add_delete_node_integration</a></code></li>
|
||||
<li><code><a title="connpy.tests.test_grpc_layer.TestGRPCIntegration.test_get_node_details_integration" href="#connpy.tests.test_grpc_layer.TestGRPCIntegration.test_get_node_details_integration">test_get_node_details_integration</a></code></li>
|
||||
<li><code><a title="connpy.tests.test_grpc_layer.TestGRPCIntegration.test_get_settings_integration" href="#connpy.tests.test_grpc_layer.TestGRPCIntegration.test_get_settings_integration">test_get_settings_integration</a></code></li>
|
||||
<li><code><a title="connpy.tests.test_grpc_layer.TestGRPCIntegration.test_import_yaml_integration" href="#connpy.tests.test_grpc_layer.TestGRPCIntegration.test_import_yaml_integration">test_import_yaml_integration</a></code></li>
|
||||
<li><code><a title="connpy.tests.test_grpc_layer.TestGRPCIntegration.test_list_nodes_integration" href="#connpy.tests.test_grpc_layer.TestGRPCIntegration.test_list_nodes_integration">test_list_nodes_integration</a></code></li>
|
||||
<li><code><a title="connpy.tests.test_grpc_layer.TestGRPCIntegration.test_list_profiles_integration" href="#connpy.tests.test_grpc_layer.TestGRPCIntegration.test_list_profiles_integration">test_list_profiles_integration</a></code></li>
|
||||
<li><code><a title="connpy.tests.test_grpc_layer.TestGRPCIntegration.test_node_not_found_integration" href="#connpy.tests.test_grpc_layer.TestGRPCIntegration.test_node_not_found_integration">test_node_not_found_integration</a></code></li>
|
||||
<li><code><a title="connpy.tests.test_grpc_layer.TestGRPCIntegration.test_update_setting_integration" href="#connpy.tests.test_grpc_layer.TestGRPCIntegration.test_update_setting_integration">test_update_setting_integration</a></code></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>
|
||||
<h4><code><a title="connpy.tests.test_grpc_layer.TestNodeServicerNaming" href="#connpy.tests.test_grpc_layer.TestNodeServicerNaming">TestNodeServicerNaming</a></code></h4>
|
||||
<ul class="">
|
||||
<li><code><a title="connpy.tests.test_grpc_layer.TestNodeServicerNaming.servicer" href="#connpy.tests.test_grpc_layer.TestNodeServicerNaming.servicer">servicer</a></code></li>
|
||||
<li><code><a title="connpy.tests.test_grpc_layer.TestNodeServicerNaming.test_interact_node_fallback_naming" href="#connpy.tests.test_grpc_layer.TestNodeServicerNaming.test_interact_node_fallback_naming">test_interact_node_fallback_naming</a></code></li>
|
||||
<li><code><a title="connpy.tests.test_grpc_layer.TestNodeServicerNaming.test_interact_node_uses_passed_name" href="#connpy.tests.test_grpc_layer.TestNodeServicerNaming.test_interact_node_uses_passed_name">test_interact_node_uses_passed_name</a></code></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>
|
||||
<h4><code><a title="connpy.tests.test_grpc_layer.TestStubsMessageFormatting" href="#connpy.tests.test_grpc_layer.TestStubsMessageFormatting">TestStubsMessageFormatting</a></code></h4>
|
||||
<ul class="">
|
||||
<li><code><a title="connpy.tests.test_grpc_layer.TestStubsMessageFormatting.test_connect_dynamic_msg_formatting_ssm" href="#connpy.tests.test_grpc_layer.TestStubsMessageFormatting.test_connect_dynamic_msg_formatting_ssm">test_connect_dynamic_msg_formatting_ssm</a></code></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
</main>
|
||||
<footer id="footer">
|
||||
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.11.6</a>.</p>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
||||
@@ -3,7 +3,7 @@
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1">
|
||||
<meta name="generator" content="pdoc3 0.11.5">
|
||||
<meta name="generator" content="pdoc3 0.11.6">
|
||||
<title>connpy.tests.test_hooks API documentation</title>
|
||||
<meta name="description" content="Tests for connpy.hooks module — MethodHook and ClassHook.">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/13.0.0/sanitize.min.css" integrity="sha512-y1dtMcuvtTMJc1yPgEqF0ZjQbhnc/bFhyvIyVNb9Zk5mIGtqVaAB1Ttl28su8AvFMOY0EwRbAe+HCLqj6W7/KA==" crossorigin>
|
||||
@@ -673,7 +673,7 @@ el.replaceWith(d);
|
||||
</nav>
|
||||
</main>
|
||||
<footer id="footer">
|
||||
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.11.5</a>.</p>
|
||||
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.11.6</a>.</p>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1">
|
||||
<meta name="generator" content="pdoc3 0.11.5">
|
||||
<meta name="generator" content="pdoc3 0.11.6">
|
||||
<title>connpy.tests.test_node_service API documentation</title>
|
||||
<meta name="description" content="">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/13.0.0/sanitize.min.css" integrity="sha512-y1dtMcuvtTMJc1yPgEqF0ZjQbhnc/bFhyvIyVNb9Zk5mIGtqVaAB1Ttl28su8AvFMOY0EwRbAe+HCLqj6W7/KA==" crossorigin>
|
||||
@@ -178,7 +178,7 @@ Regression: connapp._mod calls add_node instead of update_node.</p></div>
|
||||
</nav>
|
||||
</main>
|
||||
<footer id="footer">
|
||||
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.11.5</a>.</p>
|
||||
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.11.6</a>.</p>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1">
|
||||
<meta name="generator" content="pdoc3 0.11.5">
|
||||
<meta name="generator" content="pdoc3 0.11.6">
|
||||
<title>connpy.tests.test_plugins API documentation</title>
|
||||
<meta name="description" content="Tests for connpy.plugins module.">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/13.0.0/sanitize.min.css" integrity="sha512-y1dtMcuvtTMJc1yPgEqF0ZjQbhnc/bFhyvIyVNb9Zk5mIGtqVaAB1Ttl28su8AvFMOY0EwRbAe+HCLqj6W7/KA==" crossorigin>
|
||||
@@ -917,7 +917,7 @@ el.replaceWith(d);
|
||||
</nav>
|
||||
</main>
|
||||
<footer id="footer">
|
||||
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.11.5</a>.</p>
|
||||
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.11.6</a>.</p>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1">
|
||||
<meta name="generator" content="pdoc3 0.11.5">
|
||||
<meta name="generator" content="pdoc3 0.11.6">
|
||||
<title>connpy.tests.test_printer API documentation</title>
|
||||
<meta name="description" content="Tests for connpy.printer module.">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/13.0.0/sanitize.min.css" integrity="sha512-y1dtMcuvtTMJc1yPgEqF0ZjQbhnc/bFhyvIyVNb9Zk5mIGtqVaAB1Ttl28su8AvFMOY0EwRbAe+HCLqj6W7/KA==" crossorigin>
|
||||
@@ -459,7 +459,7 @@ el.replaceWith(d);
|
||||
</nav>
|
||||
</main>
|
||||
<footer id="footer">
|
||||
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.11.5</a>.</p>
|
||||
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.11.6</a>.</p>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -0,0 +1,154 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1">
|
||||
<meta name="generator" content="pdoc3 0.11.6">
|
||||
<title>connpy.tests.test_printer_concurrency API documentation</title>
|
||||
<meta name="description" content="">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/13.0.0/sanitize.min.css" integrity="sha512-y1dtMcuvtTMJc1yPgEqF0ZjQbhnc/bFhyvIyVNb9Zk5mIGtqVaAB1Ttl28su8AvFMOY0EwRbAe+HCLqj6W7/KA==" crossorigin>
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/13.0.0/typography.min.css" integrity="sha512-Y1DYSb995BAfxobCkKepB1BqJJTPrOp3zPL74AWFugHHmmdcvO+C48WLrUOlhGMc0QG7AE3f7gmvvcrmX2fDoA==" crossorigin>
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/default.min.css" crossorigin>
|
||||
<style>:root{--highlight-color:#fe9}.flex{display:flex !important}body{line-height:1.5em}#content{padding:20px}#sidebar{padding:1.5em;overflow:hidden}#sidebar > *:last-child{margin-bottom:2cm}.http-server-breadcrumbs{font-size:130%;margin:0 0 15px 0}#footer{font-size:.75em;padding:5px 30px;border-top:1px solid #ddd;text-align:right}#footer p{margin:0 0 0 1em;display:inline-block}#footer p:last-child{margin-right:30px}h1,h2,h3,h4,h5{font-weight:300}h1{font-size:2.5em;line-height:1.1em}h2{font-size:1.75em;margin:2em 0 .50em 0}h3{font-size:1.4em;margin:1.6em 0 .7em 0}h4{margin:0;font-size:105%}h1:target,h2:target,h3:target,h4:target,h5:target,h6:target{background:var(--highlight-color);padding:.2em 0}a{color:#058;text-decoration:none;transition:color .2s ease-in-out}a:visited{color:#503}a:hover{color:#b62}.title code{font-weight:bold}h2[id^="header-"]{margin-top:2em}.ident{color:#900;font-weight:bold}pre code{font-size:.8em;line-height:1.4em;padding:1em;display:block}code{background:#f3f3f3;font-family:"DejaVu Sans Mono",monospace;padding:1px 4px;overflow-wrap:break-word}h1 code{background:transparent}pre{border-top:1px solid #ccc;border-bottom:1px solid #ccc;margin:1em 0}#http-server-module-list{display:flex;flex-flow:column}#http-server-module-list div{display:flex}#http-server-module-list dt{min-width:10%}#http-server-module-list p{margin-top:0}.toc ul,#index{list-style-type:none;margin:0;padding:0}#index code{background:transparent}#index h3{border-bottom:1px solid #ddd}#index ul{padding:0}#index h4{margin-top:.6em;font-weight:bold}@media (min-width:200ex){#index .two-column{column-count:2}}@media (min-width:300ex){#index .two-column{column-count:3}}dl{margin-bottom:2em}dl dl:last-child{margin-bottom:4em}dd{margin:0 0 1em 3em}#header-classes + dl > dd{margin-bottom:3em}dd dd{margin-left:2em}dd p{margin:10px 0}.name{background:#eee;font-size:.85em;padding:5px 10px;display:inline-block;min-width:40%}.name:hover{background:#e0e0e0}dt:target .name{background:var(--highlight-color)}.name > span:first-child{white-space:nowrap}.name.class > span:nth-child(2){margin-left:.4em}.inherited{color:#999;border-left:5px solid #eee;padding-left:1em}.inheritance em{font-style:normal;font-weight:bold}.desc h2{font-weight:400;font-size:1.25em}.desc h3{font-size:1em}.desc dt code{background:inherit}.source > summary,.git-link-div{color:#666;text-align:right;font-weight:400;font-size:.8em;text-transform:uppercase}.source summary > *{white-space:nowrap;cursor:pointer}.git-link{color:inherit;margin-left:1em}.source pre{max-height:500px;overflow:auto;margin:0}.source pre code{font-size:12px;overflow:visible;min-width:max-content}.hlist{list-style:none}.hlist li{display:inline}.hlist li:after{content:',\2002'}.hlist li:last-child:after{content:none}.hlist .hlist{display:inline;padding-left:1em}img{max-width:100%}td{padding:0 .5em}.admonition{padding:.1em 1em;margin:1em 0}.admonition-title{font-weight:bold}.admonition.note,.admonition.info,.admonition.important{background:#aef}.admonition.todo,.admonition.versionadded,.admonition.tip,.admonition.hint{background:#dfd}.admonition.warning,.admonition.versionchanged,.admonition.deprecated{background:#fd4}.admonition.error,.admonition.danger,.admonition.caution{background:lightpink}</style>
|
||||
<style media="screen and (min-width: 700px)">@media screen and (min-width:700px){#sidebar{width:30%;height:100vh;overflow:auto;position:sticky;top:0}#content{width:70%;max-width:100ch;padding:3em 4em;border-left:1px solid #ddd}pre code{font-size:1em}.name{font-size:1em}main{display:flex;flex-direction:row-reverse;justify-content:flex-end}.toc ul ul,#index ul ul{padding-left:1em}.toc > ul > li{margin-top:.5em}}</style>
|
||||
<style media="print">@media print{#sidebar h1{page-break-before:always}.source{display:none}}@media print{*{background:transparent !important;color:#000 !important;box-shadow:none !important;text-shadow:none !important}a[href]:after{content:" (" attr(href) ")";font-size:90%}a[href][title]:after{content:none}abbr[title]:after{content:" (" attr(title) ")"}.ir a:after,a[href^="javascript:"]:after,a[href^="#"]:after{content:""}pre,blockquote{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}tr,img{page-break-inside:avoid}img{max-width:100% !important}@page{margin:0.5cm}p,h2,h3{orphans:3;widows:3}h1,h2,h3,h4,h5,h6{page-break-after:avoid}}</style>
|
||||
<script defer src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/highlight.min.js" integrity="sha512-D9gUyxqja7hBtkWpPWGt9wfbfaMGVt9gnyCvYa+jojwwPHLCzUm5i8rpk7vD7wNee9bA35eYIjobYPaQuKS1MQ==" crossorigin></script>
|
||||
<script>window.addEventListener('DOMContentLoaded', () => {
|
||||
hljs.configure({languages: ['bash', 'css', 'diff', 'graphql', 'ini', 'javascript', 'json', 'plaintext', 'python', 'python-repl', 'rust', 'shell', 'sql', 'typescript', 'xml', 'yaml']});
|
||||
hljs.highlightAll();
|
||||
/* Collapse source docstrings */
|
||||
setTimeout(() => {
|
||||
[...document.querySelectorAll('.hljs.language-python > .hljs-string')]
|
||||
.filter(el => el.innerHTML.length > 200 && ['"""', "'''"].includes(el.innerHTML.substring(0, 3)))
|
||||
.forEach(el => {
|
||||
let d = document.createElement('details');
|
||||
d.classList.add('hljs-string');
|
||||
d.innerHTML = '<summary>"""</summary>' + el.innerHTML.substring(3);
|
||||
el.replaceWith(d);
|
||||
});
|
||||
}, 100);
|
||||
})</script>
|
||||
</head>
|
||||
<body>
|
||||
<main>
|
||||
<article id="content">
|
||||
<header>
|
||||
<h1 class="title">Module <code>connpy.tests.test_printer_concurrency</code></h1>
|
||||
</header>
|
||||
<section id="section-intro">
|
||||
</section>
|
||||
<section>
|
||||
</section>
|
||||
<section>
|
||||
</section>
|
||||
<section>
|
||||
<h2 class="section-title" id="header-functions">Functions</h2>
|
||||
<dl>
|
||||
<dt id="connpy.tests.test_printer_concurrency.test_printer_manual_stream"><code class="name flex">
|
||||
<span>def <span class="ident">test_printer_manual_stream</span></span>(<span>)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def test_printer_manual_stream():
|
||||
"""Verify that setting a thread stream correctly captures printer output in the current thread."""
|
||||
buf = io.StringIO()
|
||||
|
||||
# We must clear the thread-local console to force it to pick up the new sys.stdout proxy
|
||||
printer.set_thread_console(None)
|
||||
printer.set_thread_stream(buf)
|
||||
|
||||
printer.info("Captured-Message")
|
||||
|
||||
output = buf.getvalue()
|
||||
printer.set_thread_stream(None)
|
||||
printer.set_thread_console(None)
|
||||
|
||||
assert "Captured-Message" in output</code></pre>
|
||||
</details>
|
||||
<div class="desc"><p>Verify that setting a thread stream correctly captures printer output in the current thread.</p></div>
|
||||
</dd>
|
||||
<dt id="connpy.tests.test_printer_concurrency.test_printer_thread_isolation"><code class="name flex">
|
||||
<span>def <span class="ident">test_printer_thread_isolation</span></span>(<span>)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def test_printer_thread_isolation():
|
||||
"""Verify that printer output is isolated per thread when using set_thread_stream."""
|
||||
num_threads = 5
|
||||
iterations = 20
|
||||
results = {}
|
||||
|
||||
def worker(thread_id):
|
||||
# Create a private buffer for this thread
|
||||
buf = io.StringIO()
|
||||
printer.set_thread_stream(buf)
|
||||
|
||||
# Ensure we have a clean console for this thread
|
||||
# In a real gRPC request, this happens automatically as it's a new thread
|
||||
printer.set_thread_console(None)
|
||||
|
||||
# Each thread prints its own ID
|
||||
expected_msg = f"Thread-{thread_id}"
|
||||
for _ in range(iterations):
|
||||
printer.info(expected_msg)
|
||||
time.sleep(0.01)
|
||||
|
||||
results[thread_id] = buf.getvalue()
|
||||
printer.set_thread_stream(None)
|
||||
|
||||
threads = []
|
||||
for i in range(num_threads):
|
||||
t = threading.Thread(target=worker, args=(i,))
|
||||
threads.append(t)
|
||||
t.start()
|
||||
|
||||
for t in threads:
|
||||
t.join()
|
||||
|
||||
# Validation
|
||||
for thread_id, output in results.items():
|
||||
expected_msg = f"Thread-{thread_id}"
|
||||
assert expected_msg in output
|
||||
|
||||
# Ensure no leaks
|
||||
for other_id in range(num_threads):
|
||||
if other_id == thread_id: continue
|
||||
assert f"Thread-{other_id}" not in output</code></pre>
|
||||
</details>
|
||||
<div class="desc"><p>Verify that printer output is isolated per thread when using set_thread_stream.</p></div>
|
||||
</dd>
|
||||
</dl>
|
||||
</section>
|
||||
<section>
|
||||
</section>
|
||||
</article>
|
||||
<nav id="sidebar">
|
||||
<div class="toc">
|
||||
<ul></ul>
|
||||
</div>
|
||||
<ul id="index">
|
||||
<li><h3>Super-module</h3>
|
||||
<ul>
|
||||
<li><code><a title="connpy.tests" href="index.html">connpy.tests</a></code></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><h3><a href="#header-functions">Functions</a></h3>
|
||||
<ul class="">
|
||||
<li><code><a title="connpy.tests.test_printer_concurrency.test_printer_manual_stream" href="#connpy.tests.test_printer_concurrency.test_printer_manual_stream">test_printer_manual_stream</a></code></li>
|
||||
<li><code><a title="connpy.tests.test_printer_concurrency.test_printer_thread_isolation" href="#connpy.tests.test_printer_concurrency.test_printer_thread_isolation">test_printer_thread_isolation</a></code></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
</main>
|
||||
<footer id="footer">
|
||||
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.11.6</a>.</p>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
||||
@@ -3,7 +3,7 @@
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1">
|
||||
<meta name="generator" content="pdoc3 0.11.5">
|
||||
<meta name="generator" content="pdoc3 0.11.6">
|
||||
<title>connpy.tests.test_profile_service API documentation</title>
|
||||
<meta name="description" content="">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/13.0.0/sanitize.min.css" integrity="sha512-y1dtMcuvtTMJc1yPgEqF0ZjQbhnc/bFhyvIyVNb9Zk5mIGtqVaAB1Ttl28su8AvFMOY0EwRbAe+HCLqj6W7/KA==" crossorigin>
|
||||
@@ -192,7 +192,7 @@ Regression: ProfileService currently doesn't resolve inheritance within profiles
|
||||
</nav>
|
||||
</main>
|
||||
<footer id="footer">
|
||||
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.11.5</a>.</p>
|
||||
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.11.6</a>.</p>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1">
|
||||
<meta name="generator" content="pdoc3 0.11.5">
|
||||
<meta name="generator" content="pdoc3 0.11.6">
|
||||
<title>connpy.tests.test_provider API documentation</title>
|
||||
<meta name="description" content="">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/13.0.0/sanitize.min.css" integrity="sha512-y1dtMcuvtTMJc1yPgEqF0ZjQbhnc/bFhyvIyVNb9Zk5mIGtqVaAB1Ttl28su8AvFMOY0EwRbAe+HCLqj6W7/KA==" crossorigin>
|
||||
@@ -139,7 +139,7 @@ el.replaceWith(d);
|
||||
</nav>
|
||||
</main>
|
||||
<footer id="footer">
|
||||
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.11.5</a>.</p>
|
||||
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.11.6</a>.</p>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1">
|
||||
<meta name="generator" content="pdoc3 0.11.5">
|
||||
<meta name="generator" content="pdoc3 0.11.6">
|
||||
<title>connpy.tests.test_sync API documentation</title>
|
||||
<meta name="description" content="Tests for connpy.services.sync_service">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/13.0.0/sanitize.min.css" integrity="sha512-y1dtMcuvtTMJc1yPgEqF0ZjQbhnc/bFhyvIyVNb9Zk5mIGtqVaAB1Ttl28su8AvFMOY0EwRbAe+HCLqj6W7/KA==" crossorigin>
|
||||
@@ -354,7 +354,7 @@ def test_perform_restore(self, mock_remove, mock_dirname, mock_exists, MockZipFi
|
||||
</nav>
|
||||
</main>
|
||||
<footer id="footer">
|
||||
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.11.5</a>.</p>
|
||||
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.11.6</a>.</p>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
Reference in New Issue
Block a user